CAS (5) —— Nginx代理模式下瀏覽器訪問CAS服務器配置詳解


CAS (5) —— Nginx代理模式下瀏覽器訪問CAS服務器配置詳解


tomcat版本: tomcat-8.0.29

jdk版本: jdk1.8.0_65

nginx版本: nginx-1.9.8

cas版本: cas4.1.2
cas-client-3.4.1

參考來源:

jasig.github.io:CAS protocol

https://github.com/Jasig/java-cas-client

通過Proxy訪問其它Cas應用

CAS負載均衡配置——SSL篇

CAS負載均衡配置

CAS客戶端集群

  • 以下的示例采用我博客的另外兩篇文章中搭建好的測試環境舉例

CAS (1) —— Mac下配置CAS到Tomcat(服務端)

CAS (2) —— Mac下配置CAS到Tomcat(客戶端)

CAS (3) —— Mac下配置CAS客戶端經代理訪問Tomcat CAS

Mac為nginx安裝nginx-sticky-module

【高可用HA】Nginx (1) —— Mac下配置Nginx Http負載均衡(Load Balancer)之101實例

Nginx (2) —— Mac下配置Apache Httpd的Https/SSL (待出)

目標架構

此代理非彼代理

在CAS官方網站上給出了一個“Proxy Web Flow Diagram”:

順序圖:(來源於http://jasig.github.io/cas/4.0.x/protocol/CAS-Protocol.html)

這個方案主要適用一種場景:

有兩個應用App1和App2,它們都是受Cas Server保護的,即請求它們時都需要通過Cas Server的認證。現需要在App1中通過Http請求訪問App2,顯然該請求將會被App2配置的Cas的AuthenticationFilter攔截並轉向Cas Server,Cas Server將引導用戶進行登錄認證,這樣我們也就不能真正的訪問到App2了。針對這種應用場景,Cas也提供了對應的支持。通過Proxy訪問其它Cas應用

無論是用中文關鍵字在“度娘”,還是用英文關鍵字再“谷哥”上搜索,多數文章都是描述上面這樣一個場景。

而我這里介紹的“代理”,並非是上述場景——依靠代理去驗證ticket,“代理”在此的角色是:

  • 只做分發反向代理(未來的負載均衡器)
* 注意:所以說“此代理非彼代理”

准備

要搭建上面這個環境會相對復雜,我們需要參照之前的文章准備以下必備的組件或環境:

  1. 2個Tomcat服務器作為客戶端應用程序服務器(即cas的客戶端)

     app1.hoau.com:8081/8413(http/https)
     app2.hoau.com:8082/8423(http/https)
    

    參照Tomcat ClusterTomcat SSLCAS Client

  2. 1個配置好SSL的Nginx服務器作為中間層代理轉發服務器(后可擴展為LoadBalancer)

     proxy.sso.hoau.com:85/443(http/https)
    

    參照Nginx Load BalancerNginx Sticky Session

  3. 另一個1個帶有SSL的Tomcat服務器作為CAS服務器

     sso.hoau.com:8083/8433(http/https)
    

    參照Tomcat SSLCAS Server

關鍵配置

  • 代理服務器(Nginx x 1)

    nginx.conf
    • http

      server:

        server {
            listen       85;
        	server_name  proxy.sso.hoau.com;
            location / {  
            #index index.html index.htm;
        	#設置主機頭和客戶端真實地址,以便服務器獲取客戶端真實IP
      
            proxy_set_header   Host   $host;
            proxy_set_header   Referer $http_referer;
            proxy_set_header   Cookie $http_cookie;
        	proxy_set_header   X-Real-IP  $remote_addr;
            proxy_set_header   X-Forwarded-For 				$proxy_add_x_forwarded_for;
      
            proxy_redirect off;  
            #禁用緩存
            #proxy_buffering off;
      
            proxy_connect_timeout 3;
            proxy_send_timeout 30;
            proxy_read_timeout 30; 
            proxy_pass http://cas_server_http; 
        }  
      

      upstream:

        upstream cas_server_http {  
        	#根據ip計算將請求分配各那個后端tomcat,許多人誤認為可以解決session問題,其實並不能。  
            #同一機器在多網情況下,路由切換,ip可能不同  
        	#ip_hash;   
            #sticky;
      
        	#Richard: http
            server localhost:8083 weight=1 srun_id=c; 
            #server localhost:8084 weight=1 srun_id=c; 
        	jvm_route $cookie_JSESSIONID|sessionid reverse;
        }
      

      *注意:

      (1)以上的“jvm_route $cookie_JSESSIONID|sessionid reverse;”是關鍵配置,因為CAS是依賴於Session和Cookie進行身份驗證的。

      (2)srun_id=c,其中“c”需要與CAS服務器Tomcat server.xml文件里的jvmRoute配置“

        <Engine name="Catalina" defaultHost="localhost" jvmRoute="c">”	  
      
    • https

      server:

        server { 
        	listen 443;
            server_name  proxy.sso.hoau.com;
        	ssl on; 
            ssl_certificate /Users/Richard/Documents/Dev/servers/cluster/nginx/keys/server.crt; 
        	ssl_certificate_key  /Users/Richard/Documents/Dev/servers/cluster/nginx/keys/server.key; 
      
            ssl_session_timeout 5m;
            ssl_protocols SSLv3 TLSv1;
        	ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
            ssl_prefer_server_ciphers on;
      
        	location / {
                proxy_redirect off;  
      
        	    proxy_set_header Host $host;  
                proxy_set_header   Referer $http_referer;
        	    proxy_set_header   Cookie $http_cookie;
                proxy_set_header X-Real-IP $remote_addr;  
        	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-FORWARDED-HOST $server_addr;  
        	    proxy_set_header X-FORWARDED-PORT $server_port;
      
                proxy_connect_timeout 3;
        	    proxy_send_timeout 30;
                proxy_read_timeout 30;
      
                proxy_pass https://cas_server_ssl;
      		}	
        }
      

      *注意:以上的ssl為關鍵配置“ssl_certificate”和“ssl_certificate_key”需要指向正確的證書和密鑰。

      upstream:

        upstream cas_server_ssl {  
            #Richard: https todo
        	server sso.hoau.com:8433 weight=1 srun_id=c;  
            #server sso.hoau.com:8443 weight=1 srun_id=c; 
        	jvm_route $cookie_JSESSIONID|sessionid reverse;
        }  
      

*注意:以上http和https可以只配一項,或兩者兼存皆可,端口不要沖突。

  • CAS客戶端應用服務器(Tomcat x 2)

    以下客戶端的藍本可以在github上收到(關鍵字:“cas-sample-java-webapp”),我這里只貼出自己的關鍵點和修改后的結果。

    CAS客戶端的應用服務器有兩台,如果不使用Spring Security的集成,比較關鍵配置就只有pom.xml(編譯)和web.xml(部署):

    • 兩個環境編譯類似,pom.xml(貼全了,有無冗余請自行解決):

      *注意:以下Spring Security相關依賴為非必須

        <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        	<modelVersion>4.0.0</modelVersion>
        	<groupId>iamlabs.unicon.net</groupId>
        	<artifactId>cas-sample-java-webapp</artifactId>
        	<version>0.0.1-SNAPSHOT</version>
        	<packaging>war</packaging>
        	<name>CAS Example Java Web App</name>
        	<description>A sample web application that exercises the CAS protocol features via the Java CAS Client.</description>
        	<build>
        		<finalName>cas-sample-java-webapp</finalName>
        		<plugins>
        			<plugin>
        				<groupId>org.apache.maven.plugins</groupId>
        				<artifactId>maven-compiler-plugin</artifactId>
        				<version>2.5.1</version>
        				<configuration>
        					<source>1.7</source>
        					<target>1.7</target>
        				</configuration>
        			</plugin>
        		</plugins>
        	</build>
      
        	<properties>       
                <spring.version>3.2.4.RELEASE</spring.version> 
                <casclient.version>3.4.1</casclient.version>        
            </properties>  
      
        	<dependencies>
      
        	<dependency>
        		<groupId>commons-logging</groupId>
        		<artifactId>commons-logging</artifactId>
        		<version>1.1.1</version>
        	</dependency>
      
        	<!-- Logging -->    
        	<dependency>  
        	    <groupId>org.slf4j</groupId>  
                <artifactId>slf4j-api</artifactId>  
        	    <version>1.7.13</version>  
            </dependency>  
        	<dependency>  
        		<groupId>org.slf4j</groupId>  
                <artifactId>slf4j-simple</artifactId>  
        	    <version>1.7.13</version>  
            </dependency>    
        	<dependency>    
        	    <groupId>org.slf4j</groupId>    
        	    <artifactId>slf4j-log4j12</artifactId>    
        	    <version>1.7.13</version>  	
        	</dependency> 
      
        	<dependency>
        		<groupId>org.opensaml</groupId>
        		<artifactId>opensaml1</artifactId>
        		<version>1.1</version>
        	</dependency>
      
        	<dependency>
        		<groupId>javax.servlet</groupId>
        		<artifactId>javax.servlet-api</artifactId>
        		<version>3.1.0</version>
        		<scope>provided</scope>
        	</dependency>
      
        	<dependency>
        		<groupId>org.jasig.cas.client</groupId>
        		<artifactId>cas-client-core</artifactId>
          		<version>${casclient.version}</version>
        		<exclusions>
        			<exclusion>
        				<groupId>javax.servlet</groupId>
        				<artifactId>servlet-api</artifactId>
        			</exclusion>
        		</exclusions>
        	</dependency>
      
        	<dependency>
        		<groupId>org.jasig.cas.client</groupId>
        		<artifactId>cas-client-integration-tomcat-common</artifactId>
        		<version>${casclient.version}</version>
        	</dependency>
      
        	<dependency>
        		<groupId>commons-codec</groupId>
        		<artifactId>commons-codec</artifactId>
        		<version>1.6</version>
        	</dependency>
      
        	<dependency>
        		<groupId>org.apache.santuario</groupId>
        		<artifactId>xmlsec</artifactId>
        		<version>1.4.3</version>
        	</dependency>
      
        	<dependency>  
                <groupId>org.springframework</groupId>  
        	    <artifactId>spring-core</artifactId>  
                <version>${spring.version}</version>  
            </dependency>  
        	<dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-beans</artifactId>  
                <version>${spring.version}</version>  
        	</dependency> 
             <dependency>  
        	    <groupId>org.springframework</groupId>  
                <artifactId>spring-context</artifactId>  
        	    <version>${spring.version}</version>  
            </dependency> 
        	 <dependency>  
                <groupId>org.springframework</groupId>  
        	    <artifactId>spring-web</artifactId>  
                <version>${spring.version}</version>  
        	</dependency>  
      
            <dependency>  
        	   <groupId>org.springframework.security</groupId>
        		<artifactId>spring-security-core</artifactId>
        	    <version>${spring.version}</version>  
            </dependency>
        	<dependency>  
              <groupId>org.springframework.security</groupId>
        		<artifactId>spring-security-web</artifactId>
                <version>${spring.version}</version>  
        	</dependency>  
            <dependency>  
        	    <groupId>org.springframework.security</groupId>
        		<artifactId>spring-security-config</artifactId>  
        	    <version>${spring.version}</version>  
            </dependency>  
        	</dependencies>
        </project>
      
    • https://app1.hoau.com:8413

      web.xml:

        <?xml version="1.0" encoding="UTF-8"?>
        <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
      
      
        	 <context-param>
                <param-name>log4jConfigLocation</param-name>
                <param-value>/WEB-INF/log4j.properties</param-value>
            </context-param>
      
      
            <listener>
        		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
        	</listener>
            
            <!--
            <listener>
            	<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
        	</listener>
            <filter>
        		<filter-name>CAS Single Sign Out Filter</filter-name>
           		<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
        		<init-param>
              		<param-name>casServerUrlPrefix</param-name>
        			<param-value>https://proxy.sso.hoau.com:443</param-value>
           		</init-param>
        	</filter>
      
        	<filter-mapping>
           		<filter-name>CAS Single Sign Out Filter</filter-name>
           		<url-pattern>/*</url-pattern>
        	</filter-mapping>
        	-->
      
        	<filter>
        		<filter-name>CAS Validation Filter</filter-name>
        		<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
      
        		<!-- 
        		<filter-class>org.jasig.cas.client.validation.Saml11TicketValidationFilter</filter-class> 
        		-->	
        		<!-- 
        		<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>	
        		-->	
        	
        	<init-param>
        		<param-name>casServerUrlPrefix</param-name>
        		<!--
        		<param-value>https://sso.hoau.com:8433/cas</param-value>
        		<param-value>https://proxy.sso.hoau.com:443/cas</param-value>
        		-->
        		<param-value>https://proxy.sso.hoau.com:443/cas</param-value>
        	</init-param>
        	
        	<!---->
      
        	<init-param>
        		<param-name>serverName</param-name>
        		<param-value>https://app1.hoau.com:8413</param-value>
        	</init-param>
      
        	<init-param>
        		<param-name>redirectAfterValidation</param-name>
        		<param-value>true</param-value>
        	</init-param>
        	<init-param>
        		<param-name>useSession</param-name>
        		<param-value>true</param-value>
        	</init-param>
        	<init-param>
        		<param-name>acceptAnyProxy</param-name>
        		<param-value>true</param-value>
        	</init-param>
        	<!-- 
        	<init-param>
        		<param-name>ticketValidatorClass</param-name>
        		<param-value>org.jasig.cas.client.validation.Cas20ProxyTicketValidator</param-value>
        	</init-param>
        	-->
        	<!-- http://haohaoxuexi.iteye.com/blog/2145751
        	<init-param>
        		<param-name>proxyReceptorUrl</param-name>
        		<param-value>/proxyCallback</param-value>
        	</init-param>
        	<init-param>
        		<param-name>proxyCallbackUrl</param-name>
        		<param-value>https://app1.hoau.com:8413/cas1/proxyCallback</param-value>
        	</init-param>
        	-->
        </filter>
      
        <filter>
        	<filter-name>CAS Authentication Filter</filter-name>
        	<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
        	<!-- 
        	<filter-class>org.jasig.cas.client.authentication.Saml11AuthenticationFilter</filter-class> 
        	-->
        	<!-- 
        	<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> 
        	-->
        	<init-param>
        		<param-name>casServerLoginUrl</param-name>
        		<!--
        		<param-value>https://sso.hoau.com:8433/cas/login</param-value>
        		-->	
        		<param-value>https://proxy.sso.hoau.com:443/cas/login</param-value>
        	</init-param>
        	<init-param>
        		<param-name>serverName</param-name>
        		<param-value>https://app1.hoau.com:8413</param-value>
        	</init-param>
        </filter>
      
        <filter>
        	<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        	<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
        </filter>
      
        <filter-mapping>
        	<filter-name>CAS Validation Filter</filter-name>
        	<url-pattern>/*</url-pattern>
        </filter-mapping>
      
        <filter-mapping>
        	<filter-name>CAS Authentication Filter</filter-name>
        	<url-pattern>/*</url-pattern>
        </filter-mapping>
      
        <filter-mapping>
        	<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        	<url-pattern>/*</url-pattern>
        </filter-mapping>
      
        <!--
        <servlet>
        	<servlet-name>ProxyValidate</servlet-name>
            <servlet-class> edu.yale.its.tp.cas.servlet.ProxyValidate</servlet-class>
        </servlet>
      
      
        <servlet> 
        	<servlet-name>ProxyTicketReceptor</servlet-name> 
        	<servlet-class>edu.yale.its.tp.cas.proxy.ProxyTicketReceptor</servlet-class> 
       	</servlet > 
      
       	<servlet-mapping> 
        	<servlet-name>ProxyTicketReceptor</servlet-name> 
         	<url-pattern>/CasProxyServlet </url-pattern> 
       	</servlet-mapping >
        -->
        <welcome-file-list>
        	<welcome-file>
        		index.jsp
            </welcome-file>
        </welcome-file-list>
        </web-app>
      

      *注意:

      • “CAS Validation Filter”需要放在“CAS Authentication Filter”之前
      • 此代理非彼代理

        網上一些文章說的需要配置諸如:

        1. “SingleSignOutHttpSessionListener”
        2. “SingleSignOutFilter”
        3. “ticketValidatorClass”
        4. “ProxyValidate”
        5. “ProxyTicketReceptor”

      均不需要

      • 如果誤配了SingleSignOutFilter,會出現異常

        Caused by: java.io.IOException: Server returned HTTP response code: 500 for URL: https://proxy.sso.hoau.com:443/cas/proxyValidate?ticket=ST-31-TM9EbFoQbasNdXh11HaJ-cas01.sso.hoau.com&service=https%3A%2F%2Fapp2.hoau.com%3A8423%2Fcas2%3Bjsessionid%3D0CEB865B53E64FF31BF02A496DF73860.tomcat2
        
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1840)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
        at org.jasig.cas.client.util.CommonUtils.getResponseFromServer(CommonUtils.java:429)
        ... 24 more
      

      如果為了在https下錄制自動化測試腳本,會修改classpath下/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/security的java.security文件,那么也可能出現類似的錯誤。

    • https://app2.hoau.com:8423

      web.xml配置同上

      *注意:修改端口

  • CAS服務器(Tomcat x 1)

測試

*1. 訪問“https://app1.hoau.com:8413/cas1”

會重定向到“https://proxy.sso.hoau.com/cas/login?service=https%3A%2F%2Fapp1.hoau.com%3A8413%2Fcas1”

*2. 然后輸入用戶明密碼(test01/psw01)

如果驗證成功,則會將瀏覽器重定向到app1的登陸成功頁面。

*3. 再次訪問“https://app1.hoau.com:8413/cas1”

可以直接進入登陸成功頁,而無需輸入用戶名密碼。

*4. 訪問另一應用

同樣可以通過test01用戶直接進入登陸成功頁,而無需輸入用戶名密碼。

代理下的網絡順序分析

參照另一文章:(待出)

源代碼

還在准備,如果需要的童鞋請留言。

結束


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM