Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use J2eePreAuthenticatedProcessingFilter and a custom authentication provider?

I want my Spring application to try two pre-authentication methods (Siteminder and Java EE container authentication).

  1. If either of these filters locates a username - I want to check that username against my database of users and assign roles based on what I see in the database. (I have an implementation of AuthenticationUserDetailsService, which does that for me.)
  2. If not - show a login page to the user. Check the credentials they enter in the form against my database of users.

The Siteminder integration is working. The login form is working too. My problem is with the Java EE pre-authentication. It never kicks in.

My applicationContext-security.xml:

<!-- HTTP security configurations -->
<sec:http auto-config="true" use-expressions="true">
    <sec:form-login login-processing-url="/resources/j_spring_security_check" always-use-default-target="true" default-target-url="/" login-page="/login"
        authentication-failure-url="/login?login_error=t" />
    <sec:logout logout-url="/resources/j_spring_security_logout" />
    <sec:access-denied-handler error-page="/accessDenied" />
    <sec:remember-me user-service-ref="customUserDetailsService" token-validity-seconds="86400" key="OptiVLM-VaultBalance" />
    <sec:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter"/>
    <sec:custom-filter after="PRE_AUTH_FILTER" ref="jeePreAuthenticatedFilter"/>

    <!-- various intercept-url elements here, skipped for brevity -->
</sec:http>

<!-- Authentication Manager -->
<sec:authentication-manager alias="authenticationManager">
    <!-- J2EE container pre-authentication or Siteminder -->
    <sec:authentication-provider ref="customPreAuthenticatedAuthenticationProvider" />
    <!-- Default provider -->
    <sec:authentication-provider user-service-ref="customUserDetailsService" />
</sec:authentication-manager>

<!-- Siteminder pre-authentication -->
<bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <property name="principalRequestHeader" value="SM_USER" />
    <property name="authenticationManager" ref="authenticationManager" />
    <property name="exceptionIfHeaderMissing" value="false" />
</bean>

<!-- J2EE pre-authentication -->
<bean id="jeePreAuthenticatedFilter" class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
    <property name="authenticationManager" ref="authenticationManager" />
</bean>

<!-- Custom pre-authentication provider -->
<bean id="customPreAuthenticatedAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <property name="preAuthenticatedUserDetailsService" ref="customAuthenticationUserDetailsService" />
</bean>

I have Java 2 security enabled in Websphere, and I am logged in as 'admin5'. (I have a user with this username in my user database.) But when I access the application, there is never a call to the 'customAuthenticationUserDetailsService' bean to verify the username. I know this, because 'customAuthenticationUserDetailsService' does extensive logging which clearly shows what it is doing. When I am using the Siteminder pre-authentication - the 'customAuthenticationUserDetailsService' works just fine, I get some trace output in the log. But not for the J2EE authentication...

My guess is that one of these things is happening:

a) Java EE pre-authentication filter is not locating the username, so it never calls the authentication manager

b) Java EE pre-authentication filter works fine, but my custom authentication provider is never called by the authentication manager for some reason

By the way, the default authentication provider, which uses 'customUserDetailsService' does not kick in either. Again, I can tell that because there is no output from 'customUserDetailsService' in the log.

Can you advise on what could be the problem here? If not a solution, then a suggestion on how to approach this would be greatly appreciated.

like image 820
anton1980 Avatar asked Mar 22 '12 22:03

anton1980


People also ask

How do I bypass authentication provider?

To plug in the new implementation of the AuthenticationProvider, override the configure(AuthenticationManagerBuilder auth) method of the WebSecurityConfigurerAdapter class in the configuration class. To register the multiple AuthenticationProvider implementations, we can invoke the auth.

How do authentication providers work?

In WebLogic Server, Authentication providers are used to prove the identity of users or system processes. Authentication providers also remember, transport, and make that identity information available to various components of a system (via subjects) when needed.

What is difference between authentication Manager and authentication Provider?

Authentication Provider calls User Details service loads the User Details and returns the Authenticated Principal. Authentication Manager returns the Authenticated Object to Authentication Filter and Authentication Filter sets the Authentication object in Security Context .

What is Dao authentication provider?

DaoAuthenticationProvider is an AuthenticationProvider implementation that leverages a UserDetailsService and PasswordEncoder to authenticate a username and password.


1 Answers

OK, I figured this out. The problem is that even though I had J2EE security setup in Websphere and was authenticated, my web.xml contained no security constraints. Because of this, Websphere was not supplying the principal for my requests. This is apparently an intentional feature. If you are not accessing a protected URL, you should not need the pre-authentication information.

To overcome this, I added a security constraint to my web.xml, which allowed ALL users to access the resources. Effectively, the resources were not secured, but still - there was a constraint now.

This is it:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>All areas</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>*</role-name>
        </auth-constraint>
</security-constraint>

This tricks the Websphere into filling in the user principal information in the request.

Thank you @Ralph for his comments on this this question: request.getUserPrincipal() got null

like image 185
anton1980 Avatar answered Sep 22 '22 19:09

anton1980