Announcement Announcement Module
Collapse
No announcement yet.
Mocking Siteminder Authentication Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Mocking Siteminder Authentication

    Hi,

    Our planned security model will consist of Siteminder for authentication and Spring security then for authorization.

    Our Siteminder configuration will work exactly as documented in the Spring 2 reference guide:

    Code:
    <bean id="siteminderFilter"
    class="org.springframework.security.ui.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter">
    <security:custom-filter position="PRE_AUTH_FILTER" />
    <property name="principalRequestHeader" value="SM_USER"/>
    <property name="authenticationManager" ref="authenticationManager" />
    </bean>
    <bean id="preauthAuthProvider"
    class="org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider">
    <security:custom-authentication-provider />
    <property name="preAuthenticatedUserDetailsService">
    <bean id="userDetailsServiceWrapper"
    class="org.springframework.security.userdetails.UserDetailsByNameServiceWrapper">
    <property name="userDetailsService" ref="userDetailsService"/>
    </bean>
    </property>
    </bean>
    <security:authentication-manager alias="authenticationManager" />
    This will work fine on servers where we have Siteminder configured. However, on a developer's machine we may wish to configure this such that the Siteminder configuration is "mocked" but the authorization may still occur using a mocked implementation of the "userDetailsService" (or other such scenarios).
    How would we achieve this best based on the configuration above?
    Would it be a case of extending the RequestHeaderPreAuthenticatedProcessingFilter to return whatever value I want?

    Thanks.
    Last edited by spitbag; May 13th, 2010, 05:29 PM.

  • #2
    From reviewing the security source code I may be able to answer my own question.

    A mock setup may be achievable by extending the RequestHeaderPreAuthenticatedProcessingFilter and overwriting the getPreAuthenticatedPrincipal method to return a corpID from a customizable properties file.
    A mock version of the UserDetailsService could then be implemented if needs be to read roles from a similar developer-controlled properties file.

    Would this be the best way to go?

    Comment


    • #3
      OK, I've attempted this and I'm running into some problems running unit tests.

      Initially when I tried to unit test my new RequestHeaderPreAuthenticatedProcessingFilterMock class the tests failed as it complained that an authentication manager wasn't set.

      I'm not interested in setting up an authentication manager though for my unit tests as I just want to test the new code in my mock class.

      However, when I attempt to mock out my parent RequestHeaderPreAuthenticatedProcessingFilter class using EasyMock I'm told:

      Error creating bean with name 'mockFilter' .... No matching factory method found: factory method 'createMock'

      I don't really understand what is happening here, why is it attempting to call createMock on my mockFilter class?

      This is the code for my mock class:

      Code:
      mport java.util.Properties;
      
      import javax.servlet.http.HttpServletRequest;
      
      import org.springframework.security.ui.preauth.PreAuthenticatedCredentialsNotFoundException;
      import org.springframework.security.ui.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter;
      
      public class RequestHeaderPreAuthenticatedProcessingFilterMock extends RequestHeaderPreAuthenticatedProcessingFilter
      {
      	// CORPID is what the Siteminder header is set to, and will be specified in the configuration of the default filter class
      	private String principalRequestHeader = "CORPID"; 
      	private Properties properties;
      	
      	protected Object getPreAuthenticatedPrincipal(HttpServletRequest request)
      	{
      		// Read the principal name from the propertiess file instead of the request header
      		String principal = properties.getProperty(principalRequestHeader); 
      		
      		if (principal == null || principal.length() == 0) {
      			throw new PreAuthenticatedCredentialsNotFoundException(principalRequestHeader 
      					+ " header not found in request.");
      		}
      
      		return principal;
      	}
      
      	public void setPrincipalRequestHeader(String principalRequestHeader) {
      		this.principalRequestHeader = principalRequestHeader;
      	}
      
      	public void setProperties(Properties properties) {
      		this.properties = properties;
      	}	
      	
      }
      And this is my Spring configuration:

      Code:
      <bean id="mockFilterParent" class="org.easymock.EasyMock" factory-method="createMock">
      	      <constructor-arg index="0" value="org.springframework.security.ui.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter"/>
      </bean>
      
      <bean id="propertiesFile" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
      		<property name="location" value="classpath:profiles.properties"/>
      </bean>
      
      <bean id="mockFilter" class="com.abc.def..security.spring.filter.RequestHeaderPreAuthenticatedProcessingFilterMock" parent="mockFilterParent">
      		<property name="properties" ref="propertiesFile"/>
      	</bean>
      Where am I going wrong here?

      Thanks.

      Comment


      • #4
        I think your problem has to do with the definition you have for your mockFilter bean. You have a 'parent' attribute that points back to 'mockFilterParent', which defines a factory method. Your 'mockFilter' bean definition will effectively inherit the definition of its parent (including properties) and allow you to override things like the class definition.

        That said, I ran into a similar problem and decided to resolve it a different way. The challenge was to test that all the mechanics worked without having Siteminder in the mix. To accomplish that, I needed to inject the appropriate header values - or at least ensure that they were there when the preauthentication filter was hit.

        I did this by creating a Servlet filter that sits in front of the springSecurityFilterChain (DelegatingFilterProxy). Here is what my class looks like.

        Code:
        public class EauthMockFilter implements Filter {
           private Log log = LogFactory.getLog(EauthMockFilter.class);
           private FilterConfig filterConfig;
        	
           @Override
           public void destroy() {
              this.filterConfig = null;
           }
        
           /**
            * The <code>doFilter</code> method is called by the container each time 
            * a request/response pair is passed through the chain due to a client 
            * request for a resource at the end of the chain.
            * This implementation will intercept the request and 'wrap' it with the
            * custom request wrapper defined below such that the 'getHeader' 
            * method can return the configured value when the 'SITEMINDER_ID'
            * header value is requested.
            */
           @Override
           public void doFilter(ServletRequest request, ServletResponse response,
          		    FilterChain chain) throws IOException, ServletException {
              // Hijack the request and make sure my version of getHeader gets called
              MyRequestWrapper myRequest = new MyRequestWrapper((HttpServletRequest)request, filterConfig );
              chain.doFilter(myRequest, response);
           }
        
           @Override
           public void init(FilterConfig filterConfig) throws ServletException {
              this.filterConfig = filterConfig;
           }
        
           public void setFilterConfig(FilterConfig filterConfig) {
              this.filterConfig = filterConfig;
           }
        
           public FilterConfig getFilterConfig() {
              return filterConfig;
           }
        
           /**
            * This wrapper allows the ability to intercept the 'getHeader' method such
            * that the a header for 'SITEMINDER_ID' can be effectively injected into
            * the request so that the pre-authenticaton filter can get it.
            *
            */
           class MyRequestWrapper extends HttpServletRequestWrapper {
              FilterConfig myFilterConfig;
              String siteminderId;
              String firstName;
              String lastName;
              String emailAddress;
        
              public MyRequestWrapper(HttpServletRequest request, FilterConfig filterConfig) {
                 super(request);
                 myFilterConfig = filterConfig;
                 siteminderId = (filterConfig.getInitParameter("SITEMINDER_ID")!=null) ? filterConfig.getInitParameter("SITEMINDER_ID") : new String();
                 firstName = (filterConfig.getInitParameter("FIRST_NAME")!=null) ? filterConfig.getInitParameter("FIRST_NAME") : new String(); 
                 lastName = (filterConfig.getInitParameter("LAST_NAME")!=null) ? filterConfig.getInitParameter("LAST_NAME") : new String(); 
                 emailAddress = (filterConfig.getInitParameter("EMAIL_ADDR")!=null) ? filterConfig.getInitParameter("EMAIL_ADDR") : new String();
              }
        	
              /**
               * The main purpose of this method is to mock up the handling of the 'SITEMINDERID'
               * header variable. When this value is requested, a value is returned based on the
               * configured init param for the filter. If that value isn't set, then all requests
               * are passed off to the super.
               * 
               * @param name The name of the header variable to get
               * 
               * @return a <code>String</code> containing the value of the requested header, or null if the request does not have a header of that name 
               */
              public String getHeader(String name) {
                 if ("SITEMINDERID".equals(name)) {
                    return siteminderId;
                 } else if ("FIRSTNAME".equals(name)) {
                    return firstName; 
                 } else if ("LASTNAME".equals(name)) {
                    return lastName;
                 } else if ("EMAIL".equals(name)) {
                    return emailAddress;
                 } else {
                    return super.getHeader(name);
                 }
              }
           }
        }
        Then in my web.xml file, I created the following definition
        Code:
         <filter>
          <description>To enable, set url pattern for filter to '/*'. To disable, set to '/disabled'</description>
          <filter-name>EauthMockFilter</filter-name>
          <filter-class>gov.usda.swed.common.security.ui.EauthMockFilter</filter-class>
          <init-param>
           <param-name>SITEMINDER_ID</param-name>
           <param-value>999999190010931451093</param-value>
          </init-param>
          <init-param>
           <param-name>FIRST_NAME</param-name>
           <param-value>Mark</param-value>
          </init-param>
          <init-param>
           <param-name>LAST_NAME</param-name>
           <param-value>Secrist</param-value>
          </init-param>
          <init-param>
           <param-name>EMAIL_ADDR</param-name>
           <param-value>mark.secrist@some_email.com</param-value>
          </init-param>
         </filter>
        The critical thing is to make sure the filter definition AND mapping are before the security filter definition and mapping.

        I used the filter config parameters as the way to pass the pre-defined values but you could just as easily write this to use a property file.

        I also used the filter mapping definition to turn on and off the filter as follows.

        Code:
         <filter-mapping>
          <filter-name>EauthMockFilter</filter-name>
          <url-pattern>/*</url-pattern>
         </filter-mapping>
        or
        Code:
         <filter-mapping>
          <filter-name>EauthMockFilter</filter-name>
          <url-pattern>/disabled</url-pattern>
         </filter-mapping>
        I hope this works for you. It takes a little time to get the initial filter set up and working but I use it on all my projects where I need a mock filter for local testing.

        Best regards,

        Mark

        Comment


        • #5
          I see thanks, didn't realize I can easily add another filter before the Spring Security filters. This should work nicely so.

          Comment

          Working...
          X