Announcement Announcement Module
Collapse
No announcement yet.
How do I use a custom WebAuthenticationDetails with BasicAuthenticationFilter Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How do I use a custom WebAuthenticationDetails with BasicAuthenticationFilter

    Hi everyone,

    I've written a handful of custom AuthenticationProviders which work with basic authentication. During the authenticate() method, I need to get hold of some custom headers. I've been trying to use a custom WebAuthenticationDetails which will extract the headers in its doPopulateAdditionalInformation() method.

    All I really want to do is use the existing basic auth mechanism but just override this one method, yet I'm having trouble working out how. Is it possible simply to tell the BasicAuthenticationFilter to use a custom class?

    many thanks in advance
    john

  • #2
    Check the Javadoc. You can inject a custom AuthenticationDetailsSource into the filter.

    Comment


    • #3
      Thanks for the reply Luke. I know there's a method to inject the custom class, but my question is: how do I invoke it? Or more precisely: can I invoke that method on the default, existing BasicAuthenticationFilter?

      At the moment I've tried creating a custom filter thus:


      Code:
          <beans:bean id="myWebAuthenticationDetails" class="my.security.MyWebAuthenticationDetails"/>
              
          <beans:bean id="myWebAuthenticationDetailsSource" class="my.security.myWebAuthenticationDetailsSource">
              <beans:property name="clazz" ref="myWebAuthenticationDetails" />
          </beans:bean>
                           
          <beans:bean id="myBasicAuthFilter"
              class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
              <beans:property name="authenticationDetailsSource" ref="myWebAuthenticationDetailsSource" />
              <beans:property name="authenticationManager" ref="authenticationManager" />
              <beans:property name="authenticationEntryPoint" ref="myBasicAuthFilterEntryPoint" />
          </beans:bean>
      But when that runs, I get "[my.security.MyWebAuthenticationDetails]: No default constructor found", and when I add a constructor, I get an null pointer exception.

      I'm very new to this and I think I'm doing more than I need to. Any helpful hints are much appreciated!

      -john

      Comment


      • #4
        Actually, just by writing that I got an idea of how to fix it, and it's working

        I removed the references to "myWebAuthenticationDetails" e.g.

        Code:
            <!-- 
            <beans:bean id="myWebAuthenticationDetails" class="my.security.myWebAuthenticationDetails"/>
                 -->
            <beans:bean id="myWebAuthenticationDetailsSource" class="my.security.myWebAuthenticationDetailsSource">
            <!-- 
                <beans:property name="clazz" ref="myWebAuthenticationDetails" />
                 -->
            </beans:bean>
        and instead set it in the myWebAuthenticationDetailsSource constructor:

        Code:
        	public MyWebAuthenticationDetailsSource() {
        		super.setClazz(MyWebAuthenticationDetails.class);
        	}
        The MyWebAuthenticationDetails class does this:

        Code:
        	@Override
        	protected void doPopulateAdditionalInformation(HttpServletRequest request) {
        		super.doPopulateAdditionalInformation(request);
        		
        		additionalHeaders = new HashMap<String, String>();
        
        		Enumeration<String> allHeaders = request.getHeaderNames();
        		while (allHeaders.hasMoreElements()) {
        			String header = allHeaders.nextElement();
        			additionalHeaders.put(header.toUpperCase(), request.getHeader(header));
        		}
        	}
        and now in my custom AuthenticationProvider authentication.getDetails() is returning the custom class, and I can see the headers.

        I'd still like to know if there's an easier solution though, that just makes use of the existing configuration

        Cheers, john

        Comment


        • #5
          The method is

          Code:
          Object buildDetails(Object context)
          All you have to do is implement that, cast the argument to an HttpServletRequest and return whatever you want.

          Comment


          • #6
            Ah OK, thanks - I'll give that a try.

            But what I would really like to be clear on: do I actually need to implement my own filter? Or can I inject MyWebAuthenticationDetailsSource into the current configuration?

            Cheers! John

            Comment


            • #7
              There is a setter for the authenticationDetailsSource, so you can just inject your custom AuthenticationDetailsSource.

              Comment


              • #8
                Thanks for the reply. What I am failing to understand is how - or even if - I can get that method to be called on the BasicAuthenticationFilter that Spring Security creates when I use "<http-basic />", supplying my custom WebAuthenticationDetailsSource.

                What would be great is to use Spring Security's default configuration, but simply supply a customised WebAuthenticationDetailsSource which gets the extra headers. If someone can tell me that's not possible, then I'm happy to use my own filter, but I'd like to be able to tell my boss that that's the case.

                Cheers, john

                Comment


                • #9
                  I don't think that's supported in the namespace for <http-basic />. You can just declare the filter as a bean and use the <custom-filter /> element to point to the bean.

                  Comment


                  • #10
                    OK, thanks Luke - that's what I was after.

                    Using basic auth and getting the extra headers is working using a custom filter. I will post what I've done here once I've narrowed it down to the minimum.

                    Cheers, john

                    Comment


                    • #11
                      Hi all,

                      I took Luke's advice which allowed me to simplify things a little.

                      When we use basic authentication we need to look at certain custom headers during authentication, as well as the standard "x-forwarded-for" header. Here's how to make all the headers available in a custom AuthenticationProvider.

                      Create a custom WebAuthenticationDetails

                      Code:
                      public class MyWebAuthenticationDetails extends WebAuthenticationDetails {
                      
                      	private Map<String, String> additionalHeaders;
                      
                      	public MyWebAuthenticationDetails(HttpServletRequest request) {
                      		super(request);
                      	}
                      
                      	@Override
                      	protected void doPopulateAdditionalInformation(HttpServletRequest request) {
                      		super.doPopulateAdditionalInformation(request);
                      		
                      		additionalHeaders = new HashMap<String, String>();
                      
                      		Enumeration<String> allHeaders = request.getHeaderNames();
                      		while (allHeaders.hasMoreElements()) {
                      			String header = allHeaders.nextElement();
                      			additionalHeaders.put(header, request.getHeader(header));
                      		}
                      	}
                      
                      	public Map<String, String> getAdditionalHeaders() {
                      		return additionalHeaders;
                      	}
                      }
                      Create a custom WebAuthenticationDetailsSource that uses the above class:
                      Code:
                      public class MyWebAuthenticationDetailsSource extends
                      		WebAuthenticationDetailsSource {
                      
                      	@Override
                      	public Object buildDetails(Object context) {
                      		return new MyWebAuthenticationDetails((HttpServletRequest)context);
                      	}
                      }
                      Specify a new filter using the above class:

                      Code:
                          <beans:bean id="myWebAuthenticationDetailsSource" class="my.security.MyWebAuthenticationDetailsSource"/>
                      
                          <beans:bean id="myBasicAuthFilterEntryPoint"
                                  class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">  
                              <beans:property name="realmName" value="Spring Security Application" />
                          </beans:bean>
                      
                          <beans:bean id="myBasicAuthFilter"
                              class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
                              <beans:property name="authenticationDetailsSource" ref="myWebAuthenticationDetailsSource" />
                              <beans:property name="authenticationManager" ref="authenticationManager" />
                              <beans:property name="authenticationEntryPoint" ref="myBasicAuthFilterEntryPoint" />
                          </beans:bean>
                      Add the authentication manager section that specifies the filter:


                      Code:
                          <http entry-point-ref="myBasicAuthFilterEntryPoint" >
                              <intercept-url pattern="/rest/*" access="ROLE_USER" />
                             <custom-filter position="BASIC_AUTH_FILTER" ref="myBasicAuthFilter"/> 
                          </http>
                      And I think that's it

                      If anyone notices anything dodgy about that, please let me know. If I find any problems I'll post back, but it's all looking promising

                      Cheers, john
                      Last edited by johnnywintermute; Dec 14th, 2010, 04:05 AM.

                      Comment


                      • #12
                        Many Thanks! Worked like a charm!

                        Comment

                        Working...
                        X