内部邀請碼:C8E245J (不寫邀請碼,沒有現金送)
國内私募機構九鼎控股打造,九鼎投資是在全國股份轉讓系統挂牌的公衆公司,股票代碼為430719,為“中國PE第一股”,市值超1000億元。
------------------------------------------------------------------------------------------------------------------------------------------------------------------
原文位址:http://www.micmiu.com/enterprise-app/sso/sso-cas-sample/
本文目錄:
一、概述
二、示範環境
三、JDK安裝配置
四、安全證書配置
五、部署CAS-Server相關的Tomcat
六、部署CAS-Client相關的Tomcat
七、 測試驗證SSO
此文的目的就是為了幫助初步接觸SSO和CAS 的人員提供一個入門指南,一步一步示範如何實作基于CAS的單點登入。
本文示範過程在同一個機器上的(也可以在三台實體機器或者三個的虛拟機上),環境如下:
windows7 64位,主機名稱:michael-pc
JDK 1.6.0_18
Tomcat 6.0.29
CAS-server-3.4.11、CAS-client-3.2.1
根據示範需求,用修改hosts 檔案的方法添加域名最簡單友善(這個非常重要),在檔案 C:\Windows\System32\drivers\etc\hosts 檔案中添加三條
demo.micmiu.com =>> 對應部署cas server的tomcat,這個虛拟域名還用于證書生成
app1.micmiu.com =>> 對應部署app1 的tomcat
app2.micmiu.com =>> 對應部署app2 的tomcat
這個詳細過程就不在描述,如果是免安裝版的,確定環境變量配置正确。
本機環境變量:JAVA_HOME=D:\jdk,如果看到以下資訊則表示安裝成功:
4.1. 生成證書:
<code>1</code>
<code>keytool -genkey -</code><code>alias</code> <code>ssodemo -keyalg RSA -keysize 1024 -keypass michaelpwd -validity 365 -keystore g:\sso\ssodemo.keystore -storepass michaelpwd</code>
ps:
截圖中需要輸入的姓名和上面hosts檔案中配置的一緻;
keypass 和 storepass 兩個密碼要一緻,否則下面tomcat 配置https 通路失敗;
4.2.導出證書:
<code>keytool -</code><code>export</code> <code>-</code><code>alias</code> <code>ssodemo -keystore g:\sso\ssodemo.keystore -</code><code>file</code><code>g:\sso\ssodemo.crt -storepass michaelpwd</code>
4.3.用戶端導入證書:
<code>keytool -</code><code>import</code> <code>-keystore %JAVA_HOME%\jre\lib\security\cacerts -</code><code>file</code><code>g:\sso\ssodemo.crt -</code><code>alias</code> <code>ssodemo</code>
ps:該指令中輸入的密碼和上面輸入的不是同一個密碼;如果是多台機器示範,需要在每一台用戶端導入該證書。
5.1. 配置HTTPS
解壓apache-tomcat-6.0.29.tar.gz并重命名後的路徑為 G:\sso\tomcat-cas,在檔案 conf/server.xml檔案找到:
<code><!--</code>
<code>2</code>
<code> </code><code><Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"</code>
<code>3</code>
<code> </code><code>maxThreads="150" scheme="https" secure="true"</code>
<code>4</code>
<code> </code><code>clientAuth="false" sslProtocol="TLS" /></code>
<code>5</code>
<code> </code><code>--></code>
修改成如下:
<code><Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"</code>
<code> </code><code>keystoreFile="g:/sso/ssodemo.keystore" keystorePass="michaelpwd"</code>
<code> </code><code>clientAuth="false" sslProtocol="TLS" URIEncoding="UTF-8"</code>
參數說明:
keystoreFile 就是4.1中建立證書的路徑
keystorePass 就是4.1中建立證書的密碼
5.2. 驗證HTTPS配置
其他按照預設配置不作修改,輕按兩下%TOMCAT_HOME%\bin\startup.bat 啟動tomcat-cas 驗證https通路配置:
如果看到上述界面表示https 通路配置成功。
5.3 部署CAS-Server
CAS-Server 下載下傳位址:http://www.jasig.org/cas/download
本文以cas-server-3.4.11-release.zip 為例,解壓提取cas-server-3.4.11/modules/cas-server-webapp-3.4.11.war檔案,把改檔案copy到 G:\sso\tomcat-cas\webapps\ 目下,并重命名為:cas.war.
啟動tomcat-cas,在浏覽器位址欄輸入:https://demo.micmiu.com:8443/cas/login ,回車
CAS-server的預設驗證規則:隻要使用者名和密碼相同就認證通過(僅僅用于測試,生成環境需要根據實際情況修改),輸入admin/admin 點選登入,就可以看到登入成功的頁面:
看到上述頁面表示CAS-Server已經部署成功。
6.1Cas-Client 下載下傳
以cas-client-3.2.1-release.zip 為例,解壓提取cas-client-3.2.1/modules/cas-client-core-3.2.1.jar
借以tomcat預設自帶的 webapps\examples 作為示範的簡單web項目
6.2 安裝配置 tomcat-app1
解壓apache-tomcat-6.0.29.tar.gz并重命名後的路徑為 G:\sso\tomcat-app1,修改tomcat的啟動端口,在檔案conf/server.xml檔案找到如下内容:
<code><</code><code>Connector</code> <code>port</code><code>=</code><code>"8080"</code> <code>protocol</code><code>=</code><code>"HTTP/1.1"</code>
<code> </code><code>connectionTimeout</code><code>=</code><code>"20000"</code>
<code> </code><code>redirectPort</code><code>=</code><code>"8443"</code> <code>/></code>
<code><</code><code>Connector</code> <code>port</code><code>=</code><code>"8009"</code> <code>protocol</code><code>=</code><code>"AJP/1.3"</code> <code>redirectPort</code><code>=</code><code>"8443"</code> <code>/></code>
<code><</code><code>Connector</code> <code>port</code><code>=</code><code>"18080"</code> <code>protocol</code><code>=</code><code>"HTTP/1.1"</code>
<code> </code><code>redirectPort</code><code>=</code><code>"18443"</code> <code>/></code>
<code><</code><code>Connector</code> <code>port</code><code>=</code><code>"18009"</code> <code>protocol</code><code>=</code><code>"AJP/1.3"</code> <code>redirectPort</code><code>=</code><code>"18443"</code> <code>/></code>
啟動tomcat-app1,浏覽器輸入 http://app1.micmiu.com:18080/examples/servlets/ 回車:
看到上述界面表示tomcat-app1的基本安裝配置已經成功。
接下來複制 client的lib包cas-client-core-3.2.1.jar到 tomcat-app1\webapps\examples\WEB-INF\lib\目錄下, 在tomcat-app1\webapps\examples\WEB-INF\web.xml 檔案中增加如下内容:
<code><!-- ======================== 單點登入開始 ======================== --></code>
<code> </code><code><!-- 用于單點退出,該過濾器用于實作單點登出功能,可選配置--></code>
<code> </code><code><</code><code>listener</code><code>></code>
<code> </code><code><</code><code>listener-class</code><code>>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</</code><code>listener-class</code><code>></code>
<code> </code><code></</code><code>listener</code><code>></code>
<code>6</code>
<code>7</code>
<code> </code><code><!-- 該過濾器用于實作單點登出功能,可選配置。 --></code>
<code>8</code>
<code> </code><code><</code><code>filter</code><code>></code>
<code>9</code>
<code> </code><code><</code><code>filter-name</code><code>>CAS Single Sign Out Filter</</code><code>filter-name</code><code>></code>
<code>10</code>
<code> </code><code><</code><code>filter-class</code><code>>org.jasig.cas.client.session.SingleSignOutFilter</</code><code>filter-class</code><code>></code>
<code>11</code>
<code> </code><code></</code><code>filter</code><code>></code>
<code>12</code>
<code> </code><code><</code><code>filter-mapping</code><code>></code>
<code>13</code>
<code>14</code>
<code> </code><code><</code><code>url-pattern</code><code>>/*</</code><code>url-pattern</code><code>></code>
<code>15</code>
<code> </code><code></</code><code>filter-mapping</code><code>></code>
<code>16</code>
<code>17</code>
<code>18</code>
<code> </code><code><</code><code>filter-name</code><code>>CAS Filter</</code><code>filter-name</code><code>></code>
<code>19</code>
<code> </code><code><</code><code>filter-class</code><code>>org.jasig.cas.client.authentication.AuthenticationFilter</</code><code>filter-class</code><code>></code>
<code>20</code>
<code> </code><code><</code><code>init-param</code><code>></code>
<code>21</code>
<code> </code><code><</code><code>param-name</code><code>>casServerLoginUrl</</code><code>param-name</code><code>></code>
<code>22</code>
<code>23</code>
<code> </code><code></</code><code>init-param</code><code>></code>
<code>24</code>
<code>25</code>
<code> </code><code><</code><code>param-name</code><code>>serverName</</code><code>param-name</code><code>></code>
<code>26</code>
<code>27</code>
<code>28</code>
<code>29</code>
<code>30</code>
<code>31</code>
<code>32</code>
<code>33</code>
<code> </code><code><!-- 該過濾器負責對Ticket的校驗工作,必須啟用它 --></code>
<code>34</code>
<code>35</code>
<code> </code><code><</code><code>filter-name</code><code>>CAS Validation Filter</</code><code>filter-name</code><code>></code>
<code>36</code>
<code> </code><code><</code><code>filter-class</code><code>></code>
<code>37</code>
<code> </code><code>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</</code><code>filter-class</code><code>></code>
<code>38</code>
<code>39</code>
<code> </code><code><</code><code>param-name</code><code>>casServerUrlPrefix</</code><code>param-name</code><code>></code>
<code>40</code>
<code>41</code>
<code>42</code>
<code>43</code>
<code>44</code>
<code>45</code>
<code>46</code>
<code>47</code>
<code>48</code>
<code>49</code>
<code>50</code>
<code>51</code>
<code>52</code>
<code> </code><code><!--</code>
<code>53</code>
<code> </code><code>該過濾器負責實作HttpServletRequest請求的包裹,</code>
<code>54</code>
<code> </code><code>比如允許開發者通過HttpServletRequest的getRemoteUser()方法獲得SSO登入使用者的登入名,可選配置。</code>
<code>55</code>
<code> </code><code>--></code>
<code>56</code>
<code>57</code>
<code> </code><code><</code><code>filter-name</code><code>>CAS HttpServletRequest Wrapper Filter</</code><code>filter-name</code><code>></code>
<code>58</code>
<code>59</code>
<code> </code><code>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</</code><code>filter-class</code><code>></code>
<code>60</code>
<code>61</code>
<code>62</code>
<code>63</code>
<code>64</code>
<code>65</code>
<code>66</code>
<code> </code><code><!--</code>
<code>67</code>
<code> </code><code>該過濾器使得開發者可以通過org.jasig.cas.client.util.AssertionHolder來擷取使用者的登入名。</code>
<code>68</code>
<code> </code><code>比如AssertionHolder.getAssertion().getPrincipal().getName()。</code>
<code>69</code>
<code>70</code>
<code>71</code>
<code> </code><code><</code><code>filter-name</code><code>>CAS Assertion Thread Local Filter</</code><code>filter-name</code><code>></code>
<code>72</code>
<code> </code><code><</code><code>filter-class</code><code>>org.jasig.cas.client.util.AssertionThreadLocalFilter</</code><code>filter-class</code><code>></code>
<code>73</code>
<code>74</code>
<code>75</code>
<code>76</code>
<code>77</code>
<code>78</code>
<code>79</code>
<code> </code><code><!-- ======================== 單點登入結束 ======================== --></code>
有關cas-client的web.xml修改的詳細說明見官網介紹:
<a href="https://wiki.jasig.org/display/CASC/Configuring+the+Jasig+CAS+Client+for+Java+in+the+web.xml" target="_blank">https://wiki.jasig.org/display/CASC/Configuring+the+Jasig+CAS+Client+for+Java+in+the+web.xml</a>
6.3 安裝配置 tomcat-app2
解壓apache-tomcat-6.0.29.tar.gz并重命名後的路徑為 G:\sso\tomcat-app2,修改tomcat的啟動端口,在檔案 conf/server.xml檔案找到如下内容:
<code><</code><code>Connector</code> <code>port</code><code>=</code><code>"28080"</code> <code>protocol</code><code>=</code><code>"HTTP/1.1"</code>
<code> </code><code>redirectPort</code><code>=</code><code>"28443"</code> <code>/></code>
<code><</code><code>Connector</code> <code>port</code><code>=</code><code>"28009"</code> <code>protocol</code><code>=</code><code>"AJP/1.3"</code> <code>redirectPort</code><code>=</code><code>"28443"</code> <code>/></code>
啟動tomcat-app2,浏覽器輸入 http://app2.micmiu.com:28080/examples/servlets/ 回車,按照上述6.2中的方法驗證是否成功。
同6.2中的複制 client的lib包cas-client-core-3.2.1.jar到 tomcat-app2\webapps\examples\WEB-INF\lib\目錄下, 在tomcat-app2\webapps\examples\WEB-INF\web.xml 檔案中增加如下内容:
<code> </code><code>該過濾器使得開發者可以通過org.jasig.cas.client.util.AssertionHolder來擷取使用者的登入名。</code>
<code> </code><code>比如AssertionHolder.getAssertion().getPrincipal().getName()。</code>
啟動之前配置好的三個tomcat分别為:tomcat-cas、tomcat-app1、tomcat-app2.
7.1 基本的測試
預期流程: 打開app1 url —-> 跳轉cas server 驗證 —-> 顯示app1的應用 —-> 打開app2 url —-> 顯示app2應用 —-> 登出cas server —-> 打開app1/app2 url —-> 重新跳轉到cas server 驗證.
打開浏覽器位址欄中輸入:http://app1.micmiu.com:18080/examples/servlets/servlet/HelloWorldExample,回車:
跳轉到驗證頁面:
驗證通過後顯示如下:
此時通路app2就不再需要驗證:
位址欄中輸入:https://demo.micmiu.com:8443/cas/logout,回車顯示:
上述表示 認證登出成功,此時如果再通路 : http://app1.micmiu.com:18080/examples/servlets/servlet/HelloWorldExample 或 http://app2.micmiu.com:28080/examples/servlets/servlet/HelloWorldExample 需要重新進行認證。
7.2 擷取登入使用者的資訊
修改類:webapps\examples\WEB-INF\classes\HelloWorldExample.java 後重新編譯并替換 webapps\examples\WEB-INF\classes\HelloWorldExample.class檔案。
HelloWorldExample.java 修改後的代碼如下:
<code>import</code> <code>java.io.*;</code>
<code>import</code> <code>java.util.*;</code>
<code>import</code> <code>java.util.Map.Entry;</code>
<code>import</code> <code>javax.servlet.*;</code>
<code>import</code> <code>javax.servlet.http.*;</code>
<code>import</code> <code>org.jasig.cas.client.authentication.AttributePrincipal;</code>
<code>import</code> <code>org.jasig.cas.client.util.AbstractCasFilter;</code>
<code>import</code> <code>org.jasig.cas.client.validation.Assertion;</code>
<code>/**</code>
<code> </code><code>* CAS simple Servlet</code>
<code> </code><code>*</code>
<code> </code><code>*/</code>
<code>public</code> <code>class</code> <code>HelloWorldExample </code><code>extends</code> <code>HttpServlet {</code>
<code> </code><code>private</code> <code>static</code> <code>final</code> <code>long</code> <code>serialVersionUID = -6593274907821061823L;</code>
<code> </code><code>@SuppressWarnings</code><code>(</code><code>"unchecked"</code><code>)</code>
<code> </code><code>public</code> <code>void</code> <code>doGet(HttpServletRequest request, HttpServletResponse response)</code>
<code> </code><code>throws</code> <code>IOException, ServletException {</code>
<code> </code><code>ResourceBundle rb = ResourceBundle.getBundle(</code><code>"LocalStrings"</code><code>,</code>
<code> </code><code>request.getLocale());</code>
<code> </code><code>response.setContentType(</code><code>"text/html"</code><code>);</code>
<code> </code><code>PrintWriter out = response.getWriter();</code>
<code> </code><code>out.println(</code><code>"<html>"</code><code>);</code>
<code> </code><code>out.println(</code><code>"<head>"</code><code>);</code>
<code> </code><code>String title = rb.getString(</code><code>"helloworld.title"</code><code>);</code>
<code> </code><code>out.println(</code><code>"<title>"</code> <code>+ title + </code><code>"</title>"</code><code>);</code>
<code> </code><code>out.println(</code><code>"</head>"</code><code>);</code>
<code> </code><code>out.println(</code><code>"<body bgcolor=\"white\">"</code><code>);</code>
<code> </code><code>out.println(</code><code>"<a href=\"../helloworld.html\">"</code><code>);</code>
<code> </code><code>out.println(</code><code>"<img src=\"../images/code.gif\" height=24 "</code>
<code> </code><code>+ </code><code>"width=24 align=right border=0 alt=\"view code\"></a>"</code><code>);</code>
<code> </code><code>out.println(</code><code>"<a href=\"../index.html\">"</code><code>);</code>
<code> </code><code>out.println(</code><code>"<img src=\"../images/return.gif\" height=24 "</code>
<code> </code><code>+ </code><code>"width=24 align=right border=0 alt=\"return\"></a>"</code><code>);</code>
<code> </code><code>out.println(</code><code>"<h1>"</code> <code>+ title + </code><code>"</h1>"</code><code>);</code>
<code> </code><code>Assertion assertion = (Assertion) request.getSession().getAttribute(</code>
<code> </code><code>AbstractCasFilter.CONST_CAS_ASSERTION);</code>
<code> </code><code>if</code> <code>(</code><code>null</code> <code>!= assertion) {</code>
<code> </code><code>out.println(</code><code>" Log | ValidFromDate =:"</code>
<code> </code><code>+ assertion.getValidFromDate() + </code><code>"<br>"</code><code>);</code>
<code> </code><code>out.println(</code><code>" Log | ValidUntilDate =:"</code>
<code> </code><code>+ assertion.getValidUntilDate() + </code><code>"<br>"</code><code>);</code>
<code> </code><code>Map<Object, Object> attMap = assertion.getAttributes();</code>
<code> </code><code>out.println(</code><code>" Log | getAttributes Map size = "</code> <code>+ attMap.size()</code>
<code> </code><code>+ </code><code>"<br>"</code><code>);</code>
<code> </code><code>for</code> <code>(Entry<Object, Object> entry : attMap.entrySet()) {</code>
<code> </code><code>out.println(</code><code>" | "</code> <code>+ entry.getKey() + </code><code>"=:"</code>
<code> </code><code>+ entry.getValue() + </code><code>"<br>"</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>AttributePrincipal principal = assertion.getPrincipal();</code>
<code> </code><code>// AttributePrincipal principal = (AttributePrincipal) request</code>
<code> </code><code>// .getUserPrincipal();</code>
<code> </code><code>String username = </code><code>null</code><code>;</code>
<code> </code><code>out.print(</code><code>" Log | UserName:"</code><code>);</code>
<code> </code><code>if</code> <code>(</code><code>null</code> <code>!= principal) {</code>
<code> </code><code>username = principal.getName();</code>
<code> </code><code>out.println(</code><code>"<span style='color:red;'>"</code> <code>+ username</code>
<code> </code><code>+ </code><code>"</span><br>"</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>out.println(</code><code>"</body>"</code><code>);</code>
<code> </code><code>out.println(</code><code>"</html>"</code><code>);</code>
<code> </code><code>}</code>
<code>80</code>
<code>}</code>
再進行上述測試顯示結果如下:
http://app1.micmiu.com:18080/examples/servlets/servlet/HelloWorldExample :
http://app2.micmiu.com:28080/examples/servlets/servlet/HelloWorldExample
從上述頁面可以看到通過認證的使用者名。
到此已經全部完成了CAS單點登入執行個體示範。