Unable to change Spring security access denied standard response - java

I have a Spring Boot application in which I used OAuth with Spring Security. When I requests an authorization token to Spring Security it returns the following response:
{"error":"invalid_grant","error_description":"Bad credentials"}
I need to change that response to a custom json, but none of the approaches I have tried works.
I have tried to use a custom AccessDeniedHandler like the following:
public class CustomOAuth2AccessDeniedHandler implements AccessDeniedHandler{
public CustomOAuth2AccessDeniedHandler() {
}
#Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException authException)
throws IOException, ServletException {
response.setContentType(MediaType.TEXT_PLAIN_VALUE);
response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
response.getOutputStream().println("Exception with message : " + authException.getMessage());
//doHandle(request, response, authException);
}
but it does not get called. Using web.xml to redirect response is not an option for me since I am using Spring Boot, and I do not want to change the format of the response globally.
My spring-security.xml is configured like this:
<!-- Definition of the Authentication Service -->
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<anonymous enabled="false"/>
<http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="dstest"/>
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="dstest/client"/>
<property name="typeName" value="Basic"/>
</bean>
<!-- <bean id="oauthAccessDeniedHandler" -->
<!-- class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/> -->
<bean id="oauthAccessDeniedHandler"
class="in.robotrack.brad.config.CustomOAuth2AccessDeniedHandler"/>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager"/>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</list>
</constructor-arg>
</bean>
<!-- Authentication in config file -->
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="customUserDetailsService">
</authentication-provider>
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<!-- Token Store -->
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore"/>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="clientDetailsService" ref="clientDetails"/>
<!-- VIV -->
<property name="accessTokenValiditySeconds" value="10"/>
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
<property name="tokenServices" ref="tokenServices"/>
</bean>

try bellow:
HttpSecurity http = ...
http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler);
if you don't want to define your custom AccessdeniedHandler then even you can try this
HttpSecurity http = ...
http.exceptionHandling().accessDeniedPage("/403");
And then in your controller just define one method that can handle /403 request mapping and there you just return your 403 error page, as you do in normal methods inside any controller class.

Related

Spring security and oauth2 authentication problem

My problem is if I use org.springframework.security.authentication.ProviderManager for my autheticationManager in applicationContext-security.xml then I unable to authenticate with oauth2. If I switch back to authentication-manager id="authenticationManager" version then it works fine.
I have to keep my REST service and oauth2 security settings in separate files. (Sometimes we don't need for REST service at all).
spring-security 4.2.9.RELEASE
spring-security-oauth2 2.3.4
web.xml snippet:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/rest-dispatcher-servlet.xml
/WEB-INF/rest-dispatcher-servlet-security.xml
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
rest-dispatcher-servlet-security
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:secdp="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- Definition of the Authentication Service -->
<secdp:http use-expressions="false" pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<anonymous enabled="false"/>
<secdp:http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
<secdp:csrf disabled="true"/>
</secdp:http>
<!-- Protected resources -->
<secdp:http use-expressions="false" pattern="/ws/api/**"
create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false"/>
<intercept-url pattern="/ws/api/**"
access="ROLE_USER"/>
<custom-filter ref="resourceServerFilter"
before="PRE_AUTH_FILTER"/>
<access-denied-handler
ref="oauthAccessDeniedHandler"/>
<secdp:csrf disabled="true"/>
</secdp:http>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="dstest"/>
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="dstest/client"/>
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager"/>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</list>
</constructor-arg>
</bean>
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<!-- Token Store -->
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore"/>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="clientDetailsService" ref="clientDetails"/>
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<property name="tokenStore" ref="tokenStore"/>
<property name="requestFactory" ref="oAuth2RequestFactory"/>
</bean>
<!-- Token management -->
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler" >
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="dstest"
token-services-ref="tokenServices"/>
<!-- Client Definition -->
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="xxxxxxxxx"
authorized-grant-types="password,authorization_code,refresh_token,implicit,redirect"
authorities="ROLE_USER, ROLE_TRUSTED_USER"
redirect-uri="/"
scope="read,write,trust"
access-token-validity="2678400"
refresh-token-validity="15552000" />
</oauth:client-details-service>
<bean class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory" id="oAuth2RequestFactory">
<constructor-arg ref="clientDetails" />
</bean>
</beans>
applicationContext-security.xml snippet
<!-- works -->
<authentication-manager id="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="CustomUserDetailsService">
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
<!-- does not work -->
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg>
<list>
<ref bean="daoAuthenticationProvider"/>
</list>
</constructor-arg>
</bean>
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService">
<ref bean="CustomUserDetailsService"/>
</property>
<property name="passwordEncoder">
<ref bean="passwordEncoder"/>
</property>
<property name="hideUserNotFoundExceptions">
<value>false</value>
</property>
</bean>

Spring OAuth2 - How to configure authentication service that it should pass User credential via request header or body

I have an app that is implemented using spring security oauth2 version 2.0 So if user needs access Token. He need to send the user credentials as query params:
/oauth/token?grant_type=password&client_id=website-CLIENT&username=test1&password=test1
Please can any one help me what configuration should be done so user credentials can go as request body or request header.
Spring Configuration File:
<!-- Definition of the Authentication Service -->
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<anonymous enabled="false"/>
<http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"/>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="client"/>
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager"/>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</list>
</constructor-arg>
</bean>
<bean id="customAuthenticationManager"
class="com.xyz.authentication.XYZDBAuthenticationProvider"/>
<!-- Authentication in config file -->
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider ref="customAuthenticationManager"/>
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<!-- Token Store -->
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
<constructor-arg ref="jdbcTokenStore" />
</bean>
<bean id="jdbcTokenStore"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="#{systemProperties['JDBC_CONNECTION_STRING']}/#{systemProperties['DATABASE']}?autoReconnect=true"/>
<property name="username" value="#{systemProperties['USER_NAME']}"/>
<property name="password" value="#{systemProperties['PASSWORD']}"/>
</bean>
<bean id="tokenServices" class="xyz.oauth2.CustomTokenServices">
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="clientDetailsService" ref="clientDetails"/>
<!-- VIV -->
<property name="accessTokenValiditySeconds" value="7776000"/>
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<property name="tokenStore" ref="tokenStore"/>
<property name="requestFactory" ref="oAuth2RequestFactory"/>
</bean>
<bean id="oAuth2RequestFactory"
class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
<constructor-arg ref="clientDetails"/>
</bean>
<!-- Token management -->
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
token-services-ref="tokenServices"/>
<!-- Client Definition -->
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="mobile-CLIENT"
authorized-grant-types="password,refresh_token,implicit"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT"
scope="read,write,trust"
access-token-validity="7776000"
refresh-token-validity="15552000"/>
<oauth:client client-id="website-CLIENT"
authorized-grant-types="password,refresh_token,implicit"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT"
scope="read,write,trust"
access-token-validity="7776000"
refresh-token-validity="15552000"/>
</oauth:client-details-service>
<sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<sec:expression-handler ref="oauthExpressionHandler"/>
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler"/>
<oauth:web-expression-handler id="oauthWebExpressionHandler"/>

Failing to exclude some URLs from Spring Security protection

We have the following spring security configuration:
<bean id="authenticationSuccessHandler" class="***.JsonAuthenticationSuccessHandler"/>
<bean id="logoutSuccessHandler" class="***.web.security.***UrlLogoutSuccessHandler">
<property name="redirectStrategy" ref="noRedirectStrategy"/>
</bean>
<bean id="authenticationFailureHandler"
class="***.web.security.***UrlAuthenticationFailureHandler"/>
<bean id="httpStatusEntryPoint" class="org.springframework.security.web.authentication.HttpStatusEntryPoint">
<constructor-arg value="UNAUTHORIZED"/>
</bean>
<security:http auto-config="true" use-expressions="false" entry-point-ref="httpStatusEntryPoint">
<security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrentSessionFilter"/>
<security:form-login
authentication-success-handler-ref="authenticationSuccessHandler"
authentication-failure-handler-ref="authenticationFailureHandler"
/>
<security:intercept-url pattern="/api/**"/>
<security:anonymous enabled="false"/>
<security:logout logout-url="/logout" delete-cookies="JSESSIONID,sessionId"
success-handler-ref="logoutSuccessHandler"
/>
<security:csrf disabled="true"/>
<security:session-management session-authentication-strategy-ref="sessionAuthenticationStrategy"/>
</security:http>
<bean id="concurrentSessionFilter" class="***.***ConcurrentSessionFilter">
<constructor-arg ref="***SessionRegistry"/>
<constructor-arg ref="errorController"/>
</bean>
<bean id="sessionAuthenticationStrategy" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg>
<list>
<ref bean="registerSessionAuthenticationStrategy"/>
<ref bean="concurrentSessionControlAuthenticationStrategy"/>
</list>
</constructor-arg>
</bean>
<bean id="registerSessionAuthenticationStrategy" class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<constructor-arg name="sessionRegistry" ref="***SessionRegistry" />
</bean>
<bean id="concurrentSessionControlAuthenticationStrategy" class="***.web.security.***ConcurrentSessionControlAuthenticationStrategy">
<constructor-arg name="sessionRegistry" ref="***SessionRegistry" />
<constructor-arg name="logoutService" ref="logoutService"/>
<property name="maximumSessions" value="1" />
</bean>
<!-- enable spring security annotation processing -->
<security:global-method-security secured-annotations="enabled"/>
<bean id="***LdapAuthenticationProvider" class="***.web.***LdapAuthProvider">
<property name="url" value="${ldap.url}"/>
<property name="filter" value="${ldap.filter}"/>
<property name="domain" value="${ldap.domain}"/>
<property name="dn" value="${ldap.dn}"/>
<property name="ldapEnabled" value="${ldap.enable}"/>
</bean>
<security:authentication-manager>
<security:authentication-provider ref="***LdapAuthenticationProvider"/>
<security:authentication-provider user-service-ref="***UserDetailsService"/>
</security:authentication-manager>
<bean id="usersResource" class="org.springframework.core.io.ClassPathResource">
<constructor-arg value="/users.properties" />
</bean>
<util:property-path id="usersResourceFile" path="usersResource.file" />
<bean id="***UserDetailsService" class="***.web.security.***InMemoryUserDetailsManager">
<constructor-arg index="0" ref="usersResourceFile"/>
</bean>
I tried different ways But I can not find a way to exclude some specific URLs from authentication.
For example:
/api/url/available/without/login
should be available even user is not logged in.
P.S.
I have tried to apply this answer, but it doesn't work for me:
https://stackoverflow.com/a/5382178/2674303
UPD
I have tired
....
<bean id="httpStatusEntryPoint" class="org.springframework.security.web.authentication.HttpStatusEntryPoint">
<constructor-arg value="UNAUTHORIZED"/>
</bean>
<security:http pattern="/api/url/available/without/login" security="none"/>
<security:http auto-config="true" use-expressions="false" entry-point-ref="httpStatusEntryPoint">
....
but when I try to use - this url still locked and I get 401
because this code:
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
String name = authentication != null ? authentication.getName() : "";
throw new BadCredentialsException("Could not find user " + name);
}
throws exception
You just need to add a "default" http interceptor:
<security:http xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/" access="permitAll()"/>
<anonymous/>
<csrf disabled="true"/>
</security:http>
after your current security:http tag. It will handle all requests, which were not handled by the first http construction.

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