Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authentication using custom AbstractAuthenticationProcessingFilter and custom CustomAuthenticationProvider is not working propertly

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.

like image 916
Ekanath Avatar asked Nov 13 '22 09:11

Ekanath


1 Answers

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>
like image 181
Ekanath Avatar answered Jan 04 '23 03:01

Ekanath