Authentication using custom AbstractAuthenticationProcessingFilter and custom CustomAuthenticationProvider is not working propertly

20,042

Sorry guys, I did not look at the question for a long time though I had solved this problem then and that time itself -

I used securityContextPersistenceFilter within the element and configured as below -

<security:http>
 <security:custom-filter before="SECURITY_CONTEXT_FILTER" ref="securityContextPersistenceFilter"/>

....

<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
    <property name="forceEagerSessionCreation" value="true"></property>
     <property name="securityContextRepository" ref="httpSessionSecurityContextRepository"/>
</bean>

<bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository">
 <property name="allowSessionCreation" value="false" />
</bean>
Share:
20,042
Ekanath
Author by

Ekanath

Working as Java/J2EE developer.

Updated on November 25, 2020

Comments

  • Ekanath
    Ekanath over 3 years

    We are using spring security to authenticate the user based on some user details (like userid ) coming from external application and perform authorization using the security context holder. We are using custom implementation of AbstractAuthenticationProcessingFilter and custom implemtation of CustomAuthenticationProvider with our own UserDetailsServiceImpl injected into provider for fetching user details from db.

    When single user tries to login it works fine, authentication object is created and it is properly set into SecurityCOntextHolder. But when another user tries to login the old authentication objects gets overwritten by new one. Looks like new session is not created on each user login.

    The implementation for the filter and provider is like below --

        public class DefaultAuthenticationProcessingFilter extends
        AbstractAuthenticationProcessingFilter {
    
    private final static Logger logger = LoggerFactory.getLogger(DefaultAuthenticationProcessingFilter.class);
    
    private static final String INTERCEPTOR_PROCESS_URL = "/sso/landingpage.action";
    
    public DefaultAuthenticationProcessingFilter() {
        super(INTERCEPTOR_PROCESS_URL);
    }
    
    public DefaultAuthenticationProcessingFilter(
            String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
        Assert.notNull(defaultFilterProcessesUrl, "Configuration error :: DefaultFilterProcessesUrl must be specified");
    }
    
    
    /**
     * Method to do authentication of user
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
            HttpServletResponse response) throws AuthenticationException,
            IOException, ServletException {
    
        logger.info("Authenticating the user .....");
    
        Authentication authResult = null;
        try {
    
            String eid = request.getParameter("EID");
    
            if( StringUtils.isEmpty(eid)) {
                 throw new PreAuthenticatedCredentialsNotFoundException("EID param not found in request.");
            }
    
            String credentials = "NA";
            PreAuthenticatedAuthenticationToken authRequest = new PreAuthenticatedAuthenticationToken(eid, credentials);
            authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
            authResult = getAuthenticationManager().authenticate(authRequest);
        } catch (AuthenticationException e) {
            unsuccessfulAuthentication(request, response, e);
        } 
        return authResult;
    }
        }
    
    
        protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                Authentication authResult) throws IOException, ServletException {
    
            if (logger.isDebugEnabled()) {
                logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
            }
    
            SecurityContextHolder.getContext().setAuthentication(authResult);
    
            getRememberMeServices().loginSuccess(request, response, authResult);
    
            // Fire event
            if (this.eventPublisher != null) {
                eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
            }
    
            getSuccessHandler().onAuthenticationSuccess(request, response, authResult);
     }
        }
    

    The implementation of custom provider is as below -

        public class CustomAuthenticationProvider implements AuthenticationProvider, InitializingBean {
    
    private final static Logger logger = LoggerFactory.getLogger(CustomAuthenticationProvider.class);
    
    private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthenticatedUserDetailsService = null;
    /**
    * 
    */
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    
        if (!supports(authentication.getClass())) {
            return null;
        }
    
        if (logger.isDebugEnabled()) {
            logger.debug("PreAuthenticated authentication request: " + authentication);
        }
    
        if (authentication.getPrincipal() == null) {
            logger.debug("No pre-authenticated principal found in request.");
            return null;
        }
    
        UserDetails ud = preAuthenticatedUserDetailsService.loadUserDetails((PreAuthenticatedAuthenticationToken)authentication);
    
        PreAuthenticatedAuthenticationToken result =
                new PreAuthenticatedAuthenticationToken(ud, authentication.getCredentials(), ud.getAuthorities());
        result.setDetails(authentication.getDetails());
    
        return result;
    
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub
    }
    
    @Override
    public boolean supports(Class<?> authentication) {
        return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
    }
    
    /**
     * @return the preAuthenticatedUserDetailsService
     */
    public AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> getPreAuthenticatedUserDetailsService() {
        return preAuthenticatedUserDetailsService;
    }
    
    /**
     * @param preAuthenticatedUserDetailsService the preAuthenticatedUserDetailsService to set
     */
    public void setPreAuthenticatedUserDetailsService(
            AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthenticatedUserDetailsService) {
        this.preAuthenticatedUserDetailsService = preAuthenticatedUserDetailsService;
    }
    }
    

    We have also configures custom authentication success handler to redirect user to appropriate URL upon authentication -

        public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    
    /**
     * redirect user to appropriate home page based on user role
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
    
        Set<GrantedAuthority> authorities = ((UserDetails)authentication.getPrincipal()).getAuthorities();
        if(CollectionUtils.isNotEmpty(authorities)){
            GrantedAuthority role = getHighestRole(authorities);
            String targetURL = getTargetURL(role);
            if (targetURL != null) {
                log.debug("Redirecting to target Url: " + targetURL);
                getRedirectStrategy().sendRedirect(request, response, targetURL);
                return;
            }
        }
    
        super.onAuthenticationSuccess(request, response, authentication);
    
    }
      }
    

    The spring security config file is like below -

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                           http://www.springframework.org/schema/security
                           http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    
     <security:http use-expressions="true" auto-config="false" pattern="/sso/*" entry-point-ref="http403ForbiddenEntryPoint" access-denied-page="/accessdenied.action" >
        <security:anonymous enabled="false"/>
        <security:custom-filter position="BASIC_AUTH_FILTER" ref="defaultBasicAuthFilter" />
        <security:expression-handler ref="expressionHandler"/>
    </security:http>
    
    <security:http use-expressions="true" auto-config="false" pattern="/rcd/associate/*" entry-point-ref="http403ForbiddenEntryPoint"  access-denied-page="/accessdenied.action">
        <security:intercept-url pattern="/saml/sso/*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
            <security:custom-filter position="BASIC_AUTH_FILTER" ref="defaultBasicAuthFilter" />
        <security:expression-handler ref="expressionHandler"/>
    </security:http>
    
    <bean id="http403ForbiddenEntryPoint"
        class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
    
    
    <bean id="expressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
         <property name="permissionEvaluator" ref="customPermissionEvaluator" /> 
    </bean>
    
    <bean id="defaultBasicAuthFilter"
        class="com.example.security.authentication.DefaultAuthenticationProcessingFilter">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
        <property name="AuthenticationFailureHandler" ref="failureHandler"></property>
    </bean>
    
    <bean id="authProvider"
    class="com.example.security.authentication.CustomAuthenticationProvider">
        <property name="preAuthenticatedUserDetailsService">
            <bean id="userDetailsServiceWrapper"
                class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                <property name="userDetailsService" ref="userDetailsService" />
            </bean>
        </property>
    </bean>
    
    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider
            ref="authProvider" />
    </security:authentication-manager>
    
    <bean id="userDetailsService" class="com.example.security.authorization.UserDetailsServiceImpl" />
    
     <bean id="successRedirectHandler"
          class="com.example.security.authentication.CustomAuthenticationSuccessHandler">
            <property name="defaultTargetUrl" value="/user1/user1LandingPage.action"/>
         </bean>
    
    <bean id="failureHandler"
          class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
        <property name="defaultFailureUrl" value="/accessdenied.action"/>
    </bean>
    

    We have also configured web.xml

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/spring-app-context.xml <!-- ,/WEB-INF/spring/security.xml -->
        </param-value>
    </context-param>
    
    <servlet>
        <servlet-name>example-dispatcher-servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <!-- Map all /example*.action requests to the example-dispatcher-servlet for handling -->
    <servlet-mapping>
        <servlet-name>example-dispatcher-servlet</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>/rcd/pages/index.jsp</welcome-file>
    </welcome-file-list>
    
    <listener>
        <listener-class>com.example.HttpSessionListenerImpl</listener-class>
    </listener>
    
    
    <!-- Spring Security -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    
    <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
    </web-app>
    

    We are using spring 3.1.3 and spring security 3.1.3 On each user login new session should be created and security context should be set accordingly. But its happening in my case. I checked debuggin my application and found that new session is not getting created on user login. May be i am missing it somewhere. I don't find any relevant solution anywhere.

    Any help in this regard will be appreciated the most.

    Thanks.

  • sumedha
    sumedha over 8 years
    i have similar requirement can you please take a look at my issue stackoverflow.com/questions/34269682/…