耶鲁大学开发的CAS单点登录系统在SSO中应该说是比较有名的啦,既然也是开源的,我们为何不拿过来学习学习呢
很早之前的耶鲁的CAS开源包地址是在:http://www.yale.edu/tp/auth/
目前的CAS开源包都已经转移到新网址了,并且开源包里面的类名都没有以yelu开头了而是jasing
CAS客户端:http://downloads.jasig.org/cas-clients/
CAS服务器端:http://www.jasig.org/cas/download
我下载的都是目前最新版的cas-server-3.4.5服务器端和cas-client-3.2.0客户端
CAS服务器端基础应用
1)将cas-server-3.4.zip解压到一个目录,将cas-server-3.4.5\modules\cas-server-webapp-3.4.5.war拷贝到tomcat的webapp中去,并且改名为CasServer.war.启动tomcat
2)现在可以访问CAS应用了,当然要使用HTTPS加密协议访问,例如本问用到地址:https://javacrazyer.sso.com:8443/CasServer/login,现在打开了CAS服务器的页面输入admin/admin点击登录(CAS默认的验证规则只要用户名和密码相同就通过)

所以如果你看到下面的这张图片你就成功了

CAS服务器端深入应用,与数据库配置登录
首先打开tomcat/webapp/cas/WEB-INF/deployerConfigContext.xml文件,配置的地方如下:
1)找到第92行处,注释掉:SimpleTestUsernamePasswordAuthenticationHandler这个验证Handler,这个是比较简单的,只是判断用户名和密码相同即可通过,这个肯定不能在实际应用中使用,弃用!
2)注释掉92行后在下面添加下面的代码:
- <bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
- <property name="dataSource" ref="dataSource" />
- <property name="sql" value="select password from t_admin_user where login_name=?" />
- <property name="passwordEncoder" ref="MD5PasswordEncoder"/>
- </bean>
在文件的末尾结束之前加上如下
- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
- <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
- <property name="url"><value>jdbc:mysql:///wsriademo</value></property>
- <property name="username"><value>root</value></property>
- <property name="password"><value>root</value></property>
- </bean>
- <bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">
- <constructor-arg index="0">
- <value>MD5</value>
- </constructor-arg>
- </bean>
完整的deployerConfigContext.xml如下
- <?xml version="1.0" encoding="UTF-8"?>
- <!--
- | deployerConfigContext.xml centralizes into one file some of the declarative configuration that
- | all CAS deployers will need to modify.
- |
- | This file declares some of the Spring-managed JavaBeans that make up a CAS deployment.
- | The beans declared in this file are instantiated at context initialization time by the Spring
- | ContextLoaderListener declared in web.xml. It finds this file because this
- | file is among those declared in the context parameter "contextConfigLocation".
- |
- | By far the most common change you will need to make in this file is to change the last bean
- | declaration to replace the default SimpleTestUsernamePasswordAuthenticationHandler with
- | one implementing your approach for authenticating usernames and passwords.
- +-->
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:p="http://www.springframework.org/schema/p"
- xmlns:sec="http://www.springframework.org/schema/security"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
- <!--
- | 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"
- p:httpClient-ref="httpClient" />
- <!--
- | 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.
- +-->
- <!--<bean
- class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
- -->
- <bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
- <property name="dataSource" ref="dataSource" />
- <property name="sql" value="select password from t_admin_user where login_name=?" />
- <property name="passwordEncoder" ref="myPasswordEncoder"/>
- </bean>
- </list>
- </property>
- </bean>
- <!--
- This bean defines the security roles for the Services Management application. Simple deployments can use the in-memory version.
- More robust deployments will want to use another option, such as the Jdbc version.
- The name of this should remain "userDetailsService" in order for Spring Security to find it.
- -->
- <!-- <sec:user name="@@THIS SHOULD BE REPLACED@@" password="notused" authorities="ROLE_ADMIN" />-->
- <sec:user-service id="userDetailsService">
- <sec:user name="@@THIS SHOULD BE REPLACED@@" password="notused" authorities="ROLE_ADMIN" />
- </sec:user-service>
- <!--
- Bean that defines the attributes that a service may return. This example uses the Stub/Mock version. A real implementation
- may go against a database or LDAP server. The id should remain "attributeRepository" though.
- -->
- <bean id="attributeRepository"
- class="org.jasig.services.persondir.support.StubPersonAttributeDao">
- <property name="backingMap">
- <map>
- <entry key="uid" value="uid" />
- <entry key="eduPersonAffiliation" value="eduPersonAffiliation" />
- <entry key="groupMembership" value="groupMembership" />
- </map>
- </property>
- </bean>
- <!--
- Sample, in-memory data store for the ServiceRegistry. A real implementation
- would probably want to replace this with the JPA-backed ServiceRegistry DAO
- The name of this bean should remain "serviceRegistryDao".
- -->
- <bean
- id="serviceRegistryDao"
- class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl">
- <property name="registeredServices">
- <list>
- <bean class="org.jasig.cas.services.RegisteredServiceImpl">
- <property name="id" value="0" />
- <property name="name" value="HTTP" />
- <property name="description" value="Only Allows HTTP Urls" />
- <property name="serviceId" value="http://**" />
- </bean>
- <bean class="org.jasig.cas.services.RegisteredServiceImpl">
- <property name="id" value="1" />
- <property name="name" value="HTTPS" />
- <property name="description" value="Only Allows HTTPS Urls" />
- <property name="serviceId" value="https://**" />
- </bean>
- <bean class="org.jasig.cas.services.RegisteredServiceImpl">
- <property name="id" value="2" />
- <property name="name" value="IMAPS" />
- <property name="description" value="Only Allows HTTPS Urls" />
- <property name="serviceId" value="imaps://**" />
- </bean>
- <bean class="org.jasig.cas.services.RegisteredServiceImpl">
- <property name="id" value="3" />
- <property name="name" value="IMAP" />
- <property name="description" value="Only Allows IMAP Urls" />
- <property name="serviceId" value="imap://**" />
- </bean>
- </list>
- </property>
- </bean>
- <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource">
- <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
- <property name="url"><value>jdbc:mysql:///javacrazyer</value></property>
- <property name="username"><value>root</value></property>
- <property name="password"><value>root</value></property>
- </bean>
- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
- <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
- <property name="url"><value>jdbc:mysql:///javacrazyer</value></property>
- <property name="username"><value>root</value></property>
- <property name="password"><value>root</value></property>
- </bean>
- <bean id="myPasswordEncoder" class="org.jasig.cas.authentication.handler.MyPasswordEncoder"/>
- <bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">
- <constructor-arg index="0">
- <value>MD5</value>
- </constructor-arg>
- </bean>
- </beans>
2.1)dataSource,就是使用JDBC查询时的数据源
这里呢关于dataSource的配置可以采用多种方式,正如我的配置文件中采用了spring支持的dataSource(这里需要添加cas-server-3.4.5\modules\cas-server-support-jdbc-3.4.5.jar),也采用了dbcp的方式(这里需要添加commons-dbcp.jar和commons-pool.jar),当然少不了添加MySQL驱动包了,当然我们可以配置N多种数据源在这里,真用到的其实只会有一个, <property name="dataSource" ref="dataSource" />这句话可以引用你想要的数据源。
这里关于数据源配置可以参考我早前写的关于spring数据源配置方式的文章
2.2)passwordEncoder:处理密码加密
细心的朋友从最后面的代码可以看到MD5加密的类有两个实MD5PasswordEncoder就是默认我们只需把摸认类添
加上无需写其他继承类,而如果你非要继承的话,那么就写你自己的类继承自PasswordEncoder,具体可以更改encode方法
我这里就选择使用了继承的方式,我写的类如下
- package org.jasig.cas.authentication.handler;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- public final class MyPasswordEncoder implements PasswordEncoder {
- public MyPasswordEncoder() {
- };
- public String encode(String password) {
- if (password == null || password.length() == 0) {
- throw new IllegalArgumentException(
- "String to encript cannot be null or zero length");
- }
- StringBuffer hexString = new StringBuffer();
- try {
- MessageDigest md = MessageDigest.getInstance("MD5");
- md.update(password.getBytes());
- byte[] hash = md.digest();
- for (int i = 0; i < hash.length; i++) {
- if ((0xff & hash[i]) < 0x10) {
- hexString.append("0"
- + Integer.toHexString((0xFF & hash[i])));
- } else {
- hexString.append(Integer.toHexString(0xFF & hash[i]));
- }
- }
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- return hexString.toString();
- }
- }
当然你也可以选择不继承,采用默认的,都由 <property name="passwordEncoder" ref="MD5PasswordEncoder"/>来决定选择哪个加密方式。
2.3)QueryDatabaseAuthenticationHandler是cas-server-support-jdbc提供的查询接口其中一个,QueryDatabaseAuthenticationHandler是通过配置一个 SQL 语句查出密码,与所给密码匹配
2.4)sql:登录查询哪一张表
这里大家或许还有一句话可以看到<property name="sql" value="select password from t_admin_user where login_name=?" />
所以需要用到数据库脚本,数据库名称我这里起名为javacrazyer
- /*
- Navicat MySQL Data Transfer
- Source Host : localhost:3306
- Source Database : javacrazyer
- Target Host : localhost:3306
- Target Database : javacrazyer
- Date: 2011-01-21 15:19:40
- */
- SET FOREIGN_KEY_CHECKS=0;
- -- ----------------------------
- -- Table structure for area_info
- -- ----------------------------
- DROP TABLE IF EXISTS `area_info`;
- CREATE TABLE `area_info` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '地区ID',
- `area_code` varchar(32) NOT NULL COMMENT '地区编码',
- `area_name` varchar(60) NOT NULL COMMENT '地区名称',
- `parent_area_id` bigint(20) NOT NULL COMMENT '上级ID',
- `area_number` char(6) DEFAULT NULL,
- `country_code` varchar(32) DEFAULT NULL,
- `area_level` int(11) NOT NULL,
- `enabled` bit(1) NOT NULL,
- `sort` int(11) DEFAULT NULL,
- `remark` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `bmc_bd_uqareainfo` (`area_code`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- -- ----------------------------
- -- Records of area_info
- -- ----------------------------
- -- ----------------------------
- -- Table structure for city
- -- ----------------------------
- DROP TABLE IF EXISTS `city`;
- CREATE TABLE `city` (
- `ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '城市ID',
- `CITY_NAME` varchar(20) NOT NULL COMMENT '城市名称',
- `SUPER_ID` bigint(20) NOT NULL COMMENT '上级城市(没有为-1)',
- `REMARK` varchar(255) DEFAULT NULL COMMENT '城市备注',
- PRIMARY KEY (`ID`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='城市';
- -- ----------------------------
- -- Records of city
- -- ----------------------------
- -- ----------------------------
- -- Table structure for t_admin_user
- -- ----------------------------
- DROP TABLE IF EXISTS `t_admin_user`;
- CREATE TABLE `t_admin_user` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `password` varchar(255) DEFAULT NULL,
- `email` varchar(255) DEFAULT NULL,
- `name` varchar(255) DEFAULT NULL,
- `login_name` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
- -- ----------------------------
- -- Records of t_admin_user
- -- ----------------------------
- INSERT INTO `t_admin_user` VALUES ('1', '88f6f4ddbd7160aa6a547589af036ee0', null, null, 'cheneywu');
- INSERT INTO `t_admin_user` VALUES ('2', '098f6bcd4621d373cade4e832627b4f6', null, null, 'test');
到这里你就认为完事了?看到我脚本中的密码的值是MD5加密过的,为什么加密?2.2中已经介绍过了,所以对于用户名/密码为:test/test的账户来说,在数据库中就应该为test/8f6bcd4621d373cade4e832627b4f6.这个密码值是怎么得到的,sql语言
中可以进行操作:select md5("test")
给力上图

这时你再去访问地址:https://javacrazyer.sso.com:8443/CasServer/login,输入数据库中存在的相同值的用户名密码,就能成功登陆了
关于CAS客户端SSO登录下一篇文章将会介绍
本文介绍如何利用耶鲁大学开发的 CAS 单点登录系统实现服务器端 SSO 功能,包括部署 CAS 服务器、配置数据库登录及密码加密等步骤。

1571

被折叠的 条评论
为什么被折叠?



