[原創(chuàng)]CAS3.0 定制驗證 |
CAS v2 定制自己的驗證邏輯,大家已經(jīng)很清楚了.[官方提供的sample只簡單校驗username,password是否相等].開發(fā)者可以通過實現(xiàn)PasswordHandler接口來使用其它的認證方式,如數(shù)據(jù)庫用戶的用戶名和密碼匹配認證,數(shù)字簽名的驗證,操作系統(tǒng)用戶認證,以及LDAP用戶認證等模式。比如:
<context-param>
<param-name>edu.yale.its.tp.cas.authHandler</param-name> <param-value> edu.yale.its.tp.cas.auth.provider.KerberosAuthHandler </param-value> </context-param>
Yale CAS3代碼全部重構(gòu),功能增強,且使用了Spring和SpringWebFlow[相關(guān)知識參見Spring論壇].
deployerConfigContext.xml是描述部署細節(jié)的,他通過web.xml如下描述而加載
<context-param>
<param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/applicationContext.xml, /WEB-INF/mydeployerConfigContext.xml </param-value> </context-param> contextConfigLocation屬性名在Spring MVC體系中,會自動獲取.
----------------------------
deployerConfigContext.xml文件是所有CAS deployer應該關(guān)心的東西,在這里,你可以對CAS的三個核心玩意進行自己的定制: <!--1.AuthenticationManager <!-- | This bean declares our AuthenticationManager. The CentralAuthenticationService service bean | declared in applicationContext.xml picks up this AuthenticationManager by reference to its id, | "authenticationManager". Most deployers will be able to use the default AuthenticationManager | implementation and so do not need to change the class of this bean. We include the whole | AuthenticationManager here in the userConfigContext.xml so that you can see the things you will | need to change in context. +--> 2.credentialsToPrincipalResolvers <!-- | UsernamePasswordCredentialsToPrincipalResolver supports the UsernamePasswordCredentials that we use for /login | by default and produces SimplePrincipal instances conveying the username from the credentials. | | If you‘ve changed your LoginFormAction to use credentials other than UsernamePasswordCredentials then you will also | need to change this bean declaration (or add additional declarations) to declare a CredentialsToPrincipalResolver that supports the | Credentials you are using. +--> 3.authenticationHandlers 這個authenticationHandler可是所有CAS用戶都需要修改的地方 | This is the authentication handler declaration that every CAS deployer will need to change before deploying CAS | into production. The default SimpleTestUsernamePasswordAuthenticationHandler authenticates UsernamePasswordCredentials | where the username equals the password. You will need to replace this with an AuthenticationHandler that implements your | local authentication strategy. You might accomplish this by coding a new such handler and declaring | edu.someschool.its.cas.MySpecialHandler here, or you might use one of the handlers provided in the adaptors modules. +-->
思路:沒撒子說的,就是實現(xiàn)自己的Hadnle.為了避免重新編譯cas代碼,使用ant部署自己的jar到目標的lib中,并替換web.xml以及引進自己的配置文件mydeployerConfigContext.xml
步驟:
A:在應用服務器中配置DS[略]
B:修改web.xml
<context-param>
<param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/applicationContext.xml, /WEB-INF/mydeployerConfigContext.xml </param-value> </context-param> C:web.xml加入DS引用
<resource-ref>
<description> Resource reference to a factory for java.sql.Connection instances that may be used for talking to a particular database that is configured in the server.xml file. </description> <res-ref-name> jdbc/EmployeeDB </res-ref-name> <res-type> javax.sql.DataSource </res-type> <res-auth> Container </res-auth> </resource-ref> D:添加mydeployerConfigContext.xml
內(nèi)容如下:
<beans>
<!-- | This bean declares our AuthenticationManager. The CentralAuthenticationService service bean | declared in applicationContext.xml picks up this AuthenticationManager by reference to its id, | "authenticationManager". Most deployers will be able to use the default AuthenticationManager | implementation and so do not need to change the class of this bean. We include the whole | AuthenticationManager here in the userConfigContext.xml so that you can see the things you will | need to change in context. +--> <bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl"> <!-- | This is the List of CredentialToPrincipalResolvers that identify what Principal is trying to authenticate. | The AuthenticationManagerImpl considers them in order, finding a CredentialToPrincipalResolver which | supports the presented credentials. | | AuthenticationManagerImpl uses these resolvers for two purposes. First, it uses them to identify the Principal | attempting to authenticate to CAS /login . In the default configuration, it is the DefaultCredentialsToPrincipalResolver | that fills this role. If you are using some other kind of credentials than UsernamePasswordCredentials, you will need to replace | DefaultCredentialsToPrincipalResolver with a CredentialsToPrincipalResolver that supports the credentials you are | using. | | Second, AuthenticationManagerImpl uses these resolvers to identify a service requesting a proxy granting ticket. | In the default configuration, it is the HttpBasedServiceCredentialsToPrincipalResolver that serves this purpose. | You will need to change this list if you are identifying services by something more or other than their callback URL. +--> <property name="credentialsToPrincipalResolvers"> <list> <!-- | UsernamePasswordCredentialsToPrincipalResolver supports the UsernamePasswordCredentials that we use for /login | by default and produces SimplePrincipal instances conveying the username from the credentials. | | If you‘ve changed your LoginFormAction to use credentials other than UsernamePasswordCredentials then you will also | need to change this bean declaration (or add additional declarations) to declare a CredentialsToPrincipalResolver that supports the | Credentials you are using. +--> <bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" /> <!-- | HttpBasedServiceCredentialsToPrincipalResolver supports HttpBasedCredentials. It supports the CAS 2.0 approach of | authenticating services by SSL callback, extracting the callback URL from the Credentials and representing it as a | SimpleService identified by that callback URL. | | If you are representing services by something more or other than an HTTPS URL whereat they are able to | receive a proxy callback, you will need to change this bean declaration (or add additional declarations). +--> <bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" /> </list> </property> <!--
| Whereas CredentialsToPrincipalResolvers identify who it is some Credentials might authenticate, | AuthenticationHandlers actually authenticate credentials. Here we declare the AuthenticationHandlers that | authenticate the Principals that the CredentialsToPrincipalResolvers identified. CAS will try these handlers in turn | until it finds one that both supports the Credentials presented and succeeds in authenticating. +--> <property name="authenticationHandlers"> <list> <!-- | This is the authentication handler that authenticates services by means of callback via SSL, thereby validating | a server side SSL certificate. +--> <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" /> <bean class="cn.com.tiansky.cas.authenticationHandlers.DsHandlers" /> </list> </property> </bean> </beans> E:編寫DsHandlers package cn.com.tiansky.cas.authenticationHandlers;
import java.sql.Connection;
import java.sql.ResultSet; import java.sql.Statement; import javax.naming.Context;
import javax.naming.InitialContext; import javax.sql.DataSource; import org.apache.log4j.Logger;
import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler; import org.jasig.cas.authentication.principal.UsernamePasswordCredentials; import cn.com.tiansky.tool.MD5;
/** * 支援CAS3,。實現(xiàn)自己的Handler(未自定義credentials,如因業(yè)務需要而修改,則需要同時 * 修改LoginFormAction和定義自己的credentialsToPrincipalResolvers)\ * ,你的需求也許包括了需要通過檢索數(shù)據(jù)庫來比配credential中的username和password, * 也可能不是數(shù)據(jù)庫,而是LDAP什么的,總之你得開始制作自己的handler了! * credential的種類是很多的,有的基于用戶名和密碼,有的基于http請求, * 如果你有你自己的credential的話,就得為它制作有一個handler, * 來告訴CAS如何處理這種特有的credential。 * @author tiansky * @version 1.0 * */ public final class DsHandlers extends AbstractUsernamePasswordAuthenticationHandler{ /**
* Logger log:log4j日志 */ private Logger log=Logger.getLogger(AbstractUsernamePasswordAuthenticationHandler.class); /** * 相關(guān)的數(shù)據(jù)庫配置DS對應的jndi */ private String _jndi="jdbc/EmployeeDB"; /* (non-Javadoc) * @see org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler#authenticateUsernamePasswordInternal(org.jasig.cas.authentication.principal.UsernamePasswordCredentials) */ public boolean authenticateUsernamePasswordInternal( final UsernamePasswordCredentials credentials) { String username = credentials.getUsername(); String password = credentials.getPassword(); log.info("username:"+username); log.info("password:"+password); try { password = MD5.encrypt(password); log.debug("md5password" + password); } catch (Exception e) { log.warn("MD5加密出錯", e); //throw new Exception("MD5加密出錯"); return false; } /* if (StringUtils.hasText(username) && StringUtils.hasText(password) && username.equals(getPasswordEncoder().encode(password))) { getLog().debug( "User [" + username + "] was successfully authenticated."); return true; } */ try { if(checkuser(username,password)==1) { getLog().info("認證成功!"); return true; } } catch(Exception e) { getLog().error("User [" + username + "] failed authentication",e); } return false;
} private int checkuser(String user, String pwd) throws Exception { int rei = 0; // Obtain our environment naming context log.debug("Obtain our environment naming context"); Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); // Look up our data source
DataSource ds = (DataSource) envCtx.lookup(this._jndi); log.debug("獲取ds成功!"); // Allocate and use a connection from the pool Connection conn = ds.getConnection(); log.debug("獲取conn成功!"); // ... use this connection to access the database ... String sql = "select OPERATORID from operator where OPERATORLOGINNAME=‘" + user + "‘ and OPERATORPASSWORD=‘" + pwd + "‘ "; log.info("sql!= "+sql); Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(sql); if (rs.next()) { //String oid = rs.getString("OPERATORID"); /* _op = new Operator(oid); _op.setName("操作員"); _op.setLoginname(user); _op.setPwd(pwd); */ rei = 1; } else { System.out.println("賬號不存在或密碼錯誤!"); } conn.close(); return rei; }
/* (non-Javadoc) * @see org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler#afterPropertiesSetInternal() */ protected void afterPropertiesSetInternal() throws Exception { super.afterPropertiesSetInternal(); getLog() .warn( this.getClass().getName() + " is only to be used in a production environment."); } }
F:ant 發(fā)布
G:運行調(diào)試
附錄:ANT腳本
<?xml version="1.0" encoding="gb2312"?>
<project name="casself" default="release" basedir="." > <property name="deployment.dir" value="C:/Program Files/Apache Software Foundation/Tomcat 5.5/webapps/cas/WEB-INF"/> <!--<property name="deployment.dir" value="C:/casself"/--> <target name="clean"> <echo message="開始清除歷史版本"/> <delete> <fileset dir="."> <include name="casself.jar"/> </fileset> <fileset dir="${deployment.dir}"> <include name="web.xml"/> <include name="mydeployerConfigContext.xml"/> <include name="log4j.properties"/> </fileset> </delete> </target> <target name="compile"> <echo message="開始編譯"/> <javac srcdir="." /> </target> <target name="jar" depends="compile"> <echo message="開始打包"/> <jar destfile="casself.jar" basedir="." includes="**/*.class" /> </target> <target name="copy"> <echo message="部署配置文件"/> <copy todir="${deployment.dir}"> <fileset dir="./xml"> <!--exclude name="**/doc/**"/--> </fileset> <fileset dir="."> <include name="log4j.properties"/> </fileset> </copy> <echo message="部署jar文件"/> <copy todir="${deployment.dir}/lib"> <fileset dir="."> <include name="casself.jar"/> </fileset> </copy> </target> <target name="release" depends="jar,copy"> <echo message="release success!~"/> </target> <target name="run" depends="jar"> <java classname="hello" classpath="hello.jar" fork="true" /> </target> </project> |