Spring Security 3 与 CAS单点登录配置-Server

转载:http://www.hxdw.com/bbs/post/view?bid=60&id=144184&sty=3&keywords=Spring+Security+3

一、环境说明: 

Tomcat6.0.20

JDK1.6.x

Spring3.0.0.RELEASE

SpringSecurity3.0.0.RELEASE

CAScas-server-3.4.2

cas-client-3.1.10

下载地址:http://www.jasig.org/cas/download

配置环境变量

JAVA_HOME:C:\Java\jdk1.6.0_11

CATALINA_HOME:C:\Tomcat6.0

Path:C:\Java\jdk1.6.0_11\bin;

二、开发步骤

1.制作SSL证书

2.配置CASServer

3.配置CASClient

4.安全框架合并

5.简单测试

三、开始

证书制作,请参考

http://linliangyi2007.javaeye.com/blog/165304

说明

*附件是制作证书的批处理程序,可以按照提示完成证书制作。

*局域网用户,不要使用localhost做这个域名,因为你的证书设置了localhost,其他客户端要从你的域名下证书,而localhost又是客户端的域(可以查看%SystemRoot%\system32\drivers\etc\hosts)

所以CAS服务器,修改%SystemRoot%\system32\drivers\etc\hosts文件

增加:127.0.0.1cas.com

Java代码

127.0.0.1localhost

127.0.0.1cas.boc.com

127.0.0.1localhost

127.0.0.1cas.boc.com

而CAS客户端,也修改hosts文件,但要域要对应服务器端的IP

Java代码

127.0.0.1localhost

192.168.0.2cas.boc.com

127.0.0.1localhost

192.168.0.2cas.boc.com

配置Tomcat的Server.xml文件

Xml代码

<Connectorprotocol="org.apache.coyote.http11.Http11Protocol"

port="8443"minSpareThreads="5"maxSpareThreads="75"

enableLookups="true"disableUploadTimeout="true"

acceptCount="100"maxThreads="200"scheme="https"secure="true"SSLEnabled="true"

keystoreFile="%USERPROFILE%/.keystore"

keystorePass="changeit"clientAuth="false"

sslProtocol="TLS"/>

<Connectorprotocol="org.apache.coyote.http11.Http11Protocol"

port="8443"minSpareThreads="5"maxSpareThreads="75"

enableLookups="true"disableUploadTimeout="true"

acceptCount="100"maxThreads="200"scheme="https"secure="true"SSLEnabled="true"

keystoreFile="%USERPROFILE%/.keystore"

keystorePass="changeit"clientAuth="false"

sslProtocol="TLS"/>

开始配置CASServer

解压缩cas-server-3.4.2-release.zip文件

eclipse导入modules文件夹内的cas-server-webapp-3.4.2.war

并改名为casServer

导入后需要配置casServer工程的JavaBuildPath

这时运行会报一个错误,找不到AutowiringSchedulerFactoryBean类

AutowiringSchedulerFactoryBean类是一个Quartz的一个调度程序,定时监控CASServer状态

删除WEB-INF/spring-configuration/applicationContext.xml中的配置

或者

AutowiringSchedulerFactoryBean添加到org.jasig.cas.util包下

(AutowiringSchedulerFactoryBean类在最后附件中可以下载)

如果你对CAS单点登录的工作不是很熟悉,请查看

打开/WEB-INF/deployerConfigContext.xml

Xml代码

<beanid="authenticationManager"

class="org.jasig.cas.authentication.AuthenticationManagerImpl">

<!--

|ThisistheListofCredentialToPrincipalResolversthatidentifywhatPrincipalistryingtoauthenticate.

|TheAuthenticationManagerImplconsiderstheminorder,findingaCredentialToPrincipalResolverwhich

|supportsthepresentedcredentials.

|

|AuthenticationManagerImplusestheseresolversfortwopurposes.First,itusesthemtoidentifythePrincipal

|attemptingtoauthenticatetoCAS/login.Inthedefaultconfiguration,itistheDefaultCredentialsToPrincipalResolver

|thatfillsthisrole.IfyouareusingsomeotherkindofcredentialsthanUsernamePasswordCredentials,youwillneedtoreplace

|DefaultCredentialsToPrincipalResolverwithaCredentialsToPrincipalResolverthatsupportsthecredentialsyouare

|using.

|

|Second,AuthenticationManagerImplusestheseresolverstoidentifyaservicerequestingaproxygrantingticket.

|Inthedefaultconfiguration,itistheHttpBasedServiceCredentialsToPrincipalResolverthatservesthispurpose.

|YouwillneedtochangethislistifyouareidentifyingservicesbysomethingmoreorotherthantheircallbackURL.

+-->

<propertyname="credentialsToPrincipalResolvers">

<list>

<!--

|UsernamePasswordCredentialsToPrincipalResolversupportstheUsernamePasswordCredentialsthatweusefor/login

|bydefaultandproducesSimplePrincipalinstancesconveyingtheusernamefromthecredentials.

|

|Ifyou'vechangedyourLoginFormActiontousecredentialsotherthanUsernamePasswordCredentialsthenyouwillalso

|needtochangethisbeandeclaration(oraddadditionaldeclarations)todeclareaCredentialsToPrincipalResolverthatsupportsthe

|Credentialsyouareusing.

+-->

<bean

class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver"/>

<!--

|HttpBasedServiceCredentialsToPrincipalResolversupportsHttpBasedCredentials.ItsupportstheCAS2.0approachof

|authenticatingservicesbySSLcallback,extractingthecallbackURLfromtheCredentialsandrepresentingitasa

|SimpleServiceidentifiedbythatcallbackURL.

|

|IfyouarerepresentingservicesbysomethingmoreorotherthananHTTPSURLwhereattheyareableto

|receiveaproxycallback,youwillneedtochangethisbeandeclaration(oraddadditionaldeclarations).

+-->

<bean

class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver"/>

</list>

</property>

<!--

|WhereasCredentialsToPrincipalResolversidentifywhoitissomeCredentialsmightauthenticate,

|AuthenticationHandlersactuallyauthenticatecredentials.HerewedeclaretheAuthenticationHandlersthat

|authenticatethePrincipalsthattheCredentialsToPrincipalResolversidentified.CASwilltrythesehandlersinturn

|untilitfindsonethatbothsupportstheCredentialspresentedandsucceedsinauthenticating.

+-->

<propertyname="authenticationHandlers">

<list>

<!--

|ThisistheauthenticationhandlerthatauthenticatesservicesbymeansofcallbackviaSSL,therebyvalidating

|aserversideSSLcertificate.

+-->

<beanclass="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"

p:httpClient-ref="httpClient"/>

<!--

|ThisistheauthenticationhandlerdeclarationthateveryCASdeployerwillneedtochangebeforedeployingCAS

|intoproduction.ThedefaultSimpleTestUsernamePasswordAuthenticationHandlerauthenticatesUsernamePasswordCredentials

|wheretheusernameequalsthepassword.YouwillneedtoreplacethiswithanAuthenticationHandlerthatimplementsyour

|localauthenticationstrategy.Youmightaccomplishthisbycodinganewsuchhandleranddeclaring

|edu.someschool.its.cas.MySpecialHandlerhere,oryoumightuseoneofthehandlersprovidedintheadaptorsmodules.

+-->

<!--<bean

class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler"/>

<beanclass="com.cas.service.CasUsernamePasswordAuthenticationHandler">

<propertyname="userDao"ref="userDao"/>

</bean>-->

<refbean="casAuthenticationHandler"/>

</list>

</property>

</bean>

<beanid="authenticationManager"

class="org.jasig.cas.authentication.AuthenticationManagerImpl">

<!--

|ThisistheListofCredentialToPrincipalResolversthatidentifywhatPrincipalistryingtoauthenticate.

|TheAuthenticationManagerImplconsiderstheminorder,findingaCredentialToPrincipalResolverwhich

|supportsthepresentedcredentials.

|

|AuthenticationManagerImplusestheseresolversfortwopurposes.First,itusesthemtoidentifythePrincipal

|attemptingtoauthenticatetoCAS/login.Inthedefaultconfiguration,itistheDefaultCredentialsToPrincipalResolver

|thatfillsthisrole.IfyouareusingsomeotherkindofcredentialsthanUsernamePasswordCredentials,youwillneedtoreplace

|DefaultCredentialsToPrincipalResolverwithaCredentialsToPrincipalResolverthatsupportsthecredentialsyouare

|using.

|

|Second,AuthenticationManagerImplusestheseresolverstoidentifyaservicerequestingaproxygrantingticket.

|Inthedefaultconfiguration,itistheHttpBasedServiceCredentialsToPrincipalResolverthatservesthispurpose.

|YouwillneedtochangethislistifyouareidentifyingservicesbysomethingmoreorotherthantheircallbackURL.

+-->

<propertyname="credentialsToPrincipalResolvers">

<list>

<!--

|UsernamePasswordCredentialsToPrincipalResolversupportstheUsernamePasswordCredentialsthatweusefor/login

|bydefaultandproducesSimplePrincipalinstancesconveyingtheusernamefromthecredentials.

|

|Ifyou'vechangedyourLoginFormActiontousecredentialsotherthanUsernamePasswordCredentialsthenyouwillalso

|needtochangethisbeandeclaration(oraddadditionaldeclarations)todeclareaCredentialsToPrincipalResolverthatsupportsthe

|Credentialsyouareusing.

+-->

<bean

class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver"/>

<!--

|HttpBasedServiceCredentialsToPrincipalResolversupportsHttpBasedCredentials.ItsupportstheCAS2.0approachof

|authenticatingservicesbySSLcallback,extractingthecallbackURLfromtheCredentialsandrepresentingitasa

|SimpleServiceidentifiedbythatcallbackURL.

|

|IfyouarerepresentingservicesbysomethingmoreorotherthananHTTPSURLwhereattheyareableto

|receiveaproxycallback,youwillneedtochangethisbeandeclaration(oraddadditionaldeclarations).

+-->

<bean

class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver"/>

</list>

</property>

<!--

|WhereasCredentialsToPrincipalResolversidentifywhoitissomeCredentialsmightauthenticate,

|AuthenticationHandlersactuallyauthenticatecredentials.HerewedeclaretheAuthenticationHandlersthat

|authenticatethePrincipalsthattheCredentialsToPrincipalResolversidentified.CASwilltrythesehandlersinturn

|untilitfindsonethatbothsupportstheCredentialspresentedandsucceedsinauthenticating.

+-->

<propertyname="authenticationHandlers">

<list>

<!--

|ThisistheauthenticationhandlerthatauthenticatesservicesbymeansofcallbackviaSSL,therebyvalidating

|aserversideSSLcertificate.

+-->

<beanclass="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"

p:httpClient-ref="httpClient"/>

<!--

|ThisistheauthenticationhandlerdeclarationthateveryCASdeployerwillneedtochangebeforedeployingCAS

|intoproduction.ThedefaultSimpleTestUsernamePasswordAuthenticationHandlerauthenticatesUsernamePasswordCredentials

|wheretheusernameequalsthepassword.YouwillneedtoreplacethiswithanAuthenticationHandlerthatimplementsyour

|localauthenticationstrategy.Youmightaccomplishthisbycodinganewsuchhandleranddeclaring

|edu.someschool.its.cas.MySpecialHandlerhere,oryoumightuseoneofthehandlersprovidedintheadaptorsmodules.

+-->

<!--<bean

class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler"/>

<beanclass="com.cas.service.CasUsernamePasswordAuthenticationHandler">

<propertyname="userDao"ref="userDao"/>

</bean>-->

<refbean="casAuthenticationHandler"/>

</list>

</property>

</bean>

其中authenticationHandlers属性是个关键,它为CAS服务器提供用户认证的依据

(它只负责用户的认证,不负责受权服务。也就是说,CAS服务器不关心用户角色)

应该注意的是,authenticationHandlers属性的值是实现了AuthenticationHandler接口类的List,多个应用提供用户账号和密码的数据源,CAS验证时,会在这个List的验证接口中逐一遍历。

可能会有疑问,当有两个应用A和B,分别有账号abc/123和abc/abc

当B系统登陆时,使用了A的账户和密码(即同账户不同密码问题),这时,CAS将提供一个有效验证,返回给B应用。这不会乱套?

其实,当你配置了Client端时,这个问题就能被解释了,其实,CAS为Client提供一个ticket后,Client需要用登陆的账号和密码再验证一次,并且取得用户的角色信息。如果没有权限,则提示401,账号被锁定

言归正传,这里的casAuthenticationHandler是一个类实现authenticationHandlers接口的类,但你可以继承一个抽象类AbstractUsernamePasswordAuthenticationHandler去实现。

因为我的cas使用了iBatis.所以直接注入UserDao进行登录有效性验证

Java代码

packagecom.cas.service;

importorg.jasig.cas.authentication.handler.AuthenticationException;

importorg.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;

importorg.jasig.cas.authentication.principal.UsernamePasswordCredentials;

importcom.cas.dao.UserDao;

importcom.cas.model.User;

publicclassCasUsernamePasswordAuthenticationHandlerextendsAbstractUsernamePasswordAuthenticationHandler{

/**

*用户信息操作层

*/

privateUserDaouserDao;

@Override

protectedbooleanauthenticateUsernamePasswordInternal(

UsernamePasswordCredentialscredentials)

throwsAuthenticationException{

Useruser=userDao.findUserByName(credentials.getUsername());

if(user==null){returnfalse;}

if(user.getPassword().equals(credentials.getPassword())){

returntrue;

}

returnfalse;

}

publicvoidsetUserDao(UserDaouserDao){

this.userDao=userDao;

}

}

packagecom.cas.service;

importorg.jasig.cas.authentication.handler.AuthenticationException;

importorg.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;

importorg.jasig.cas.authentication.principal.UsernamePasswordCredentials;

importcom.cas.dao.UserDao;

importcom.cas.model.User;

publicclassCasUsernamePasswordAuthenticationHandlerextendsAbstractUsernamePasswordAuthenticationHandler{

/**

*用户信息操作层

*/

privateUserDaouserDao;

@Override

protectedbooleanauthenticateUsernamePasswordInternal(

UsernamePasswordCredentialscredentials)

throwsAuthenticationException{

Useruser=userDao.findUserByName(credentials.getUsername());

if(user==null){returnfalse;}

if(user.getPassword().equals(credentials.getPassword())){

returntrue;

}

returnfalse;

}

publicvoidsetUserDao(UserDaouserDao){

this.userDao=userDao;

}

}

接下来修改deployerConfigContext.xml文件的

Xml代码

<sec:user-serviceid="userDetailsService">

<sec:username="user01"password="user01"authorities="ROLE_USER"/>

<sec:username="admin"password="admin"authorities="ROLE_ADMIN"/>

<sec:username="@@THISSHOULDBEREPLACED@@"password="notused"authorities="ROLE_ADMIN"/>

</sec:user-service>

<sec:user-serviceid="userDetailsService">

<sec:username="user01"password="user01"authorities="ROLE_USER"/>

<sec:username="admin"password="admin"authorities="ROLE_ADMIN"/>

<sec:username="@@THISSHOULDBEREPLACED@@"password="notused"authorities="ROLE_ADMIN"/>

</sec:user-service>

这是登录cas管理页面的账号密码(这是一个简单的配置,也可以实现UserDetailsService接口,进行配置。这跟SpringSecurity的用户登录验证接口其实是一个)

配置cas.properties文件

Xml代码

#cas.securityContext.serviceProperties.service=http://localhost:8080/casServer/services/j_acegi_cas_security_check

cas.securityContext.serviceProperties.service=http://cas.boc.com:8080/casServer/services/j_acegi_cas_security_check

#NamesofrolesallowedtoaccesstheCASservicemanager

cas.securityContext.serviceProperties.adminRoles=ROLE_ADMIN

cas.securityContext.casProcessingFilterEntryPoint.loginUrl=http://cas.boc.com:8080/casServer/login

cas.securityContext.ticketValidator.casServerUrlPrefix=http://cas.boc.com:8080/casServer

cas.themeResolver.defaultThemeName=default

cas.viewResolver.basename=default_views

host.name=casServer

#database.hibernate.dialect=org.hibernate.dialect.OracleDialect

#database.hibernate.dialect=org.hibernate.dialect.MySQLDialect

database.hibernate.dialect=org.hibernate.dialect.HSQLDialect

#cas.securityContext.serviceProperties.service=http://localhost:8080/casServer/services/j_acegi_cas_security_check

cas.securityContext.serviceProperties.service=http://cas.boc.com:8080/casServer/services/j_acegi_cas_security_check

#NamesofrolesallowedtoaccesstheCASservicemanager

cas.securityContext.serviceProperties.adminRoles=ROLE_ADMIN

cas.securityContext.casProcessingFilterEntryPoint.loginUrl=http://cas.boc.com:8080/casServer/login

cas.securityContext.ticketValidator.casServerUrlPrefix=http://cas.boc.com:8080/casServer

cas.themeResolver.defaultThemeName=default

cas.viewResolver.basename=default_views

host.name=casServer

#database.hibernate.dialect=org.hibernate.dialect.OracleDialect

#database.hibernate.dialect=org.hibernate.dialect.MySQLDialect

database.hibernate.dialect=org.hibernate.dialect.HSQLDialect

启动CasServer

如果一切正常,能看到服务启动

因为配置了

Xml代码

<beanid="scheduler"class="org.jasig.cas.util.AutowiringSchedulerFactoryBean"/>

<beanid="scheduler"class="org.jasig.cas.util.AutowiringSchedulerFactoryBean"/>

每隔一段时间,控制台将有当前服务信息提示。

到目前为止,CAS服务器的雏形配置完成。这是一个基本的配置,我们查看cas-servlet.xml

文件

Xml代码

<bean

id="handlerMappingC"

class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property

name="mappings">

<props>

<prop

key="/logout">

logoutController

</prop>

<prop

key="/serviceValidate">

serviceValidateController

</prop>

<prop

key="/validate">

legacyValidateController

</prop>

<prop

key="/proxy">

proxyController

</prop>

<prop

key="/proxyValidate">

proxyValidateController

</prop>

<prop

key="/samlValidate">

samlValidateController

</prop>

<prop

key="/services/add.html">

addRegisteredServiceSimpleFormController

</prop>

<prop

key="/services/edit.html">

editRegisteredServiceSimpleFormController

</prop>

<prop

key="/services/loggedOut.html">

serviceLogoutViewController

</prop>

<propkey="/services/viewStatistics.html">

viewStatisticsController

</prop>

<prop

key="/services/*">

manageRegisteredServicesMultiActionController

</prop>

<prop

key="/openid/*">openIdProviderController</prop>

<prop

key="/authorizationFailure.html">passThroughController</prop>

</props>

</property>

<property

name="alwaysUseFullPath"value="true"/>

<!--

uncommentthistoenablesendingPageRequestevents.

<property

name="interceptors">

<list>

<refbean="pageRequestHandlerInterceptorAdapter"/>

</list>

</property>

-->

</bean>

<bean

id="handlerMappingC"

class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property

name="mappings">

<props>

<prop

key="/logout">

logoutController

</prop>

<prop

key="/serviceValidate">

serviceValidateController

</prop>

<prop

key="/validate">

legacyValidateController

</prop>

<prop

key="/proxy">

proxyController

</prop>

<prop

key="/proxyValidate">

proxyValidateController

</prop>

<prop

key="/samlValidate">

samlValidateController

</prop>

<prop

key="/services/add.html">

addRegisteredServiceSimpleFormController

</prop>

<prop

key="/services/edit.html">

editRegisteredServiceSimpleFormController

</prop>

<prop

key="/services/loggedOut.html">

serviceLogoutViewController

</prop>

<propkey="/services/viewStatistics.html">

viewStatisticsController

</prop>

<prop

key="/services/*">

manageRegisteredServicesMultiActionController

</prop>

<prop

key="/openid/*">openIdProviderController</prop>

<prop

key="/authorizationFailure.html">passThroughController</prop>

</props>

</property>

<property

name="alwaysUseFullPath"value="true"/>

<!--

uncommentthistoenablesendingPageRequestevents.

<property

name="interceptors">

<list>

<refbean="pageRequestHandlerInterceptorAdapter"/>

</list>

</property>

-->

</bean>

这里有很多映射关系,我们关注/services/viewStatistics.html这个地址

在浏览器中打开(系统会先提示你登陆,如果你跟我的配置一样,那么admin/admin即可登陆)

里面红色提示内容大体是说

因为你没有配置提供的服务,所以CAS处于开放模式,一旦你配置了一个服务,CAS将不再是开放模式,任何应用希望提供CAS,则必须注册。如果你要用这个工具,第一件事是需要将自己加入到这个工具中,默认服务管理工具的URL为"http://cas.boc.com:8080/casServer/services/j_acegi_cas_security_check"

这里我们先不要去管它,因为要做的工作还有很多,这里只不过是刚刚开始。

下一步对Client端进行配置

相关推荐