Spring Security and custom Remember me filter: logout issue - spring

I need to define a custom RememberMeAuthenticationFilter so that I can override the onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) method to put some custom logic.
I've configured the XML in order to use my custom filter:
<security:http disable-url-rewriting="true" request-matcher-ref="excludeUrlRequestMatcher" entry-point-ref="authenticationEntryPoint">
<security:custom-filter position="FORM_LOGIN_FILTER" ref="usernamePasswordAuthenticationFilter"/>
<security:custom-filter position="REMEMBER_ME_FILTER" ref="extRememberMeProcessingFilter"/>
<security:anonymous username="anonymous" granted-authority="ROLE_ANONYMOUS"/>
<security:session-management session-authentication-strategy-ref="fixation" />
<!-- Intercepts url HERE: removed for brevity -->
<!--<security:form-login: using custom filter -->
<!--login-page="/login"-->
<!--authentication-failure-handler-ref="loginAuthenticationFailureHandler"-->
<!--authentication-success-handler-ref="loginGuidAuthenticationSuccessHandler"/>-->
<security:logout logout-url="/logout" success-handler-ref="logoutSuccessHandler"/>
<security:port-mappings>
<security:port-mapping http="#{configurationService.configuration.getProperty('tomcat.http.port')}"
https="#{configurationService.configuration.getProperty('tomcat.ssl.port')}"/>
<security:port-mapping http="80" https="443"/>
<!--security:port-mapping http="#{configurationService.configuration.getProperty('proxy.http.port')}"
https="#{configurationService.configuration.getProperty('proxy.ssl.port')}" /-->
</security:port-mappings>
<security:request-cache ref="httpSessionRequestCache"/>
<security:access-denied-handler ref="b2bAccessDeniedHandler"/>
<!-- RememberMe: using custom filter -->
<!--<security:remember-me key="comtestrememberme" services-ref="rememberMeServices"/>-->
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="myAuthenticationProvider"/>
<security:authentication-provider ref="rememberMeAuthenticationProvider"/>
</security:authentication-manager>
<bean id="myAuthenticationProvider"
class="com.test.security.MyAuthenticationProvider">
<property name="bruteForceAttackCounter" ref="bruteForceAttackCounter"/>
<property name="customerService" ref="customerService"/>
<aop:scoped-proxy/>
</bean>
<bean id="rememberMeServices"
class="com.test.security.MyRememberMeServices">
<property name="key" value="comtestrememberme"/>
<property name="cookieName" value="myRememberMe"/>
<property name="alwaysRemember" value="false"/>
<property name="customerService" ref="customerService"/>
<property name="useSecureCookie" value="false"/>
<aop:scoped-proxy/>
</bean>
<bean id="rememberMeAuthenticationProvider"
class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="comtestrememberme"/>
<aop:scoped-proxy/>
</bean>
<bean id="usernamePasswordAuthenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationSuccessHandler" ref="loginGuidAuthenticationSuccessHandler"/>
<property name="authenticationFailureHandler" ref="loginAuthenticationFailureHandler"/>
</bean>
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login"/>
</bean>
<bean id="extRememberMeProcessingFilter" class="com.test.security.filters.ExtRememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
The remember me cookie is getting created and my custom filter is being used, but the problem is that the logout never happens.
When I click on the logout button it looks like I'm going through the authentication process again and the customer is logged in again.
If I revert back to the standard Spring Filters everything is working fine.
Have I missed something in the configuration?

What may be happening here is - your logout is working fine but you haven't deleted myRememberMe cookie on logout. So, when your session is getting invalidated on logout, remember me services is creating a new session by using myRememberMe cookie.
Solution: You can modify your configuration by adding delete-cookies attribute in your <security:logout> tag.
<security:logout logout-url="/logout" success-handler-ref="logoutSuccessHandler" delete-cookies="JSESSIONID,myRememberMe" />

Related

Spring Security having two authentication layers

In our application, we are required to have two layers of authentication,Database and LDAP, i.e,
Once User logins with username and password, Database validation is done only to check if username exists in database using custom authentication privider.
If username exists in the database then second layer of LDAP has to be invoked to check if password matches.If password matches with that in LDAP then user should be authenticated.If username doesn't exist in the database, the LDAP layer shouldn't be invoked and user shouldn't be authenticated.
I have implemented the first layer of authentication i.e Database validation for username.
However I am not able to figure out how I can have second layer i.e LDAP for password check.
It would be great if someone helps me on this.
Below is the code in security xml file:
<security:http auto-config="false" use-expressions="true"
entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:custom-filter ref="customAuthenticationFilter"
position="FORM_LOGIN_FILTER" />
<security:custom-filter ref="concurrencyFilter" position="CONCURRENT_SESSION_FILTER" />
<security:access-denied-handler
error-page="/accessDenied" />
<security:logout delete-cookies="JSESSIONID" logout-success-url="/logout" />
<security:session-management session-authentication-strategy-ref="sas" />
<security:headers >
<security:cache-control />
<security:hsts/>
</security:headers>
</security:http>
<security:global-method-security
pre-post-annotations="enabled" />
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="customAuthenticationProvider" />
</security:authentication-manager>
<bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/">
</property>
</bean>
<bean id="customAuthenticationFilter"
class="com.honeywell.wfm.util.CustomAuthenticationFilter">
<property name="usernameParameter" value="username"></property>
<property name="passwordParameter" value="password"></property>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler" ref="failureHandler"/>
<property name="authenticationSuccessHandler" ref="successHandler"/>
<property name="sessionAuthenticationStrategy" ref="sas" />
</bean>
<bean id="successHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/dashboard"/>
</bean>
<bean id="failureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/failTologin"/>
</bean>
<bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<property name="sessionRegistry" ref="sessionRegistry" />
<property name="expiredUrl" value="/logout" />
</bean>
<bean id="sas"
class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg>
<list>
<bean
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<constructor-arg ref="sessionRegistry" />
<property name="maximumSessions" value="1" />
<property name="exceptionIfMaximumExceeded" value="false" />
</bean>
<bean
class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
</bean>
<bean
class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<constructor-arg ref="sessionRegistry" />
</bean>
</list>
</constructor-arg>
</bean>
<bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
<property name="rolePrefix" value="" />
</bean>
<bean id="customAuthenticationProvider"
class="com.honeywell.wfm.service.impl.CustomAuthenticationProvider"></bean>
CustomAuthenticationProvider.java
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String employeeNumber = authentication.getName();
String password = (String) authentication.getCredentials();
UserDTO userDTO = loginComponent.loadUserByUsername(employeeNumber);
if (userDTO.getEmployeeNo() == null) {
logger.error("Authentication failure for "+employeeNumber);
throw new BadCredentialsException("Invalid Employee Number");
}
logger.info("Successfully Authenticated " +userDTO.getUserName());
userDTO.setPassword(password);
return new UsernamePasswordAuthenticationToken(userDTO, password, userDTO.getAuthorities());
}

Method 'setProviders' is marked deprecated in Spring Security 3.2.7

I am using Spring Security 3.2.7 and I got this warning in my spring configuration
Multiple annotations found at this line:
- Method 'setProviders' is marked deprecated
security-config.xml:
<security:http auto-config="true">
<security:intercept-url pattern="/**" />
<security:form-login login-page="/login**"
default-target-url="/dashboard**"
authentication-failure-url="/login.xhtml?failed=true"/>
<security:logout logout-url="/logout" logout-success-url="/login.xhtml"/>
</security:http>
<bean id="userDao" class="com.tds.erp.dao.impl.UserDaoImpl"
autowire="default" />
<bean id="userDetailsService" class="com.tds.erp.services.impl.UserDetailServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService" ></property>
</bean>
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
</list>
</property>
</bean>
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<!-- <security:password-encoder hash="bcrypt"/> -->
</security:authentication-provider>
</security:authentication-manager>
</beans>
Try with the following for the authentication manager
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg ref="daoAuthenticationProvider"/>
</bean>

Spring security - Access http session on successful login handler

I'm trying to access the HttpSession after logging in, using the successful handler - MySimpleUrlAuthenticationSuccessHandler - using request.getSession(false) , but it's null at this phase, any suggestions ?
Part of beans.xml:
<security:http auto-config="false"
entry-point-ref="authenticationEntryPoint">
<security:intercept-url pattern="/**" />
<security:custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter" />
<security:remember-me />
<security:anonymous enabled="false" />
<security:session-management session-fixation-protection="none" />
</security:http>
<bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint" >
<constructor-arg type="java.lang.String" value="/login"/>
</bean>
<bean id="authenticationFilter"
class="com.me.filter.CustomAuthenticationFilter">
<constructor-arg type="java.lang.String" value="/login"/>
<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="authenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login/failure" />
</bean>
<bean id="authenticationSuccessHandler"
class="com.me.web.filter.MySimpleUrlAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/login/success" />
</bean>
We should define a session strategy to make the filter create the session on successful authentication, so beans.xml changes are like this:
<bean id="authenticationFilter"
class="com.me.filter.CustomAuthenticationFilter">
<constructor-arg type="java.lang.String" value="/login"/>
<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
<property name="authenticationManager" ref="authenticationManager"/>
<property name="sessionAuthenticationStrategy" ref="registerSessionStrategy" />
</bean>
<bean id="registerSessionStrategy" class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
</bean>
<bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />

Spring Security Custom Preauthentication filter with Digest Authentication

I have an app with uses a Digest authentication. I want to customize the authentication process by checking a custom HTTP header in addition to the Digest method. If the header is present in the request the authentication should proceed as before, if it isn't then the user should be rejected. I tried to do this by defining a custom preauthentication filter, but somehow it doesn't work together with the Digest filter.
<security:http entry-point-ref="digestEntryPoint">
<security:custom-filter ref="customPreauthFilter" position="PRE_AUTH_FILTER"/>
<security:custom-filter ref="digestFilter" before="BASIC_AUTH_FILTER"/>
<security:anonymous enabled="false"/>
</security:http>
<bean id="customPreauthFilter" class="com.myapp.messaging.security.SoundianRequestHeaderAuthenticationFilter">
<property name="authenticationManager" ref="appControlAuthenticationManager" />
</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="customUserDetailsService"/>
</bean>
</property>
</bean>
<security:authentication-manager alias="appControlAuthenticationManager">
<security:authentication-provider ref="preauthAuthProvider" />
<security:authentication-provider ref="daoAuthenticationProvider"/>
</security:authentication-manager>
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="customUserDetailsService"/>
</bean>
<!-- Digest authentication -->
<bean id="digestFilter" class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
<security:authentication-provider ref="preauthAuthProvider" />
<!-- <security:authentication-provider ref="daoAuthenticationProvider"/>-->
</bean>
<bean id="digestEntryPoint" class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
<property name="realmName" value="myvalue"/>
<property name="key" value="acegi"/>
<property name="nonceValiditySeconds" value="10"/>
</bean>
The Preauthentication filter succeeds, but I am still getting 401 results.
If I uncomment
<!-- <security:authentication-provider ref="daoAuthenticationProvider"/>-->
then the preauthentication filter is disregarded.

Spring 3.x configuration for multiple login pages

I'm using Spring 3.1 for authentication purpose.
My requirement:
Two different login pages. One for Customer and other for Employee.
Each after successful authentication, will be forwarded to respective successful URL.
My spring security configuration:
<sec:http pattern="/resources/**" security="none" />
<sec:http auto-config="true">
<sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<sec:intercept-url pattern="/customer/**" access="ROLE_CUSTOMER" />
<sec:intercept-url pattern="/employee/**" access="ROLE_EMPLOYEE" />
</sec:http>
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/**"
filters="authenticationProcessingFilterForCustomer,authenticationProcessingFilterForEmployee" />
</sec:filter-chain-map>
</bean>
<bean id="authenticationProcessingFilterForCustomer"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManagerForCustomer" />
<property name="filterProcessesUrl" value="/j_spring_security_check_for_customer" />
<property name="authenticationSuccessHandler" ref="customerSuccessHandler" />
<property name="authenticationFailureHandler" ref="customerFailureHandler" />
</bean>
<bean id="customerSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/customer/index.html" />
</bean>
<bean id="customerFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/customer.html?login_error=1" />
</bean>
<bean id="authenticationManagerForCustomer"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref bean="customCustomerAuthenticationProvider" />
</list>
</property>
</bean>
<bean id="customCustomerAuthenticationProvider" class="com.edu.CustomerCustomAuthenticationProvider">
<property name="userDetailsService">
<bean class="com.edu.CustomerUserDetailsService" />
</property>
</bean>
<bean id="authenticationProcessingFilterForEmployee"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManagerForEmployee" />
<property name="filterProcessesUrl" value="/j_spring_security_check_for_employee" />
<property name="authenticationSuccessHandler" ref="employeeSuccessHandler" />
<property name="authenticationFailureHandler" ref="employeeFailureHandler" />
</bean>
<bean id="employeeSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/employee/index.html" />
</bean>
<bean id="employeeFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/employee.html?login_error=1" />
</bean>
<bean id="authenticationManagerForEmployee"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref bean="customEmployeeAuthenticationProvider" />
</list>
</property>
</bean>
<bean id="customEmployeeAuthenticationProvider" class="com.edu.EmployeeCustomAuthenticationProvider">
<property name="userDetailsService">
<bean class="com.edu.EmployeeUserDetailsService" />
</property>
</bean>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="customCustomerAuthenticationProvider" />
<sec:authentication-provider ref="customEmployeeAuthenticationProvider" />
</sec:authentication-manager>
Both CustomAuthenticationProvider have implemented Support method as follows:
public boolean supports(Class<? extends Object> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
After launching application, while trying to authenticate, the message displayed in login pages are:
Your login attempt was not successful, try again.
Reason: No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken
I'm using Spring 3.1. Any help appreciated.
Thank You
I have done similar things in grails, what you need is:
extend UsernamePasswordAuthenticationToken, create two sub-class for employee and customer, say EmployeeUsernamePasswordAuthenticationToken and CustomerUsernamePasswordAuthenticationToken
extend UsernamePasswordAuthenticationFilter, to create different instance of EmployeeUsernamePasswordAuthenticationToken or CustomerUsernamePasswordAuthenticationToken based on current auth request
extend AuthenticationProvider for employee and custoner, create two class say EmployeeAuthenticationProvider and CustomerAuthenticationProvider, overwrite each class' supports method to support its target UsernamePasswordAuthenticationToken
you only need one authenticationManager, register both provide into it
only need one AuthenticationSuccessHandler, you can decide which url want to go in it
I also create a my own instance of AuthenticationEntryPoint to support multi entrypoint
Beginning from Spring 3.1 you have as many configuration as you want :
https://jira.springsource.org/browse/SEC-1171
You should point the authenticationManager ref in 'authenticationProcessingFilterForCustomer' and 'authenticationProcessingFilterForEmployee' beans to correct bean i.e. 'authenticationManager' which has providers. No need to define 'authenticationManagerForCustomer' and 'authenticationManagerForEmployee' beans.

Resources