- 浏览: 182446 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (153)
- 小技巧 (14)
- spring (3)
- struts2 (20)
- hibernate (0)
- java api (2)
- java se (8)
- jsp/servlet (4)
- oracle (0)
- mysql (1)
- ms sqlserver (1)
- js (30)
- jquery (8)
- ajax (2)
- .net (1)
- 软件 (1)
- j2ee (25)
- 网址收藏 (3)
- web综合 (9)
- web打印控件 (3)
- fckeditor (2)
- Groovy (1)
- PHP (5)
- 项目管理 (1)
- SEO (1)
- PostgreSQL (5)
- CKeditor (1)
- Fusion chart (1)
- 网页播放器 (1)
- 曾遇bug (3)
- java日志 (1)
- linux/Unix/CentOs (5)
- VBA (1)
- C# (0)
- 日期控件 (1)
- tomcat (2)
- cookies (1)
- java7 (1)
- JAVA文件操作 (2)
- hibernate;ehcache (2)
- 缓存 (1)
- dd (0)
- DB (1)
- android (2)
最新评论
-
flyingbin:
沙发,不过从头到尾没怎么看懂~
Windows密码本地破解通用方法 -
jfeimao:
credentialsToPrincipalResolvers ...
CAS(单点登陆)---总结一 -
haige18:
这两张图片引用的是网易的地址,现在资源有可能被删除了,所以就显 ...
Struts2中的Value Stack/Stack Context -
fengzhisha0914:
我的图片也不显示了..为何...
Struts2中的Value Stack/Stack Context -
greatwqs:
java.lang.IllegalStateException ...
java.lang.IllegalStateException:Cannot forward after response has been committed
前端时间需要实现公司内网证书自动登录CAS.
由于对CAS的底层还不是特别了解所以学习了下,看了下源码.
这里我由上而下的讲解实现的过程.
1.Web Flow
我们都知道CAS目前使用了Spring Web Flow,
在CAS中Spring Web Flow的配置文件为login-webflow.xml
里面主要配置了登录的流程.这个如果用图来表示的话那应该是一个状态图,
一些节点会有一些判断然后会有不同的分支.
这里增加了startX509Authenticate这个节点,当需要登录的时候首先进入这个节点来验证,如果这里验证不成功的话才会进入普通的登录界面.负责直接登录成功,或者登录失败.
修改后的配置文件如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <flow xmlns="http://www.springframework.org/schema/webflow"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="
- http://www.springframework.org/schema/webflow
- http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">
- <start-state idref="initialFlowSetup"/>
- <action-state id="initialFlowSetup">
- <action bean="initialFlowSetupAction" />
- <transition on="success" to="ticketGrantingTicketExistsCheck" />
- </action-state>
- <decision-state id="ticketGrantingTicketExistsCheck">
- <if test="${flowScope.ticketGrantingTicketId != null}" then="hasServiceCheck" else="gatewayRequestCheck" />
- </decision-state>
- <decision-state id="gatewayRequestCheck">
- <if test="${externalContext.requestParameterMap['gateway'] != '' && externalContext.requestParameterMap['gateway'] != null && flowScope.service != null}" then="redirect" else="startX509Authenticate" />
- </decision-state>
- <decision-state id="hasServiceCheck">
- <if test="${flowScope.service != null}" then="renewRequestCheck" else="viewGenericLoginSuccess" />
- </decision-state>
- <decision-state id="renewRequestCheck">
- <if test="${externalContext.requestParameterMap['renew'] != '' && externalContext.requestParameterMap['renew'] != null}" then="startX509Authenticate" else="generateServiceTicket" />
- </decision-state>
- <decision-state id="warn">
- <if test="${flowScope.warnCookieValue}" then="showWarningView" else="redirect" />
- </decision-state>
- <action-state id="startX509Authenticate">
- <action bean="x509Check" />
- <transition on="success" to="sendTicketGrantingTicket" />
- <transition on="error" to="viewLoginForm" />
- </action-state>
- <view-state id="viewLoginForm" view="casLoginView">
- <render-actions>
- <action bean="authenticationViaFormAction" method="setupForm"/>
- <action bean="authenticationViaFormAction" method="referenceData"/>
- </render-actions>
- <transition on="submit" to="bindAndValidate" />
- </view-state>
- <action-state id="bindAndValidate">
- <action bean="authenticationViaFormAction" />
- <transition on="success" to="submit" />
- <transition on="error" to="viewLoginForm" />
- </action-state>
- <action-state id="submit">
- <action bean="authenticationViaFormAction" method="submit" />
- <transition on="warn" to="warn" />
- <transition on="success" to="sendTicketGrantingTicket" />
- <transition on="error" to="viewLoginForm" />
- </action-state>
- <action-state id="sendTicketGrantingTicket">
- <action bean="sendTicketGrantingTicketAction" />
- <transition on="success" to="serviceCheck" />
- </action-state>
- <decision-state id="serviceCheck">
- <if test="${flowScope.service != null}" then="generateServiceTicket" else="viewGenericLoginSuccess" />
- </decision-state>
- <action-state id="generateServiceTicket">
- <action bean="generateServiceTicketAction" />
- <transition on="success" to ="warn" />
- <transition on="error" to="viewLoginForm" />
- <transition on="gateway" to="redirect" />
- </action-state>
- <end-state id="viewGenericLoginSuccess" view="casLoginGenericSuccessView" />
- <end-state id="showWarningView" view="casLoginConfirmView" />
- <end-state id="redirect" view="bean:alibabaDynamicRedirectViewSelector" />
- <end-state id="viewServiceErrorView" view="viewServiceErrorView" />
- <end-state id="viewServiceSsoErrorView" view="viewServiceSsoErrorView" />
- <global-transitions>
- <transition to="viewServiceErrorView" on-exception="org.springframework.webflow.execution.repository.NoSuchFlowExecutionException" />
- <transition to="viewServiceSsoErrorView" on-exception="org.jasig.cas.services.UnauthorizedSsoServiceException" />
- <transition to="viewServiceErrorView" on-exception="org.jasig.cas.services.UnauthorizedServiceException" />
- </global-transitions>
- </flow>
<?xml version="1.0" encoding="UTF-8"?> <flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd"> <start-state idref="initialFlowSetup"/> <action-state id="initialFlowSetup"> <action bean="initialFlowSetupAction" /> <transition on="success" to="ticketGrantingTicketExistsCheck" /> </action-state> <decision-state id="ticketGrantingTicketExistsCheck"> <if test="${flowScope.ticketGrantingTicketId != null}" then="hasServiceCheck" else="gatewayRequestCheck" /> </decision-state> <decision-state id="gatewayRequestCheck"> <if test="${externalContext.requestParameterMap['gateway'] != '' && externalContext.requestParameterMap['gateway'] != null && flowScope.service != null}" then="redirect" else="startX509Authenticate" /> </decision-state> <decision-state id="hasServiceCheck"> <if test="${flowScope.service != null}" then="renewRequestCheck" else="viewGenericLoginSuccess" /> </decision-state> <decision-state id="renewRequestCheck"> <if test="${externalContext.requestParameterMap['renew'] != '' && externalContext.requestParameterMap['renew'] != null}" then="startX509Authenticate" else="generateServiceTicket" /> </decision-state> <decision-state id="warn"> <if test="${flowScope.warnCookieValue}" then="showWarningView" else="redirect" /> </decision-state> <action-state id="startX509Authenticate"> <action bean="x509Check" /> <transition on="success" to="sendTicketGrantingTicket" /> <transition on="error" to="viewLoginForm" /> </action-state> <view-state id="viewLoginForm" view="casLoginView"> <render-actions> <action bean="authenticationViaFormAction" method="setupForm"/> <action bean="authenticationViaFormAction" method="referenceData"/> </render-actions> <transition on="submit" to="bindAndValidate" /> </view-state> <action-state id="bindAndValidate"> <action bean="authenticationViaFormAction" /> <transition on="success" to="submit" /> <transition on="error" to="viewLoginForm" /> </action-state> <action-state id="submit"> <action bean="authenticationViaFormAction" method="submit" /> <transition on="warn" to="warn" /> <transition on="success" to="sendTicketGrantingTicket" /> <transition on="error" to="viewLoginForm" /> </action-state> <action-state id="sendTicketGrantingTicket"> <action bean="sendTicketGrantingTicketAction" /> <transition on="success" to="serviceCheck" /> </action-state> <decision-state id="serviceCheck"> <if test="${flowScope.service != null}" then="generateServiceTicket" else="viewGenericLoginSuccess" /> </decision-state> <action-state id="generateServiceTicket"> <action bean="generateServiceTicketAction" /> <transition on="success" to ="warn" /> <transition on="error" to="viewLoginForm" /> <transition on="gateway" to="redirect" /> </action-state> <end-state id="viewGenericLoginSuccess" view="casLoginGenericSuccessView" /> <end-state id="showWarningView" view="casLoginConfirmView" /> <end-state id="redirect" view="bean:alibabaDynamicRedirectViewSelector" /> <end-state id="viewServiceErrorView" view="viewServiceErrorView" /> <end-state id="viewServiceSsoErrorView" view="viewServiceSsoErrorView" /> <global-transitions> <transition to="viewServiceErrorView" on-exception="org.springframework.webflow.execution.repository.NoSuchFlowExecutionException" /> <transition to="viewServiceSsoErrorView" on-exception="org.jasig.cas.services.UnauthorizedSsoServiceException" /> <transition to="viewServiceErrorView" on-exception="org.jasig.cas.services.UnauthorizedServiceException" /> </global-transitions> </flow>
2.从X509Check着手
从上面的配置文件我们可看出startX509Authenticate这个节点对应的Bean是x509Check
那么我们需要增加这样的一个Bean
我们在cas-servlet.xml这个配置文件中增加这个类的配置,因为CAS自带了证书认证的Action
- <bean id="x509Check" class="org.jasig.cas.adaptors.x509.web.flow.X509CertificateCredentialsNonInteractiveAction"
- p:centralAuthenticationService-ref="centralAuthenticationService"/>
<bean id="x509Check" class="org.jasig.cas.adaptors.x509.web.flow.X509CertificateCredentialsNonInteractiveAction" p:centralAuthenticationService-ref="centralAuthenticationService"/>
这里不得不插进来说一下,在执行的时候是怎么个机制了.
当有一个请求过来之后,web flow安排对应节点的Action 来处理,
Action便通过它的centralAuthenticationService 来进行createTicketGrantingTicket,传递的参数是credentials.
centralAuthenticationService ,即org.jasig.cas.CentralAuthenticationServiceImpl这个类.
在颁发TGT之前先通过自己的authenticationManager来验证当前传递过来的credentials是否合法.
来到authenticationManager 的家中之后,使用什么来验证credentials呢,对了各种authenticationHandlers该上场了,这些authenticationHandlers 们也都是在配置authenticationManager的时候xml配置进去的.这里会选择一个能够处理当前credential的authenticationHandler来进行验证工作(authenticationHandler.supports(credentials)).也就是这些处理器都需要实现supports这个方法.
如果验证成功了,我们需要将一些标示信息带到cas的client端阿,那边需要这个信息.
所以验证之后,credentialsToPrincipalResolvers 们上场了,他们能够很好的带出需要传回给cas client的信息.
经过上面的分析,我们需要将我们自己的Handler和credentialsToPrincipalResolvers添加到authenticationManager的配置中
- <bean id="authenticationManager"
- class="org.jasig.cas.authentication.AuthenticationManagerImpl">
- <property name="credentialsToPrincipalResolvers">
- <list>
- <bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" />
- <bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" />
- <bean class="org.jasig.cas.adaptors.x509.authentication.principal.X509CertificateCredentialsToDNEmailPrincipalResolver"/>
- </list>
- </property>
- <property name="authenticationHandlers">
- <list>
- <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
- p:httpClient-ref="httpClient" />
- <ref bean="dynamicAuthenticationHandler" />
- <ref bean="x509CredentialsAuthenticationHandler"/>
- </list>
- </property>
- </bean>
<bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl"> <property name="credentialsToPrincipalResolvers"> <list> <bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" /> <bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" /> <bean class="org.jasig.cas.adaptors.x509.authentication.principal.X509CertificateCredentialsToDNEmailPrincipalResolver"/> </list> </property> <property name="authenticationHandlers"> <list> <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" p:httpClient-ref="httpClient" /> <ref bean="dynamicAuthenticationHandler" /> <ref bean="x509CredentialsAuthenticationHandler"/> </list> </property> </bean>
x509CredentialsAuthenticationHandler这个CAS自带了,但是我们需要返回到CAS Client的为证书的邮箱,而CAS没有提供这样的Resolver,所以我自己写了一个从证书中取得email的X509CertificateCredentialsToDNEmailPrincipalResolver
当然这里引用到的类也需要在Spring中进行配置
- <bean id="x509CredentialsAuthenticationHandler" class="org.jasig.cas.adaptors.x509.authentication.handler.support.X509CredentialsAuthenticationHandler" >
- <property name="trustedIssuerDnPattern" value="CN=intranet.+"/>
- </bean>
<bean id="x509CredentialsAuthenticationHandler" class="org.jasig.cas.adaptors.x509.authentication.handler.support.X509CredentialsAuthenticationHandler" > <property name="trustedIssuerDnPattern" value="CN=intranet.+"/> </bean>
这样便可以了.
3.Tomcat配置
接下来我们便需要将CA的证书加入到servlet容器的TrustStore中.并开启客户端认证.
- <Connector port="8447" maxHttpHeaderSize="8192"
- maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
- enableLookups="false" disableUploadTimeout="true"
- acceptCount="100" scheme="https" secure="true"
- clientAuth="want" sslProtocol="TLS"
- keystoreFile="conf/ssl/keystore.jks" keystorePass="changeit"
- truststoreFile="conf/ssl/keystore.jks" truststorePass="changeit"
- />
<Connector port="8447" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" clientAuth="want" sslProtocol="TLS" keystoreFile="conf/ssl/keystore.jks" keystorePass="changeit" truststoreFile="conf/ssl/keystore.jks" truststorePass="changeit" />
clientAuth="want"配置成want表示不强求,如果有则使用,配置成true的话那就必须通过证书,否则直接返回404
我们这里为了如果没有证书还可以进去普通登录页面,所以采取了want这个参数.
启动CAS ,一切OK了.
---------------------------------------------------------------------------------------------
PS:附上从证书中获取Email的代码
- package org.jasig.cas.adaptors.x509.authentication.principal;
- import java.security.cert.X509Certificate;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.bouncycastle.asn1.x509.X509NameTokenizer;
- public class X509CertificateCredentialsToDNEmailPrincipalResolver extends AbstractX509CertificateCredentialsToPrincipalResolver {
- public static final String EMAIL = "rfc822name";
- public static final String EMAIL1 = "email";
- public static final String EMAIL2 = "EmailAddress";
- public static final String EMAIL3 = "E";
- private static final String[] EMAILIDS = { EMAIL, EMAIL1, EMAIL2, EMAIL3 };
- protected final Log log = LogFactory.getLog(this.getClass());
- @Override
- protected String resolvePrincipalInternal(X509Certificate certificate) {
- String email = getEmailFromDN(certificate.getSubjectDN().getName());
- dynamicAuthenticationHandler.reload();
- if(email!=null){
- return email;
- }
- return null;
- }
- /**
- * Convenience method for getting an email address from a DN.
- * @param dn the DN
- * @return the found email address, or <code>null</code> if none is found
- */
- public String getEmailFromDN(String dn) {
- log.info(">getEmailFromDN(" + dn + ")");
- String email = null;
- for (int i = 0; (i < EMAILIDS.length) && (email == null); i++) {
- email = getPartFromDN(dn, EMAILIDS[i]);
- }
- log.error("<getEmailFromDN(" + dn + "): " + email);
- return email;
- }
- /**
- * Gets a specified part of a DN. Specifically the first o
发表评论
-
Java 连接access 使用access文件 不用配置
2012-05-23 09:43 862String url = "jdbc:od ... -
在Java 7里如何对文件进行操作
2012-04-25 16:53 712下面的代码片段是由经过验证的程序修改而来。观察这些代码片段你会 ... -
Java将中文转换成拼音,用于字母的模糊查询
2012-04-23 15:05 1804/** * 将汉字转换为拼音 * ... -
JSON+Jquery实现页面动态加载
2011-12-09 18:10 735看附件 -
轻松实现Apache,Tomcat集群和负载均衡
2011-04-29 09:42 694作者:罗代均 ldj_work#126.com,转载请保 ... -
Java或web中解决所有路径问题
2011-04-28 21:48 663Java中使用的路径, ... -
基于jquery的上传插件Uploadify
2010-11-26 17:24 946无论是做Web产品还是Web项目,文件上传是经常要用到的功 ... -
JSP中的两种包含页面的方法
2010-11-09 11:47 722写道 第一种:include指令:当JSP转换成Servle ... -
pager-taglib 使用说明
2010-11-03 22:10 894http://www.iteye.com/topic/6265 ... -
jFreeChart 在jsp页上实现简单的折线图、柱状图
2010-10-31 13:57 1955可参考资料与网址 官方网站 http://www ... -
SSH + Lucene + 分页 + 排序 + 高亮 模拟简单新闻网站搜索引擎
2010-10-31 11:22 863SSH + Lucene + 分页 + 排序 + 高亮 ... -
【原创】CAS调研总结
2010-10-31 11:13 913本篇文章是对JA-SIG CAS(v3.3)的初步调研总结。 ... -
CAS(单点登陆)---总结一
2010-10-31 11:05 1283单点登录(sso)是指基 ... -
单点登录CAS Server 介绍
2010-10-31 11:04 912下面的讲解基于CAS Server ... -
CAS(单点登陆)---总结二
2010-10-31 11:01 779返回更多用户信息继... 配置ssoAuth/WEB-INF ... -
java 防sql注入
2010-10-27 21:29 793package com.cssweb.webcall.util ... -
防止未登录进行操作 解决登录页面内嵌问题
2010-10-27 21:28 1370防止未登录进行操作 解决登录页面内嵌问题 1.进入登录的 ... -
fckeditor的使用
2010-10-27 21:17 721先根据上一篇博文下载FckEditor的工具 1.简单的例子 ... -
网页在线编辑器 fckeditor
2010-10-27 21:16 990几种常见的网页在线编 ... -
解决地址栏传输中文问题
2010-10-27 21:10 773一、传统的方法,修改tomcat/conf/server.xm ...
相关推荐
cas4.2.7服务端+cas客户端+示例程序+环境搭建之客户端war包 一切跑不起来的程序和走不通的...该客户端的这个URL还演示了如何调用cas服务端获取当前登录用户的相关信息(由服务端负责从数据库中读取后返回给cas客户端)。
cas客户端集成单点登录代码cas客户端集成单点登录代码cas客户端集成单点登录代码cas客户端集成单点登录代码cas客户端集成单点登录代码cas客户端集成单点登录代码
CAS客户端获取用户保存至sessionUser
cas客户端登录配置详细文档,支持客户端自定义登录和服务端统一登录。
包含cas源码、cas使用说明文档(包含配置信息)、连接数据库所需jar包、cas服务端自定义返回值等
cas客户端集成单点登录代码登录登出cas客户端集成单点登录代码登录登出cas客户端集成单点登录代码登录登出cas客户端集成单点登录代码登录登出cas客户端集成单点登录代码登录登出
CAS客户端自定义核心过滤器,继承CAS的AbstractCasFilter自定义AuthenticationFilter
cas 单点登录客户端连接服务器所需jar包
整合spring+springWebMVC+cas客户端,亲自验证可用,连接的cas服务端是cas4.2.7,下载后在使用中若有问题,请联系我
[置顶] SSO单点登录系列2:cas客户端和cas服务端交互原理动画图解,cas协议终极分析 http://blog.csdn.net/ae6623/article/details/8848107 目 录 1 引言 4 1.1 摘要 4 1.2 范围 4 1.3 读者对象 4 1.4 关键词 4 2 ...
cas客户端代码,亲测没问题,这里是3.2.1版本完全没问题。
1.如果客户端项目采用shiro控制权限 则需要将cas-client 认证过滤交给shiro来管理 2.从shiro下载相应版本的shiro-cas-xxxx. Jar或者在maven里直接添加
CAS客户端php版 经本人验证可以使用。可以参考 http://blog.csdn.net/xiangyuanhong08/article/details/78390664
排除CAS客户端不需要过滤的路径,在web.xml文件中配置排除地址。
用于CAS配置应用程序端,将lib下jar文件放到需要整合的应用lib下
单点登录CAS.net客户端源码,已调试成功,需要在webconfig中将服务端地址以及跳转地址修改好即可
在这之前由于没有使用过Cas用来做单点登录,结果是一个坑接一个坑,我相信大多数第一次使用这个来做单点登录的大牛们=都会有类似的经历,今天就简单的把CAS客户端以SpringBoot的方式来讲述一下.(重点说一下忽略某些Url...
cas 结合 springmvc shiro 做项目单点登录包括cas服务端,cas客户端。shiro-cas集成项目
CAS客户端JAR包版本3.3.3下载之后拷贝到lib文件夹下 配置web.xml <!--退出--> <param-name>casServerLogoutUrl <param-value>http://192.168.156.120:8080/cas/logout</param-value><!--server cas ...