• 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用户直接进入登陆成功页,而无需输入用户名密码。

    代理下的网络顺序分析

    参照另一文章:(待出)

    源代码

    还在准备,如果需要的童鞋请留言。

    结束

  • 相关阅读:
    PDF 补丁丁 0.5.0.2713 发布(替换字库功能修正字符宽度问题)
    PDF 补丁丁 0.5.0.2691 发布(替换字库新增字符映射功能)
    PDF 补丁丁 0.5.0.2657 发布
    安装Windows 10后PDF补丁丁等程序界面变得模糊的解决办法
    《React+Redux前端开发实战》笔记1:不涉及React项目构建的Hello World案例
    React前端有钱途吗?《React+Redux前端开发实战》学起来
    《陪孩子像搭积木一样学编程》,一起来玩Scratch(1)使用Scratch编程的基本流程
    为什么使用React Native
    React Native移动开发实战-5-Android平台的调试技巧
    React Native移动开发实战-4-Android平台的适配原理
  • 原文地址:https://www.cnblogs.com/richaaaard/p/5053108.html
Copyright © 2020-2023  润新知