Single Sign On CAS Acegi Configuration
Overview:
taking the definition from Acegi Documentation
CAS is an enterprise-wide single sign on system. Unlike other initiatives, Central Authentication
Service is open source, widely used, simple to understand, platform
independent, and supports proxy capabilities. Acegi Security fully
supports CAS, and provides an easy migration path from
single-application deployments of Acegi Security through to
multiple-application deployments secured by an enterprise-wide CAS
server.
Configuration:
- Download acegi-security-1.0.1.zip
- Download cas-server-3.0.4.zip
- Download tomcat-5.5
Hint: Here I'm using Tomcat as server that will only host the cas web application, my service applications will be on oc4j.
First, install the CAS application.
as mentioned in Acegi documentation
CAS Version 3.0 Configuration
To install, you will need to download and extract the CAS
server archive. We used version 3.0.4. There will be a
/webapp directory in the root of the deployment.
Edit the an deployerConfigContext.xml so that it
contains your AuthenticationManager as well as
the CasAuthenticationHandler. A sample
applicationContext.xml is included below:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <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" /> </list> </property> <property name="authenticationHandlers"> <list> <!--bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" /> <bean class="org.acegisecurity.adapters.cas3.CasAuthenticationHandler"> <property name="authenticationManager" ref="acegiAuthenticationManager" /> </bean--> <bean id="SearchModeSearchDatabaseAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler" abstract="false" singleton="true" lazy-init="default" autowire="default" dependency-check="default"> <property name="tableUsers"> <value>SF_INF_USERS</value> </property> <property name="fieldUser"> <value>NAME</value> </property> <property name="fieldPassword"> <value>PSWD</value> </property> <property name="dataSource" ref="dataSource" /> </bean> </list> </property> </bean> <!--bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl"> <property name="userMap"> <value> aabdelaziz=aabdelaziz,EPS_SYSTEM_ADMIN marissa=koala,ROLES_IGNORED_BY_CAS dianne=emu,ROLES_IGNORED_BY_CAS scott=wombat,ROLES_IGNORED_BY_CAS peter=opal,disabled,ROLES_IGNORED_BY_CAS </value> </property> </bean> <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> <property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property> </bean> <bean id="acegiAuthenticationManager" class="org.acegisecurity.providers.ProviderManager"> <property name="providers"> <list> <ref bean="daoAuthenticationProvider"/> </list> </property> </bean--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>oracle.jdbc.driver.OracleDriver</value> </property> <property name="url"> <value>jdbc:oracle:thin:@10.1.119.76:1521:epsdb</value> </property> <property name="username"> <value>eps</value> </property> <property name="password"> <value>eps</value> </property> </bean> </beans>
Note the granted authorities are ignored by CAS because it has
no way of communicating the granted authorities to calling
applications. CAS is only concerned with username and passwords (and
the enabled/disabled status).
Copy acegi-security.jar and
acegi-security-cas.jar files into
/localPlugins/lib. Now use the ant task in the
warbuild.xml in the
/localPlugins directory. This will create
/localPlugins/target/cas.war, which is ready for
deployment to your servlet container.
Note CAS heavily relies on HTTPS. You can't even test the
system without an HTTPS certificate. Whilst you should refer to your
web container's documentation on setting up HTTPS, if you need some
additional help or a test certificate you might like to check the
CAS documentation on setting up SSL:
http://www.ja-sig.org/products/cas/server/ssl/index.html
Deploy the generate cas.war to $CATALINA_HOME/webapp/
Configuration of CAS Client
you can read and get more details about each bean from Acegi Documentation - Chapter 18. CAS Authentication
here I will just past my applicationContext-acegiSecurity.xml, web.xml as it may be useful for some one like me who suffered before making it works.
ÂapplicationContext-acegiSecurity.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- UserDetailsService is the most commonly frequently Acegi Security interface implemented by end users -->
<bean id="userDetailsService" class="ae.dxbpolice.eps.business.service.UserDetailsServiceImpl"/>
<!-- This bean is optional; it isn't used by any other bean as it only listens and logs -->
<bean id="loggerListener" class="org.acegisecurity.event.authentication.LoggerListener"/>
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,logoutFilter,casProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>
<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/>
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg value="/index.jsp"/><!-- URL redirected to after logout -->
<constructor-arg>
<list>
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>
<!-- Authorization in Acegi Security is performed mainly by the FilterSecurityInterceptor filter.
This filter identifies a user-role relationship for a URL.
-->
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager">
<!-- The AffirmativeBased voter allows access if at least one voter votes
to grant access. Use the UnanimousBased voter if you only want to
grant access if no voter votes to deny access. -->
<bean class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false"/>
<property name="decisionVoters">
<list>
<bean class="org.acegisecurity.vote.RoleVoter">
<!-- Reset the role prefix to "EPS_", default is ROLE_ -->
<property name="rolePrefix">
<value>EPS_</value>
</property>
</bean>
<!-- The authenticated voter grant access if e.g.
IS_AUTHENTICATED_FULLY is an attribute -->
<bean class="org.acegisecurity.vote.AuthenticatedVoter" />
</list>
</property>
</bean>
</property>
<!-- Start the Dinamic URL-ROLe Mapping -->
<property name="objectDefinitionSource">
<ref local="dbDrivenFilterInvocationDefinitionSource" />
</property>
</bean>
<bean id="dbDrivenFilterInvocationDefinitionSource"
class="ae.dxbpolice.eps.business.service.DatabaseDrivenFilterInvocationDefinitionSource">
<property name="securityService">
<ref bean="securityService" />
</property>
</bean>
<bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="userDetailsService"/>
<property name="key" value="changeThis"/>
</bean>
<!-- End Acegi Configuration for web -->
<!-- ===================== Start of CAS SECURITY CONFIGURATIOS ==================== -->
<bean id="serviceProperties" class="org.acegisecurity.ui.cas.ServiceProperties">
<property name="service"><value>http://localhost:8889/eps/j_acegi_cas_security_check</value></property>
<property name="sendRenew"><value>false</value></property>
</bean>
<bean id="casProcessingFilter" class="org.acegisecurity.ui.cas.CasProcessingFilter">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="authenticationFailureUrl"><value>/casfailed.jsp</value></property>
<property name="defaultTargetUrl"><value>/</value></property>
<property name="filterProcessesUrl"><value>/j_acegi_cas_security_check</value></property>
</bean>
<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint"><ref local="casProcessingFilterEntryPoint"/></property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/jsps/login/access-denied.jsf"/>
</bean>
</property>
</bean>
<bean id="casProcessingFilterEntryPoint" class="org.acegisecurity.ui.cas.CasProcessingFilterEntryPoint">
<property name="loginUrl"><value>https://localhost:8443/cas/login</value></property>
<property name="serviceProperties"><ref bean="serviceProperties"/></property>
</bean>
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="casAuthenticationProvider"/>
<bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
<property name="key" value="changeThis"/>
</bean>
<bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="changeThis"/>
</bean>
</list>
</property>
</bean>
<bean id="casAuthenticationProvider" class="org.acegisecurity.providers.cas.CasAuthenticationProvider">
<property name="casAuthoritiesPopulator"><ref bean="casAuthoritiesPopulator"/></property>
<property name="casProxyDecider"><ref bean="casProxyDecider"/></property>
<property name="ticketValidator"><ref bean="casProxyTicketValidator"/></property>
<property name="statelessTicketCache"><ref bean="statelessTicketCache"/></property>
<property name="key"><value>my_password_for_this_auth_provider_only</value></property>
</bean>
<bean id="casProxyTicketValidator" class="org.acegisecurity.providers.cas.ticketvalidator.CasProxyTicketValidator">
<property name="casValidate"><value>https://localhost:8443/cas/proxyValidate</value></property>
<!--property name="proxyCallbackUrl"><value>http://localhost:8888/eps//casProxy/receptor</value></property-->
<property name="serviceProperties"><ref bean="serviceProperties"/></property>
<property name="trustStore"><value>C:\ProgramFiles\Java\jdk1.5.0_06\jre\lib\security\cacerts</value></property>
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation">
<value>classpath:/ehcache-failsafe.xml</value>
</property>
</bean>
<bean id="ticketCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager"/>
</property>
<property name="cacheName">
<value>ticketCache</value>
</property>
</bean>
<bean id="statelessTicketCache" class="org.acegisecurity.providers.cas.cache.EhCacheBasedTicketCache">
<property name="cache"><ref local="ticketCacheBackend"/></property>
</bean>
<bean id="casAuthoritiesPopulator" class="org.acegisecurity.providers.cas.populator.DaoCasAuthoritiesPopulator">
<!--property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property-->
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
<bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
aabdelaziz=PASSWORD_NOT_USED,EPS_SYSTEM_ADMIN
marissa=PASSWORD_NOT_USED,ROLE_TELLER,ROLE_SUPERVISOR
dianne=PASSWORD_NOT_USED,ROLE_TELLER
scott=PASSWORD_NOT_USED,ROLE_TELLER
peter=PASSWORD_NOT_USED_AND_DISABLED_IGNORED,disabled,ROLE_TELLER
</value>
</property>
</bean>
<bean id="casProxyDecider" class="org.acegisecurity.providers.cas.proxy.RejectProxyTickets"/>
<!-- ===================== HTTP CHANNEL REQUIREMENTS ==================== -->
<!-- Enabled by default for CAS, as a CAS deployment uses HTTPS -->
<!--bean id="channelProcessingFilter" class="org.acegisecurity.securechannel.ChannelProcessingFilter">
<property name="channelDecisionManager"><ref local="channelDecisionManager"/></property>
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
\A/secure/.*\Z=REQUIRES_SECURE_CHANNEL
\A/j_acegi_cas_security_check.*\Z=REQUIRES_SECURE_CHANNEL
\A.*\Z=REQUIRES_INSECURE_CHANNEL
</value>
</property>
</bean>
<bean id="channelDecisionManager" class="org.acegisecurity.securechannel.ChannelDecisionManagerImpl">
<property name="channelProcessors">
<list>
<ref local="secureChannelProcessor"/>
<ref local="insecureChannelProcessor"/>
</list>
</property>
</bean>
<bean id="secureChannelProcessor" class="org.acegisecurity.securechannel.SecureChannelProcessor"/>
<bean id="insecureChannelProcessor" class="org.acegisecurity.securechannel.InsecureChannelProcessor"/-->
<!-- ====================== End of CAS SECURITY CONFIGURATIOS ===================== -->
</beans>
Â
Âweb.xml
<?xml version = '1.0' encoding = 'windows-1256'?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<description>Empty web.xml file for Web Application</description>
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/eps-faces-config.xml</param-value>
</context-param>
<!-- /WEB-INF/applicationContext.xml
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml,
classpath:applicationContext-localDataSource.xml,
classpath:applicationContext-acegiSecurity.xml
</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
<description>
State saving method: "client" or "server" (= default)
See JSF Specification 2.5.2
</description>
</context-param>
<context-param>
<param-name>org.apache.myfaces.ALLOW_JAVASCRIPT</param-name>
<param-value>true</param-value>
<description>
This parameter tells MyFaces if javascript code should be allowed in the
rendered HTML output.
If javascript is allowed, command_link anchors will have javascript code
that submits the corresponding form.
If javascript is not allowed, the state saving info and nested parameters
will be added as url parameters.
Default: "true"
</description>
</context-param>
<context-param>
<param-name>org.apache.myfaces.DETECT_JAVASCRIPT</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.PRETTY_HTML</param-name>
<param-value>true</param-value>
<description>
If true, rendered HTML code will be formatted, so that it is "human readable".
i.e. additional line separators and whitespace will be written, that do not
influence the HTML code.
Default: "true"
</description>
</context-param>
<context-param>
<param-name>org.apache.myfaces.AUTO_SCROLL</param-name>
<param-value>false</param-value>
<description>
If true, a javascript function will be rendered that is able to restore the
former vertical scroll on every request. Convenient feature if you have pages
with long lists and you do not want the browser page to always jump to the top
if you trigger a link or button action that stays on the same page.
Default: "false"
</description>
</context-param>
<filter>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>org.acegisecurity.util.FilterChainProxy</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup> 1 </load-on-startup>
</servlet>
<servlet>
<servlet-name>tiles</servlet-name>
<servlet-class>org.apache.struts.tiles.TilesServlet</servlet-class>
<init-param>
<param-name>definitions-config</param-name>
<param-value>/WEB-INF/tiles-defs.xml</param-value>
</init-param>
<init-param>
<param-name>definitions-parser-validate</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>35</session-timeout>
</session-config>
<mime-mapping>
<extension>html</extension>
<mime-type>text/html</mime-type>
</mime-mapping>
<mime-mapping>
<extension>txt</extension>
<mime-type>text/plain</mime-type>
</mime-mapping>
<taglib>
<taglib-uri>http://java.sun.com/jsf/html</taglib-uri>
<taglib-location>/WEB-INF/html_basic.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsf/core</taglib-uri>
<taglib-location>/WEB-INF/jsf_core.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://jakarta.apache.org/struts/tags-tiles</taglib-uri>
<taglib-location>/WEB-INF/struts-tiles.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://isoftfaces.ae/isoftpicklist</taglib-uri>
<taglib-location>/WEB-INF/picklist.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://isoft.ae/messagecomponent</taglib-uri>
<taglib-location>/WEB-INF/message.tld</taglib-location>
</taglib>
<!-- Start of Extension Filter Part -->
<!-- Extensions Filter -->
<filter>
<filter-name>extensionsFilter</filter-name>
<filter-class>org.apache.myfaces.component.html.util.ExtensionsFilter</filter-class>
<init-param>
<param-name>uploadMaxFileSize</param-name>
<param-value>100m</param-value>
<description>Set the size limit for uploaded files.
Format: 10 - 10 bytes
10k - 10 KB
10m - 10 MB
1g - 1 GB
</description>
</init-param>
<init-param>
<param-name>uploadThresholdSize</param-name>
<param-value>100k</param-value>
<description>Set the threshold size - files
below this limit are stored in memory, files above
this limit are stored on disk.
Format: 10 - 10 bytes
10k - 10 KB
10m - 10 MB
1g - 1 GB
</description>
</init-param>
</filter>
<filter-mapping>
<filter-name>extensionsFilter</filter-name>
<url-pattern>*.jsf</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>extensionsFilter</filter-name>
<url-pattern>/faces/*</url-pattern>
</filter-mapping>
<!-- End of Extension Filter Part -->
<!-- Start Welcome Files -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- End Welcome Files -->
</web-app>
attached contact-cas.war it can use it as sample to test the single sing on CAS. its configured with cas.
also I have attached the web.xml,acegi.xml files
thats all I hope it helps.
References:
http://forum.springframework.org/archive/index.php/t-12811.html
| Attachment | Size |
|---|---|
| contacts-cas.war | 2.11 MB |
| web.xml | 11.99 KB |
| cas.war | 7.85 MB |
| deployerConfigContext.xml | 2.72 KB |
| applicationContext.xml | 82.8 KB |
| applicationContext-acegiSecurity.xml | 10.14 KB |

Recent comments
10 weeks 4 days ago
10 weeks 6 days ago
10 weeks 6 days ago
22 weeks 1 day ago
26 weeks 3 days ago
27 weeks 4 days ago
47 weeks 2 days ago
47 weeks 2 days ago
51 weeks 1 day ago
1 year 10 weeks ago