# CAS Demo **Repository Path**: paul.lmc/CAS-Demo ## Basic Information - **Project Name**: CAS Demo - **Description**: CAS服务端和客户端示例DEMO。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 6 - **Created**: 2019-06-02 - **Last Updated**: 2021-06-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README >参考资料: [开涛shiro教程14小节SSL](http://jinnianshilongnian.iteye.com/blog/2036420) [开涛shiro教程15小节单点登录](http://jinnianshilongnian.iteye.com/blog/2036730) [Spring Security整合CAS官方文档,有完整的说明](https://docs.spring.io/spring-security/site/docs/3.1.x/reference/cas.html) [Shiro整合CAS官方文档,根据这个文档配置客户端](http://shiro.apache.org/cas.html) #SSL证书 CAS服务端进行登陆验证时一般使用HTTPS协议,此时需要提供证书。 **证书可以使用JDK自带工具生成,其中证书私钥需要存放到CAS服务端,供Tomcat的SSL端口配置使用(获取其他容器);证书公钥则存放到客户端应用程序运行的JDK中。** ##keytool生成证书 JDK自带的keytool工具可以生成证书,示例命令:`keytool -genkey -keystore "D:\localhost.keystore" -alias localhost -keyalg RSA` ``` keytool -genkey -keystore "D:\localhost.keystore" -alias localhost -keyalg RSA 输入密钥库口令: 再次输入新口令: 您的名字与姓氏是什么? [Unknown]: localhost 您的组织单位名称是什么? [Unknown]: invengo.cn 您的组织名称是什么? [Unknown]: invengo.cn 您所在的城市或区域名称是什么? [Unknown]: beijing 您所在的省/市/自治区名称是什么? [Unknown]: beijing 该单位的双字母国家/地区代码是什么? [Unknown]: cn CN=localhost, OU=invengo.cn, O= invengo.cn, L=beijing, ST=beijing, C=cn是否正确 ? [否]: y 输入 的密钥口令 (如果和密钥库口令相同, 按回车): 再次输入新口令: ``` ##Tomcat/Jetty使用证书配置SSL端口 Tomcat中配置SSL端口的方法是,打开conf/server.xml文件,找到: ``` ``` 替换为: ``` ``` 注意keystorePass是生成证书时输入的密码。 >特殊情况下,还需要Connectors还需要加入下列内容,否则chrome浏览器无法正常访问: ``` ciphers="TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA" ``` 如果是使用内嵌的Jetty服务器,则在pom.xml中配置: ``` org.mortbay.jetty jetty-maven-plugin 8.1.8.v20121106 /sso-server 8080 60000 8443 60000 ${project.basedir}/localhost.keystore 123456 123456 ``` 同时把证书文件localhost.keystore拷贝到项目根目录下(根据``配置)。 ##客户端JDK导入证书公钥 客户端运行JDK需要导入证书的公钥,方法还是使用keytool工具: + 首先执行命令生成公钥: ``` keytool -export -alias localhost -file d:\localhost.cer -keystore d:\localhost.keystore ``` + 然后执行命令导入到JDK: ``` keytool -import -alias localhost -file "D:/localhost.cer" -noprompt -trustcacerts -storetype jks -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -storepass 123456 ``` 如果出现导入失败,则把`%JAVA_HOME%/jre/lib/security`目录下的cacerts文件删除。 ##单机/多机部署的问题 **注意,生成证书时,当提示“您的名字与姓氏是什么?”的时候不能输入IP地址,否则错误!!** 需要使用域名代替IP地址,例如使用`localhost`代替本机,或者使用在HOSTS中配置域名。 >参考资料: http://www.cnblogs.com/sunshineatnoon/p/4123324.html http://stackoverflow.com/questions/9331087/how-to-setup-ssl-for-cas-and-client-different-machines https://wiki.jasig.org/display/casum/ssl+troubleshooting+and+reference+guide 假如把服务端和客户端应用都部署到同一台机器上的同一个Tomcat服务器中,那么生成证书的时候,可以使用localhost作为域名。 此时服务端和客户端都使用同一个Tomcat进行部署,所以需要把服务端和客户端都配置为不同的服务(service),具体方法是修改conf/service.xml文件。 示例如下: ``` ``` 这里分别配置了2个`Service`,其中`Catalina`是Tomcat默认的配置,这里在原配置基础上添加了SSL端口的配置。`Catalina`指定webapps为部署目录,**把服务端程序部署到这里。** 而`Catalina2`是新增的`Service`,指定mywebapps为部署目录,把客户端程序部署到这里。 如果希望在不同机器的不同Tomcat上分别部署服务端和客户端程序,**那么生成证书的时候需要指定域名为服务端所在机器的域名!** 例如这个有2台机器,IP分别是10.10.10.1和10.10.10.156,这里吧10.10.10.1作为服务端,首先修改这2台机器的HOSTS文件: ``` 10.10.10.1 server.com 10.10.10.156 service.com ``` 然后生成机器的是,提示`您的名字与姓氏是什么?`的时候输入server.com! 有了证书后再生成公钥,最后把公钥导入客户端所在的JDK,即10.10.10.156机器上面的JDK! 因为这里分别把服务端和客户端程序部署到各自的Tomcat中,所以Tomcat不需要再配置新的`Service`,但是别忘了服务端Tomcat上的SSL端口还是需要的! #CAS实现单点登陆 Jasig CAS包括服务端和客户端,其中服务端负责登陆校验功能和ticket验证。集成CAS的完整登陆过程大致为: + 用户访问客户端应用,例如`http://service.com:90900/sso-service`,应用判断用户没有登陆,重定向到CAS服务端的登陆页面,例如`https://server.com:8443/sso-server/login?service=http://service.com:9090/sso-service/cas`。 注意这里的判断不会使用到CAS的服务区或者客户端,可以在代码中自己实现,或者使用框架,例如shiro中配置如下内容: ``` ``` 还有地址为什么是`https://server.com:8443/sso-server/login?service=http://service.com:9090/sso-service/cas`这样的形式? 首先`https://server.com:8443/sso-server/login`是CAS服务端暴露的登陆地址,负责进行用户密码的校验。 而service后面的地址`http://service.com:9090/sso-service/cas`则是客户端暴露的用于获取ticker的地址,也就是后面所说的服务端验证成功后调整到客户端的地址。 + 请求到达服务端后显示登陆页面,输入用户名、密码进行登陆; + 如果登陆成功则服务端跳转到`http://service.com:9090/sso-service/cas?ticket=ST-1-eh2cIo92F9syvoMs5DOg-cas01.example.org`,注意url带了一个ticket,此时处理流程到达客户端; + 客户端会根据这个请求url提取ticket,然后又提交到服务端验证这个ticket是否有效; + 服务端这时候验证ticket,如果有效则返回用户身份信息给客户端; + 客户端根据身份信息就能知道用户登陆成功; + 这时候如果访问其它配置的客户端应用,会直接提交ticket到服务端进行验证,这样就不需要再次登陆了! **根据上述信息,可以知道即需要一个负责验证用户名/密码和ticket的服务端,也需要一个提取ticket并提交服务端验证的客户端应用!** ##sso server Maven项目pom.xml核心配置项如下: ``` org.jasig.cas cas-server 4.0.0 4.0.0 cas-server-sample war org.jasig.cas cas-server-webapp-support 4.0.0 ``` 其中一定要声明`parent`节点为`org.jasig.cas:cas-server`,这样就会自动下载这个模块依赖的文件。然后再添加`org.jasig.cas:cas-server-webapp-support`依赖。 接下来到github上下载cas某个版本的压缩文件,例如4.0.0版,把里面的cas-server-webapp模块的resource目录和webapp目录下的文件拷贝到当前项目的对应位置。 当前项目依赖了`org.jasig.cas:cas-server`后,自动添加一些插件,例如checkstyle、license等。当使用`jetty:run`命令其中项目时,某些插件可能执行出错。 这时候有两种解决方法: + 一种时根据插件的要求解决,一般这些插件的错误都是缺失某些文件造成的。从下载的压缩包中一般都包含了这些文件; + 在pom.xml文件配置命令,跳过这些插件,例如: ``` maven-checkstyle-plugin true com.mycila.maven-license-plugin maven-license-plugin true ``` 这里跳过了checkstyle和license2个插件。 运行配置: ``` org.mortbay.jetty jetty-maven-plugin 8.1.8.v20121106 /${project.build.finalName} 8080 60000 8443 60000 ${project.basedir}/localhost.keystore 123456 123456 ``` 注意: + 这里配置8443作为SSL连接的端口,应用程序(客户端)需要访问这个端口进行密码与ticker的验证!!** + 同时配置了SSL证书文件localhost.keystore,这是用JDK自带的keytool工具生成的。 ##sso-client 这里使用shiro框架集成CAS的客户端功能。 >参考资料:http://shiro.apache.org/cas.html 首先配置依赖: ``` org.springframework spring-core 4.0.0.RELEASE org.springframework spring-webmvc 4.0.0.RELEASE org.apache.shiro shiro-core 1.2.4 org.apache.shiro shiro-web 1.2.4 org.apache.shiro shiro-spring 1.2.4 org.apache.shiro shiro-cas 1.2.4 javax.servlet javax.servlet-api 3.1.0 provided javax.servlet.jsp jsp-api 2.2 javax.servlet jstl 1.2 ``` 可以看到这里用到了shiro作为权限控制框架。 接着根据参考资料的说明,配置shiro请求过滤规则,也就是shiro-web.xml的内容: ``` casFilter /casValidationUrl.jsp = anon /cas = casFilter /logout = logout /** = user ``` 这里有几个注意的地方: + casServerUrlPerfix是服务端验证地址,casService是客户端获取ticket的地址; + SecurityManager需要把subjectFactory修改为`CasSubjectFactory`; + 客户端获取ticket的url地址需要用`CasFilter`进行拦截; + 登陆url的值应该为:`casServiceUrlPrefix` + login?service + `casService`的格式;如果这里缺少了service参数值则不会进行重定向跳转 最后运行的时候,需要把SSL证书的公钥添加到本地JDK中,然后配置jetty测试运行环境(在pom.xml中): ``` org.mortbay.jetty jetty-maven-plugin 8.1.8.v20121106 /sso-client 9090 60000 9443 60000 ${project.basedir}/localhost.keystore 123456 123456 ``` 与服务端一样,主要是配置SSL端口与SSL证书。此时运行`jetty:run`,客户端就能正常运行。 ##自定义登陆页面 参考资料: >https://jasig.github.io/cas/4.0.x/installation/User-Interface-Customization.html 修改casLoginView.jsp,或者自定义JSP,并修改resource/default_views.properties文件中的对应值。 #原理解析 ##login请求的处理过程 核心类`AuthenticationViaFormAction`,这里还用到了Spring Web Flow,有必要了解一下(配置文件login-webflow.xml)。