首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

CAS客户端证件认证登录

2012-10-26 
CAS客户端证书认证登录前端时间需要实现公司内网证书自动登录CAS.由于对CAS的底层还不是特别了解所以学习

CAS客户端证书认证登录

前端时间需要实现公司内网证书自动登录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'] != '' &amp;&amp; externalContext.requestParameterMap['gateway'] != null &amp;&amp; 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'] != '' &amp;&amp; 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" name="code"><bean id="authenticationManager"/><bean /><bean /><ref bean="dynamicAuthenticationHandler" /><ref bean="x509CredentialsAuthenticationHandler"/></list></property></bean>

?x509CredentialsAuthenticationHandler这个CAS自带了,但是我们需要返回到CAS Client的为证书的邮箱,而CAS没有提供这样的Resolver,所以我自己写了一个从证书中取得email的X509CertificateCredentialsToDNEmailPrincipalResolver

?

当然这里引用到的类也需要在Spring中进行配置

<bean id="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"    />

?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());@Overrideprotected 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 occurrence it the DN contains several     * instances of a part (i.e. cn=x, cn=y returns x).     *     * @param dn String containing DN, The DN string has the format "C=SE, O=xx, OU=yy, CN=zz".     * @param dnpart String specifying which part of the DN to get, should be "CN" or "OU" etc.     *     * @return String containing dnpart or null if dnpart is not present     */    public  String getPartFromDN(String dn, String dnpart) {        log.debug(">getPartFromDN: dn:'" + dn + "', dnpart=" + dnpart);        String part = null;        if ((dn != null) && (dnpart != null)) {            String o;            dnpart += "="; // we search for 'CN=' etc.            X509NameTokenizer xt = new X509NameTokenizer(dn);            while (xt.hasMoreTokens()) {                o = xt.nextToken();                //log.debug("checking: "+o.substring(0,dnpart.length()));                if ((o.length() > dnpart.length()) &&                    o.substring(0, dnpart.length()).equalsIgnoreCase(dnpart)) {                    part = o.substring(dnpart.length());                    break;                }            }        }        log.debug("<getpartFromDN: resulting DN part=" + part);        return part;    } //getPartFromDN}
?

?

1 楼 infante_yin 2010-08-19   你好!可以配置多种证书吗? 2 楼 musenl 2012-08-27   dynamicAuthenticationHandler.reload()是哪个类的啊

热点排行