利用Spring Security 3.2的remember-me搭建SSO

回顧

在上一篇文章,我實現了Spring Security3.2搭建的第一個網站應用firstWeb. 進階-使用Spring Security3.2搭建LDAP認證受權和Remember-me。 而在更早的時候,我有使用Apache+tomcat搭建cluster,Apache httpd與tomcat集羣。接下來,我將利用以前的做品,繼續向更遠的地方前進。java

提綱

  1. 爲firstWeb應用建立cluster。node

  2. 建立並部署一個新的應用secondWeb。web

  3. 使用Remember-me機制實現firstWeb與secondWeb的SSO。算法

架構示意圖

此圖是爲最終形態而畫的,今天的實驗並不涉及CAS,請忽略CAS。apache

由上圖可見,Apache做爲一個逆向代理,提供兩個虛擬主機,兩個虛擬主機均在.test.com域中。其中一個虛擬主機爲cluster, Apache須要爲其提供負載平衡服務。另外,Apache開啓了SSL。tomcat

全部Apache的配置能夠在此下載:http://pan.baidu.com/s/1i37fUFbcookie

因爲以前的文章已經有配置好OpenLDAP,OpenSSL,因此本文將在此基礎上搭建網站。想從頭開始的請往前翻。session

FirstWeb集羣

FirstWeb是咱們在上一篇文章所產生的應用,若是須要將FirstWeb部署爲cluster的話,須要四個步驟:架構

  1. 在FristWeb的web.xml中添加配置,使其支持session同步。dom

    <distributable/>
  2. 配置tomcat1和tomcat2的server.xml,使它們成爲cluster。詳細見Apache httpd與tomcat集羣 。

  3. 配置Apache逆向代理,作負載平衡。

    <VirtualHost *:443>
       ServerAdmin joey
       ServerName first.test.com
       ErrorLog "logs/firstWebDetail"
       CustomLog "logs/accessFisrtWeb" common
       
       SSLEngine on
       SSLCipherSuite RC4-SHA:AES128-SHA:HIGH:MEDIUM:!aNULL:!MD5
       SSLCertificateFile "C:/Program Files (x86)/Apache Software Foundation/Apache2.2/conf/server.crt"
       SSLCertificateKeyFile "C:/Program Files (x86)/Apache Software Foundation/Apache2.2/conf/server.key"
       
       LogLevel debug
       ProxyRequests Off
       ProxyPreserveHost On
       ProxyPass /firstWeb balancer://mycluster/firstWeb
       ProxyPassReverse /firstWeb balancer://mycluster/firstWeb
       <Proxy balancer://mycluster>
          BalancerMember ajp://127.0.0.1:8009 loadfactor=1 route=node1
          BalancerMember ajp://127.0.0.1:8010 loadfactor=1 route=node2
    	  ProxySet stickysession=JSESSIONID
    	  ProxySet lbmethod=byrequests
       </Proxy>
    </VirtualHost>
  4. 配置DNS,創建ip和域名映射。(無條件的同窗能夠修改本地的hosts文件)。

FirstWeb的源碼在此:http://pan.baidu.com/s/1nthpuDN 

SecondWeb開發部署

快速開發secondWeb,並將其部署到tomcat3上。

SecondWeb很是簡單,它只包含兩個頁面,一個登錄頁面和一個Index頁面。Index頁面是受保護的,未認證的用戶訪問獎盃轉到登錄頁面。secondWeb的源碼能夠從這裏下載http://pan.baidu.com/s/1o64TQ9k。 SecondWeb一樣使用Spring Security 3.2,並使用和FirstWeb相同的LDAP。

配置逆向代理:

<VirtualHost *:443>
   ServerAdmin joey
   ServerName second.test.com
   ErrorLog "logs/secondWebDetail"
   CustomLog "logs/accessSecondWeb" common
   
   SSLEngine on
   SSLCipherSuite RC4-SHA:AES128-SHA:HIGH:MEDIUM:!aNULL:!MD5
   SSLCertificateFile "C:/Program Files (x86)/Apache Software Foundation/Apache2.2/conf/server.crt"
   SSLCertificateKeyFile "C:/Program Files (x86)/Apache Software Foundation/Apache2.2/conf/server.key"
   
   LogLevel debug
   ProxyRequests Off
   ProxyPreserveHost On
   ProxyPass /secondWeb ajp://127.0.0.1:8011/secondWeb
   ProxyPassReverse /secondWeb ajp://127.0.0.1:8011/secondWeb
</VirtualHost>

如今啓動tomcat1,2,3, 而後啓動apache,咱們能夠訪問如下兩個網站了:

https://first.test.com/firstWeb

https://second.test.com/secondWeb

使用Remember-me構建SSO

Remember-me的原理是在cookie中存有一個token,這個token包含了用戶名,加密後的密碼,過時時間,以及一個混入的key。remember me cookie value的生成默認算法爲:

value = Base64(username:MD5(password):expireDateValue:key)

MD5是默認的,能夠選擇不一樣的算法爲密碼加密。 key能夠聲明,若是沒有聲明key,Spring Security將使用一個Random GUUID. GUUID在不一樣的server,不一樣的context下都是不一樣的。每次重啓server也會不一樣。咱們固然能夠聲明一個固定的key值。

當用戶攜帶這個cookie訪問網站的時候,網站會使用此token與LDAP中的用戶信息比對,比對成功之後,則自動登陸此用戶。

因而我想,若是個人兩個網站共用remember me的cookie的話,一旦一個網站登陸了,另外一個網站就能夠實現自動登陸了。

須要克服的一個難點,Spring Security中的RememberMeAuthenticationFilter所使用的cookie是有限制的,例如

secondWeb的remember-me cookie只對http://second.test.com/secondWeb有用,我須要改寫cookie的做用域和cookie的過時時間,以達到對整個.test.com域的做用。

我須要在上面的firstWeb和secondWeb基礎上,修改代碼。步驟以下:

  1. 配置相同的LDAP認證。(已經知足,跳過)

  2. 修改代碼,爲每一個remember me指定相同的混入key -".test.com"。 以下:

            @Override
    	public void configure(HttpSecurity http) throws Exception {
    		http
    		... ...
    		.and()
    		.rememberMe().tokenValiditySeconds(15*24*60*60)
    		.key(".test.com"); // 使用一個固定的key.
    	}
  3. 建立一個新的SevletFilter,進行RememberMe cookie的改寫。

    //RememberMeCookieFilter.java
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest)request;
            Cookie newCookie = null;
            Cookie[] cookies = req.getCookies();
            if ((cookies != null) && (cookies.length > 0)) {
                for (Cookie cookie : cookies) {
                    if ("remember-me".equals(cookie.getName())) {
                        newCookie = new Cookie(cookie.getName(), cookie.getValue());
                        newCookie.setHttpOnly(cookie.isHttpOnly());
                        newCookie.setSecure(cookie.getSecure());
                        // Control following
                        // 設置cookie過時時間
                        newCookie.setMaxAge(cookie.getMaxAge());
                        // 設置cookie的有效路徑
                        newCookie.setPath("/");
                        // 設置cookie的有效域
                        newCookie.setDomain(".test.com");
                    }
                }
            } 
            chain.doFilter(request, response);
            if (newCookie != null) {
                HttpServletResponse rep = (HttpServletResponse)response;
                rep.addCookie(newCookie);
            }
        }
  4. 將RememberMeCookieFilter註冊到SpringSecurityFilterChain中去。在每一個httpSecurity中註冊,以下例子:

        public void configure(HttpSecurity http) throws Exception {
            // 將RememberMeCookieFilter註冊到SpringSecurityFilterChain中
            // 並放置在HeaderWriterFilter以前。
            http
            .addFilterBefore(new RememberMeCookieFilter(), HeaderWriterFilter.class)
            ... ...
        }
  5. (沒有包含在實驗中)爲logout添加一個handler,將cookie刪除。

  6. 而後從新打包部署FirstWeb和SecondWeb。

經過上面的filter,remember me cookie的做用域變成了

domain:   .test.com 
path:     /

兩個網站 https://first.test.com/firstWeb 與 https://second.test.com/secondWeb 共用remember me cookie.

如今兩個網站能夠經過使用Remember Me的cookie進行SSO了。獲得啓發的人,能夠對上面的代碼進行改進,使得更健壯。

這部分的代碼能夠從如下地址下載:http://pan.baidu.com/s/1jDDpW

下一步使用CAS搭建Cluster

Spring Security 3和CAS 3.5.2集成的完整實例 

相關文章
相關標籤/搜索