#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文件,找到:
替换为:
secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="D:\localhost.keystore"
keystorePass="123456"/>
注意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中配置域名。
假如把服务端和客户端应用都部署到同一台机器上的同一个Tomcat服务器中,那么生成证书的时候,可以使用localhost作为域名。
此时服务端和客户端都使用同一个Tomcat进行部署,所以需要把服务端和客户端都配置为不同的服务(service),具体方法是修改conf/service.xml文件。
示例如下:
connectionTimeout="20000"
redirectPort="8443"/>
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="d:/localhost.keystore" keystorePass="123456"
clientAuth="false" sslProtocol="TLS"
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"/>
resourceName="UserDatabase"/>
unpackWARs="true" autoDeploy="true">
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b"/>
connectionTimeout="20000"
redirectPort="9443"/>
resourceName="UserDatabase"/>
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
这里分别配置了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的客户端功能。
首先配置依赖:
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的内容:
value="https://server:8443/sso-server/login?service=http://service.com:9090/sso-service/cas"/>
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,客户端就能正常运行。
##自定义登陆页面
参考资料:
修改casLoginView.jsp,或者自定义JSP,并修改resource/default_views.properties文件中的对应值。
#原理解析
##login请求的处理过程
核心类AuthenticationViaFormAction,这里还用到了Spring Web Flow,有必要了解一下(配置文件login-webflow.xml)。