Announcement Announcement Module
Collapse
No announcement yet.
Pass Multiple Headers to UserDetailsService Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Pass Multiple Headers to UserDetailsService

    This is my first post, so let me know if I'm not following posting protocol properly.

    My application uses Shibboleth/Spring Security and I am trying to pass multiple headers to UserDetailsService because I have to look up the user by different fields. My configuration looks the one at

    http://static.springsource.org/sprin...e/preauth.html

    i.e.

    Code:
     
    <security:http>
        <!-- Additional http configuration omitted -->
        <security:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
      </security:http>
    
        <bean id="siteminderFilter" class=
    "org.springframework.security.web.authentication.preauth.header.RequestHeaderAuthenticationFilter">
        <property name="principalRequestHeader" value="SM_USER"/>
        <property name="authenticationManager" ref="authenticationManager" />
      </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="userDetailsService"/>
          </bean>
        </property>
        </bean>
    
        <security:authentication-manager alias="authenticationManager">
          <security:authentication-provider ref="preauthAuthProvider" />
        </security-authentication-manager>
    How can I accomplish doing something like :

    Code:
        <bean id="siteminderFilter" class=
    "org.springframework.security.web.authentication.preauth.header.RequestHeaderAuthenticationFilter">
        <property name="principalRequestHeader1" value="LOCAL_ID"/>
        <property name="principalRequestHeader2" value="GLOBAL_ID"/>
        <property name="principalRequestHeader3" value="OTHER_ID"/>
        <property name="authenticationManager" ref="authenticationManager" />
      </bean>
    Any help is appreciated

  • #2
    Do you need all the fields at once or just individually? If you need them individually you can create three instances of the filter one with each of the headers. Make sure that the first two do not have the exceptionIfHeaderMissing set to true. An alternative (and cleaner approach) would be to extend the AbstractPreAuthenticatedProcessingFilter. This would work even if you needed only one of the fields or if you needed all the fields at once.

    Comment


    • #3
      I need all fields at once so I will try your second suggestion. Thank you!

      Comment


      • #4
        As a follow up to my question (let me know if I should start a new thread) I implemented my own RequestHeaderAuthenticationFilter which grabs all the header fields that I need.
        Now, when I pass it to my UserDetailsService implementation, I need to pass all the fields to loadUserByUsername so the correct User is load.

        The problem is that loadUserByUsername takes a String as a parameter.

        The reason I need to do this is that my authentication service is federated so the loadUserByUsername method has to figure out which field to use to retrieve the user, i.e.

        1. look up user in the "local" population by username1
        2. if none found, look up user in the "global" population by username2, etc.

        So I have to somehow pass all of the usernames as a map to loadUserByUsername.

        The only way I could think of doing this is converting the map to a string, passing it to loadUserByUsername and then parsing the Map. This is definitely a hack.

        Any ideas on a cleaner way to do this?


        Thank you!

        Comment


        • #5
          Originally posted by dotcom View Post

          The problem is that loadUserByUsername takes a String as a parameter.
          The preAuthenticatedUserDetailsService is actually an AuthenticationUserDetailsService, so you can implement this directly. If you look at your configuration, you are using a wrapper which creates the actual instance from a basic UserDetailsService.

          Either that or you can implement the AuthenticationProvider directly.

          Comment


          • #6
            Originally posted by dotcom View Post
            The problem is that loadUserByUsername takes a String as a parameter.
            You can pass extra parameters as HTTP-headers and extract them from the request in loadUserByUsername().

            Add a RequestContextListener in web.xml
            Code:
            <listener>
            <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
            </listener>
            In your UserDetailsService implementation
            Code:
            public EntityUserDetails loadUserByUsername...
            {
                    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            ...

            Comment

            Working...
            X