Authentication Failed: The user's credentials have expired. CAS v4.2 - java

I have a problem that I do not know how to solve.
I have the CAS v4.2 configured on a tomcat 8 port 8443.
The spring-security configuration that I have, it does the redirection to the cas correctly, when I authenticate in the cas, in the logs it is clear that the authentication and the ticket generation have been correct.
I have configured so that the ticket has a duration of 2 weeks as indicated in the documentation. I have increased the cas session from 5 to 15 in the web.xml as they indicate in the possible errors that is pressed, but all this has resulted in the same.
After authenticating myself, I did not redirect myself to the home of the client application but it displays a message "Authentication Failed: The user's credentials have expired"
I do not know what I may be doing wrong or what may be missing by configuring in cas.properties properties according to version 4.2.
I would be grateful if you could tell me what this problem could be in order to continue.
Thanks in advance.
JDK8.
Spring 4.2.6.
CAS v4.2.
Tomcat8.
Spring-security.xml
<security:http entry-point-ref="casEntryPoint" auto-config="true" use-expressions="true">
<security:csrf disabled="false"/>
<security:custom-filter position="FIRST" ref="ajaxSessionFilter"/>
<!-- ACCESO SIN RESTRICCIONES -->
<security:intercept-url pattern="/static/**" access="permitAll"/>
<security:intercept-url pattern="/WEB-INF/views/**" access="permitAll"/>
<security:custom-filter ref="casAuthenticationFilter" after="CAS_FILTER"/>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>
<bean id="casServiceProperties" class="org.springframework.security.cas.ServiceProperties"
p:service="http://localhost:8080/aap/j_spring_cas_security_check"
p:sendRenew="false" p:authenticateAllArtifacts="true" />
<bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"
p:serviceProperties-ref="casServiceProperties" p:loginUrl="https://cas:8443/cas/login" />
<bean id="ajaxSessionFilter" class="com.xxxx.auth.web.filters.ajax.SessionFilter">
<property name="homePage" value="https://cas:8443/cas/login"/>
</bean>
<bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="serviceProperties" ref="casServiceProperties"/>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/casfailed"/>
</bean>
</property>
<!-- -->
<property name="authenticationSuccessHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/"/>
</bean>
</property>
<property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
</bean>
<bean id="proxyGrantingTicketStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl" />
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>
<!-- This filter redirects to the CAS Server to signal Single Logout should be performed -->
<bean id="requestSingleLogoutFilter"
class="org.springframework.security.web.authentication.logout.LogoutFilter"
p:filterProcessesUrl="/j_spring_cas_security_logout">
<constructor-arg value="https://cas:8443/cas/logout" />
<constructor-arg >
<bean
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
</constructor-arg>
</bean>
<!-- This filter handles a Single Logout Request from the CAS Server -->
<bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider"/>
</security:authentication-manager>
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="authenticationUserDetailsService">
<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<constructor-arg ref="userDetailService" />
</bean>
</property>
<property name="serviceProperties" ref="casServiceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://cas:8443/cas" />
<property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
</bean>
</property>
<property name="key" value="CAS"/>
</bean>
<bean id="userDetailService" class="com.xxx.services.security.userdetails.PSOUserDetailsService"/>
cas.properties
# Decides whether SSO cookie should be created only under secure connections.
tgc.secure=true
# The expiration value of the SSO cookie
tgc.maxAge=1209600
# The name of the SSO cookie
tgc.name=TGC
# The path to which the SSO cookie will be scoped
tgc.path=/cas
# The expiration value of the SSO cookie for long-term authentications
tgc.remember.me.maxAge=1209600
# Decides whether SSO Warning cookie should be created only under secure connections.
warn.cookie.secure=true
# The expiration value of the SSO Warning cookie
warn.cookie.maxAge=1209600
# The name of the SSO Warning cookie
warn.cookie.name=CASPRIVACY
# The path to which the SSO Warning cookie will be scoped
warn.cookie.path=/cas
##
# Single Sign-On Session TGT Timeouts
#
# Inactivity Timeout Policy
tgt.timeout.maxTimeToLiveInSeconds=1209600
# Default Expiration Policy
tgt.maxTimeToLiveInSeconds=28800
tgt.timeToKillInSeconds=7200
##
# Service Ticket Timeout
#
st.timeToKillInSeconds=28800
st.numberOfUses=1
tgc.remember.me.maxAge=1209600
Cookie
"CASPRIVACY="";
Expires=Thu, 01-Jan-1970 00:00:10 GMT;
Path=/cas;
SecureTGC=eyJhbGciOiJIUzUxMiJ9.WlhsS2FHSkhZMmxQYVVwcllWaEphVXhEU214aWJVMXBUMmxLUWsxVVNUUlJNRXBFVEZWb1ZFMXFWVEpKYmpBdUxqRnNSVEl5T1U5SFdsQTRVWFpUTFc5VWIzRmpNRUV1T0Vac2J6QnRaMjl5ZVRWRk9XRnFNR3AwVFZKcFNIQklTVGt5YjJGelNWZE9XR0pEU2swM2VrMUJRekJYVUVjd1UwSnRaRGRaTTFwVlJHNVROekpNTjA5aWNsZGtjMEo2TkVGVVZYQkJWMGxPVEhKQkxWSmxVWEozZUdWRlpFaGxOV2xEYkhZdFgxUnRWbXBYY0hJeFZEWlpXQzFRVG1kcFdtNUJRa2RuTW5CdlRHOUxaRzB3VFMxQk56ZFNWelZ4YVdORVQxQXRVekEzTVVVNGNFSmxWVFJ2UkZwZmVFTTNWRzVFVlRWRmMyeFJRVXR3Y2tOMFlXMVhTVVJGT0ZoQ00xQlNaV0pMVTJGcVJrMVdPV1ZEVmxkU1ozaEtkeTVQYTJwSFEzTmhWRmxRVkdwSE0xZG5UVnBVZUVKQg.H2P1nCulIj3BtS-wOJr3PtOVGi1hT6y0PDP0MVSQerwv3khVB-lFQe2BdKNElUYzJhURtW-zwyZK3PuBh6p_eQ;
Expires=Wed, 18-Jan-2017 15:00:18 GMT;
Path=/cas;
Secure"

I respond to myself, and in case someone happens to be the same.
The problem lies in the PSOUserDetails, which had not overwritten the method for either the credentials did not expire.
Thanks

Related

Support Basic Authentication + LDAP and Pre-Authenticated at the same time

I have a security app context which works fine with Pre-authentication.
I would want to know if it is possible to have both Basic Authentication (With LDAP Bind as authentication manager) and Pre-authentication effective at the same time:
If container provides principal name, we will rely on it (and go to LDAP to get user details), and if pre-authentication of container does not happen (e.g. we have deployed in Jetty for testing without pre-authetication), we would want Basic Authentication to be used which in turns authenticated by LDAP Bind.
Is it something possible? How can I do it?
Here is my existing (simplified) app context:
<s:global-method-security
secured-annotations="enabled"
pre-post-annotations="enabled"
proxy-target-class="true" />
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<s:filter-chain-map path-type="ant">
<s:filter-chain pattern="/**"
filters="securityContextPersistenceFilter,preAuthenticatedFilter" />
</s:filter-chain-map>
</bean>
<bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name='securityContextRepository'>
<bean
class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
<property name='allowSessionCreation' value='true' />
</bean>
</property>
</bean>
<bean id="preAuthenticatedFilter"
class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<s:authentication-manager alias="authenticationManager">
<s:authentication-provider ref="preAuthenticatedAuthProvider" />
</s:authentication-manager>
<bean id="preAuthenticatedAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" >
<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper" >
<property name="userDetailsService" ref="userDetailsService" />
</bean>
</property>
</bean>
<bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<!-- some config skipped -->
</bean>
<bean id="userDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService" >
<constructor-arg index="0" ref="ldapUserSearch"/>
<constructor-arg index="1" ref="ldapAuthoritiesPopulator"/>
<property name="userDetailsMapper" ref="fooUserDetailsMapper" />
</bean>
<bean id="fooUserDetailsMapper" class="com.foo.FooUserDetailsMapper" />
<bean id="ldapUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<!-- some config skipped -->
</bean>
<bean id="ldapAuthoritiesPopulator"
class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<!-- some config skipped -->
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.simple.SimpleLdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="ldapAuthorities" class="com.fil.ims.LdapAuthoritiesServices" />
I have tried the followings but none of them works
add a new ldap authentication provider (org.springframework.security.ldap.authentication.LdapAuthenticationProvider), and add one more <s:authentication-provider> entry under <s:authentication-manager>, or
add a separate org.springframework.security.web.authentication.www.BasicAuthenticationFilter, which points to a new <s:authentication-provider> which points to the new ldap authentication provider (It is complaining for "An AuthenticationEntryPoint is required".)
What should be the right way to do so?
From my bare understanding, seems 2 should be the right way, if someone can give me some direction, it will be good enough.
Thanks

Pre-authentication in Spring Security + LDAP

Here is what I want to achieve:
I am using Websphere and I want to rely on the container to do the authentication (using Kerberos+SPNEGO). When it come to Spring Security, I want to rely on the pre-authentication, and use LDAP to retrieve user details (roles etc) for authorization checking.
Here is the part of Spring app context config I have (tried to only include related parts)
<s:global-method-security secured-annotations="enabled" pre-post-annotations="enabled" proxy-target-class="true" />
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<s:filter-chain-map path-type="ant">
<s:filter-chain pattern="/**"
filters="securityContextPersistenceFilter,preAuthenticatedFilter" />
</s:filter-chain-map>
</bean>
<s:http use-expressions="true" create-session="stateless" auto-config="true">
<!--
<s:http-basic />
-->
</s:http>
<bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name='securityContextRepository'>
<bean class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
<property name='allowSessionCreation' value='true' />
</bean>
</property>
</bean>
<bean id="preAuthenticatedFilter"
class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<s:authentication-manager alias="authenticationManager">
<s:authentication-provider ref="preAuthenticatedAuthenticationProvider" />
</s:authentication-manager>
<bean id="preAuthenticatedAuthenticationProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" >
<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper" >
<property name="userDetailsService" ref="userDetailsService" />
</bean>
</property>
</bean>
<bean id="userDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService" >
<constructor-arg index="0" ref="ldapUserSearch"/>
<constructor-arg index="1" ref="ldapAuthoritiesPopulator"/>
<property name="userDetailsMapper" >
<bean class="com.foo.MyUserDetailsMapper" />
</property>
</bean>
<bean id="ldapContextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<!-- some setting skipped here -->
</bean>
<bean id="ldapUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<!-- some setting skipped here -->
</bean>
<bean id="ldapAuthoritiesPopulator"
class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<!-- some setting skipped here -->
</bean>
<bean id="ldapTemplate" class="org.springframework.ldap.core.simple.SimpleLdapTemplate">
<constructor-arg ref="ldapContextSource" />
</bean>
It mostly worked, I can see correct user name and role coming in for my custom UserDetailsMapper (com.foo.MyUserDetailsMapper) which comes from LDAP, and inside that I am returning a new UserDetails with updated roles.
The problem is, in my controller, when I tried to do
SecurityContextHolder.getContext().getAuthentication()
It is returning null. (For which works before I change to pre-authentication)
Is there anything I missed?
Found the problem. Sorry that is mostly because of my own implementation fault which is not visible in the question itself.
My custom UserDetails impl is incorrectly having getEnabled() returning false. In LdapAuthenticationProvider, it is working fine as there is no checking on the user status.
However, in PreAuthenticatedAuthenticationProvider, by default there is a UserDetailsChecker which checks the status of user, for which getEnabled() returning false will cause the user details checker to fail silently, and causing authentication not populated to SecurityContext (i.e. treating that account as not authenticated)
Although it is mostly my implementation issue, I think still worth leaving here as a reference for difference of LdapAuthenticationProvider and PreAuthenticatedAuthenticationProvider

CAS + Spring Security Detect localhost

I am trying to implement an application with Spring security and CAS, it works fine on localhost but when I try to access it from an outside machine it and the application needs authentication it redirect to localhost too.
meaning
I access the application using https://172.16.1.50:8443/isxannouncements/
and when it needs authentication it should go to https://172.16.1.50:8443/cas/login/
but instead it goes to https://localhost:8443/isxannouncements/
which ofcourse breaks the application flow.
my config is
security-cas.xml
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://localhost:8443/isxannouncements/login"/>
</bean>
<!--
Allows changing where the CAS Server and CAS Service are easily
by specifying System Arguments or replacing the values only in one place.
Could also use external properties file -->
<context:property-placeholder
system-properties-mode="OVERRIDE" properties-ref="environment"/>
<util:properties id="environment">
<prop key="cas.service.host">localhost:8443</prop>
<prop key="cas.server.host">localhost:8443</prop>
</util:properties>
<!-- sends to the CAS Server, must be in entry-point-ref of security.xml -->
<bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="serviceProperties" ref="serviceProperties"/>
<property name="loginUrl" value="https://localhost:8443/cas/login" />
</bean>
<!-- authenticates CAS tickets, must be in custom-filter of security.xml -->
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="filterProcessesUrl" value="/login"/>
</bean>
<bean id="casAuthProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="ticketValidator" ref="ticketValidator"/>
<property name="serviceProperties" ref="serviceProperties"/>
<property name="key" value="isxannouncements"/>
<property name="authenticationUserDetailsService" ref="DBUserServiceDetails"/>
<property name="statelessTicketCache" ref="statelessTicketCache"/>
</bean>
<bean id="statelessTicketCache" class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache">
<property name="cache">
<bean class="net.sf.ehcache.Cache"
init-method="initialise" destroy-method="dispose">
<constructor-arg value="casTickets"/>
<constructor-arg value="50"/>
<constructor-arg value="true"/>
<constructor-arg value="false"/>
<constructor-arg value="3600"/>
<constructor-arg value="900"/>
</bean>
</property>
</bean>
<bean id="ticketValidator" class="org.jasig.cas.client.validation.Saml11TicketValidator">
<constructor-arg value="https://localhost:8443/cas" />
<property name="encoding" value="utf8" />
</bean>
<!-- Handles a Single Logout Request from the CAS Server must be in custom-filter of security.xml -->
<bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>
and my security.xml
<security:http pattern="/resources/images" security="none"/>
<security:http use-expressions="true" entry-point-ref="casEntryPoint">
<security:intercept-url pattern="/login/*"
access="permitAll"/>
<security:intercept-url pattern="/resources/**"
access="permitAll"/>
<security:intercept-url pattern="/logout"
access="permitAll"/>
<security:intercept-url pattern="/errors/**"
access="permitAll"/>
<security:intercept-url pattern="/approve-announcement**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/delete-announcement**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/edit-announcement**"
access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/admin/**"
access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/META-INF"
access="hasRole('ROLE_USER')"/>
<security:access-denied-handler error-page="/errors/403"/>
<security:custom-filter ref="singleLogoutFilter" before="LOGOUT_FILTER"/>
<security:custom-filter ref="casFilter" position="CAS_FILTER"/>
<security:port-mappings>
<security:port-mapping http="8080" https="8443"/>
</security:port-mappings>
<security:logout logout-url="/logout"
logout-success-url="https://localhost:8443/cas/logout"/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthProvider" />
</security:authentication-manager>
how to fix this ??
Ok I found a workaround but I did not test it properly,
Inspired by this answer I did the following
since I have two domains that the user might use to access my application, the only way to get the domain the user used was to get from the request and then return it to the security provider.
I created a bean named serviceProperties and used it instead of the serviceproperties of spring, and I overrided the method of getService to return the service based on the domain name that the user to access the application.
Then I made this bean available at Web Application Context, and I passed in the session, I had already extracted the domain from the Request and put it in the Session.
So when the CasAuthenticationEntryPoint tries to get the service, I pass the service URL that I created from the session appended to it is the service name.
We handle this with property files. Anything that is specific to a certain environment (i.e. your local machine versus your test server) should be in a property file.
For example, create properties files for each environment with something like this:
localhost.properties:
cas.service.url=http://localhost/login
test.properties:
cas.service.url=http://mytestserver/login
And then configure spring security with the value from the properties file instead of directly as you have it above:
Your build process would then have a target for each environment to shuffle the appropriate files into place in the final artifact.
CAS works under domain. so you should use cas.example.com and define it in the cas.properties

CAS Spring Security Java - Not Authorizing with User Details Service Not Loading Roles

I am using latest version of spring 3.2.5 and spring security 3.1.4 with java 6. I have setup CAS server using the instructions from this page
https://wiki.jasig.org/display/CASUM/Best+Practice+-+Setting+Up+CAS+Locally+using+the+Maven+WAR+Overlay+Method
The CAS server part is working fine and authenticating.
I have setup client side using the instructions from this page and various other pages
https://wiki.jasig.org/display/CASC/Configuring+the+JA-SIG+CAS+Client+for+Java+using+Spring
When tried to enter secure page in the application, CAS is redirecting to the correct login page and then correctly authenticating and then correctly redirecting to the calling application page, but not invoking the user details service supplied and not authorizing the user and not loading roles using the user details service.
After authentication user lands on this page. The page was correct but I don't want to see the ticket parameter in the URL and also load the user and roles using user details service bean supplied.
http://localhost:8080/my/sports-life/schedule?ticket=ST-3-xklhdGJW6gZxieELGxo5-cas01.example.org
Any pointers to get my authorization going is highly appreciated. Thanks in advance.
Here are the relevant beans from application context
<!-- Single sign on with CAS -->
<bean id="casEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="https://localhost:8443/cas/login"/>
<property name="serviceProperties" ref="serviceProperties"/>
</bean>
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<property name="service" value="http://localhost:8080/my/sports-life/schedule/j_spring_cas_security_check"/>
<property name="sendRenew" value="false"/>
</bean>
<bean id="casFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="preAuthenticationManager"/>
<property name="authenticationSuccessHandler">
<bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/my"/>
<property name="targetUrlParameter" value="spring-security-redirect" />
</bean>
</property>
</bean>
<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="userDetailsService" ref="myAccountDetailsService" />
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://localhost:8443/cas" />
</bean>
</property>
<property name="key" value="Vi9Pra88Si777"/>
<property name="authenticationUserDetailsService" ref="authenticationUserDetailsService"/>
</bean>
<bean id="authenticationUserDetailsService" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="myAccountDetailsService"/>
</bean>
<bean name="authenticationFilter" class="org.jasig.cas.client.authentication.AuthenticationFilter">
<property name="casServerLoginUrl" value="https://localhost:8443/cas/login" />
<property name="renew" value="false" />
<property name="gateway" value="false" />
<property name="service" value="http://localhost:8080/my/sports-life/schedule" />
</bean>
<!--
<bean
name="ticketValidationFilter"
class="org.jasig.cas.client.validation.Cas10TicketValidationFilter">
<property name="service" value="http://localhost:8080/my/sports-life/schedule" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://localhost:8443/cas" />
</bean>
</property>
</bean>
-->
<bean id="preauthAuthProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="myAccountDetailsService"/>
</bean>
</property>
</bean>
<!--
<bean id="preAuthEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<bean id="j2eePreAuthFilter" class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="preAuthenticationManager"/>
<property name="authenticationDetailsSource">
<bean class="org.springframework.security.web.authentication.WebAuthenticationDetailsSource" />
</property>
</bean>
-->
<bean id="myAccountDetailsService" class="com.viprasi.security.AccountDetailsServiceImpl">
</bean>
Then here are relevant config from my spring security configuration file.
<http use-expressions="true" entry-point-ref="casEntryPoint">
<intercept-url pattern="/app/j_spring_cas*" access="permitAll"
requires-channel="https" />
<!-- Member -->
<intercept-url pattern="/app/**" access="isAuthenticated()" />
<access-denied-handler error-page="/app/login/accessdenied" />
<anonymous />
<http-basic />
<custom-filter position="CAS_FILTER" ref="casFilter" />
</http>
<authentication-manager alias="preAuthenticationManager">
<authentication-provider ref="casAuthenticationProvider" />
<!--
<authentication-provider user-service-ref='accountDetailsService' />
-->
</authentication-manager>
i think the anonymous tag applies the role *IS_AUTHENTICATED_ANONYMOUSLY* to a user.
the result of this is that the user isAuthenticated() and no further filter is invoked (e.g. the one who calls the UserDetailsServive)
change isAuthenticated() to hasRole('ROLE')
I have an example cas client You can check in cas-web-client how provide your own authorization
We ran into lot of issues and at the end the main culprit was url rewriting filter. This filter was changing url and then spring security and cas failed to handled the changed URL. After moving the url rewrite filter below the security filters, it's all started working.

Implement SSO using CAS + Spring Security

I'm trying to implement SSO across several web applications using CAS and Spring Security. Expected case:
CAS - http:// localhost:8080/cas/
App A protected content - http: //localhost:8081/cas-client1/secure/index.html
App B protected content - http: //localhost:8081/cas-client2/secure/index.html
1) When user access cas-client1, CAS login form will be prompted and trigger authentication.
2) The same user access cas-client2, previous login should be recognized and no login form will be prompted
However, I am failed to implement step 2. CAS login form still prompted to user and therefore requires double login. Is there any wrong setting in my Spring Security configuration:
<security:http entry-point-ref="casAuthenticationEntryPoint" auto-config="true">
<security:intercept-url pattern="/secure/**" access="ROLE_USER" />
<security:custom-filter position="CAS_FILTER" ref="casAuthenticationFilter" />
</security:http>
<bean id="casAuthenticationEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="http://localhost:8080/cas/login" />
<property name="serviceProperties" ref="serviceProperties" />
</bean>
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<!-- http://localhost:8081/cas-client2 for app 2-->
<property name="service" value="http://localhost:8081/cas-client1/j_spring_cas_security_check" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider" />
</security:authentication-manager>
<bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/casfailed.jsp" />
</bean>
</property>
</bean>
<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="userDetailsService" ref="userService" />
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="http://localhost:8080/cas" />
</bean>
</property>
<property name="key" value="an_id_for_this_auth_provider_only" />
</bean>
<security:user-service id="userService">
<security:user name="wilson" password="wilson" authorities="ROLE_USER" />
</security:user-service>
The problem is finally solved. My CAS is using HTTP and therefore need to set secure cookies to false.
Modify ticketGrantingTicketCookieGenerator.xml
p:cookieSecure="false"

Categories

Resources