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

  • PreAuthentication URL

    In our application, users are authenticated by an external resource. We only receive a certain value in the header, so we can lookup certain information regarding that particular user. We don't have to do any password verification.

    I've been playing around with my configuration, but something isn't clear. I created a servlet to simulate the external resource. This servlet will add a certain value to the header, so Spring Security can extract it and lookup information regarding that user. The problem is, to which URL does the servlet has to redirect. In a standard procedure, the AuthenticationProcessingFilter listens to /j_spring_security_check. Since there is no AuthenticationProcessingFilter, I can't configure the URL.

    Is it possible to give me some more information about this? I'm using the RequestHeaderPreAuthenticatedProcessingFilter, since that is also used for the example.

    Configuration:
    Code:
    <security:authentication-manager alias="authenticationManagerAlias" />
    	
    <security:http auto-config="false">
    	<security:intercept-url pattern="/private/**" access="ROLE_USER" />
    </security:http>
    	
    <security:authentication-provider>
    	<security:user-service>
    		<security:user name="test" password="test" authorities="ROLE_USER" /> 
    	</security:user-service>
    </security:authentication-provider>
    
    <bean id="preAuthenticatedProcessingFilter" class="org.springframework.security.ui.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter">
    	<security:custom-filter position="PRE_AUTH_FILTER" />
    	<property name="principalRequestHeader" value="USERNAME" />
    	<property name="" value="authenticationManager" ref="authenticationManagerAlias" />
    </bean>

  • #2
    I am in the exact same situation, any solutions/suggestions to this problem will be greatly appreciated. I couldn't find any sample applications that use pre-authentication scenarios in which spring security reads the authenticated username from request headers.
    Please help,
    robin

    Comment


    • #3
      The point of pre-authentication is that it assumes the user has already been authenticated and that the user information (header, request parameter, whatever) is made available by that system, whatever the request. So the URL doesn't matter. The pre-authentication filter will attempt to extract the user information if the user isn't already authenticated (from Spring Security's perspective - i.e. the security context is empty).

      Comment


      • #4
        Thanks for the response. The external authentication system (Tivoli Identity/Access Manager) that we are relying upon will set the http request header named "iv-user" in our case. In development mode, I am trying to "mock" that system by calling a filter before calling springSecurityFilterChain and Spring MVC Dispatcher Servlet. This filter will set the http request header , and then pass the control on to the next filter/servlet.

        The problem I am facing with this approach is I cannot find out how to set
        the request header
        in a filter since HttpServletRequest class does not provide any setHeader() method.

        Is there any recommended way to handle this situation. and can you confirm the above mentioned mock approach is going to work.. (off any previous experience etc.)

        My Spring context file looks as follows...

        Code:
        <global-method-security secured-annotations="enabled">
        	</global-method-security>
        
        	<http>
        		<intercept-url pattern="/secure/extreme/**"
        			access="ROLE_SUPERVISOR" />
        		<intercept-url pattern="/secure/**"
        			access="ROLE_SUPERVISOR,ROLE_USER" />
        		<intercept-url pattern="/faces/policysearch*"
        			access="ROLE_SUPERVISOR,ROLE_USER" />
        	</http>
        	
        	<beans:bean id="preAuthenticatedProcessingFilter"
        		class="org.springframework.security.ui.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter">
        		<custom-filter position="PRE_AUTH_FILTER" />
        		<beans:property name="principalRequestHeader" value="iv-user" />
        		<beans:property name="authenticationManager"
        			ref="authenticationManager" />
        	</beans:bean>
        	
        	<authentication-manager alias="authenticationManager" />
        	<authentication-provider>
        		<user-service>
        			<user name="super" password="super"
        				authorities="ROLE_SUPERVISOR" />
        			<user name="scott" password="scott" authorities="ROLE_USER" />
        			<user name="mark" password="mark" authorities="ROLE_USER"
        				disabled="true" />
        			<user name="base" password="base" authorities="ROLE_BASE" />
        		</user-service>
        	</authentication-provider>
        My web.xml looks as follows.

        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <web-app ...
        	<display-name>My Application Name</display-name>
        	<listener>
        		<listener-class>
        			org.springframework.web.context.ContextLoaderListener
        		</listener-class>
        	</listener>
        
                      ......
        	
        		<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>
        
        	<!-- Serves static resource content from .jar files such as spring-faces.jar -->
        	<servlet>
        		<servlet-name>Resources Servlet</servlet-name>
        		<servlet-class>
        			org.springframework.js.resource.ResourceServlet
        		</servlet-class>
        		<load-on-startup>0</load-on-startup>
        	</servlet>
        
        	<!-- Map all /resources requests to the Resource Servlet for handling -->
        	<servlet-mapping>
        		<servlet-name>Resources Servlet</servlet-name>
        		<url-pattern>/resources/*</url-pattern>
        	</servlet-mapping>
        
        	<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
        	<servlet>
        		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        		<servlet-class>
        			org.springframework.web.servlet.DispatcherServlet
        		</servlet-class>
        		<init-param>
        			<param-name>contextConfigLocation</param-name>
        			<param-value></param-value>
        		</init-param>
        		<load-on-startup>2</load-on-startup>
        	</servlet>
        
        	<!-- Map all /spring requests to the Dispatcher Servlet for handling -->
        	<servlet-mapping>
        		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        		<url-pattern>/spring/*</url-pattern>
        	</servlet-mapping>
        </web-app>

        Comment


        • #5
          Use a mock request object, such as the one in spring-test or a separate web client (e.g. httpunit).

          Comment


          • #6
            Okay I reverted back my code to a working case of form-login based authentication and <user-service> (inMemory) authorization model.
            Now I am making one change at a time to make it work with Pre-Authentication scenario.
            I have written a Mock authentication filter that's I intend to put first in the filter chain so that it adds a http request header named
            "iv-user" which the Spring Security's preAuthenticatedProcessingFilter will be able to read from.
            But before I change my securityContext.xml to bring in preAuthenticatedProcessingFilter, I am noticing some issues.

            The MockAuthFilter is being hit now (as mentioned above, MockAuthFilter just sets http request header named "iv-user" with a "user-name" that is defined
            in spring securityContext.xml under <user-service>)
            Here's my web.xml setup ..
            Code:
            	<filter-mapping>
            		<filter-name>mockAuthFilter</filter-name>
            		<url-pattern>/*</url-pattern>
            	</filter-mapping>	
            	
            	<filter-mapping>
            		<filter-name>springSecurityFilterChain</filter-name>
            		<url-pattern>/*</url-pattern>
            	</filter-mapping>
            	
            	.......
            	..
            	.
            	
            	<!-- Servlets -->
            	<!-- Serves static resource content from .jar files such as spring-faces.jar -->
            	<servlet>
            		<servlet-name>Resources Servlet</servlet-name>
            		<servlet-class>
            			org.springframework.js.resource.ResourceServlet
            		</servlet-class>
            		<load-on-startup>0</load-on-startup>
            	</servlet>
            	
            	<servlet>
            		<servlet-name>Faces Servlet</servlet-name>
            		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
            		<load-on-startup>1</load-on-startup>
            	</servlet>
            
            	<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
            	<servlet>
            		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
            		<servlet-class>
            			org.springframework.web.servlet.DispatcherServlet
            		</servlet-class>
            		<init-param>
            			<param-name>contextConfigLocation</param-name>
            			<param-value></param-value>
            		</init-param>
            		<load-on-startup>2</load-on-startup>
            	</servlet>
            	
            	<!-- Servlet mappings -->
            	<servlet-mapping>
            		<servlet-name>Faces Servlet</servlet-name>
            		<url-pattern>*.faces</url-pattern>
            	</servlet-mapping>
            	
            	<servlet-mapping>
            		<servlet-name>Resources Servlet</servlet-name>
            		<url-pattern>/resources/*</url-pattern>
            	</servlet-mapping>
            	
            	<servlet-mapping>
            		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
            		<url-pattern>/spring/*</url-pattern>
            	</servlet-mapping>
            Here's the code for my Mock Authentication Filter..

            Code:
            public class MockAuthFilter implements Filter{
            	private FilterConfig filterConfig = null;
            	private static String loggedInUserName = "super"; 
            	private static String httpRequestHeaderName = "iv-user";
            	private Logger logger =Logger.getLogger(MockAuthFilter.class);
            	public void destroy() {
            		logger.debug("entered MockAuthFilter.destroy() method");
            		this.filterConfig = null;
            		logger.debug("exited MockAuthFilter.destroy() method");
            	}
            	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            		logger.debug("entered MockAuthFilter.doFilter() method");
            		if(this.filterConfig.getServletContext()==null){
            			logger.debug("this.filterConfig.getServletContext()== NULL !!");
            		}
            		MockHttpServletRequest mockRequest = new MockHttpServletRequest(this.filterConfig.getServletContext());
            		
            		if(mockRequest.getHeader(httpRequestHeaderName)==null || !mockRequest.getHeader(httpRequestHeaderName).equalsIgnoreCase(loggedInUserName)){
            			mockRequest.addHeader(httpRequestHeaderName, loggedInUserName);	
            		}
            		logger.debug("exited MockAuthFilter.doFilter() method");
            		chain.doFilter(mockRequest, response);
            	}
            
            	public void init(FilterConfig arg0) throws ServletException {
            		logger.debug("entered MockAuthFilter.init() method");
            		this.filterConfig = arg0;
            		logger.debug("exited MockAuthFilter.init() method");
            	}
            }
            I have two separate webapplication paths of interest in this application and both are having separate set of issues.
            I would like to get issues with (1) resolved first.

            1) /secure/* containing simple index.jsp (/secure/index.jsp) [this is simple /secure/index.jsp from spring security sample "tutorial" application)
            2) /spring/* containing my spring web flow related flows. (all setup according to what is described in spring web flow docs - JSF integration section)

            When webAppRoot/index.jsp (my unprotected index page) is visited, and I click on the link to visit /secure/index.jsp,
            my MockAuthFilter is successfully hit and /secure/index.jsp can print out the request header using this code block..
            Code:
            <authz:authorize ifAnyGranted="ROLE_SUPERVISOR,ROLE_USER">
            	ONLY USERS OF ROLE_SUPERVISOR OR ROLE_USER will see this message.
            	Logged In UserName: <font size="6" style="bold" color="blue"><authz:authentication property="name" /></font> 
            </authz:authorize>
            
            <h2>Request header values</h2>
            <c:forEach var="req" items="${header}">
            <strong> <c:out value="${req.key}"/></strong>: <c:out value="${req.value}"/> <br/>
            </c:forEach>
            CASE -1
            Now the issue is when I put the MockAuthFilter first and springSecurityFilterChain second in my web.xml

            The only output I get is ((in this case, spring <authorize> tag DOES NOT WORK)
            iv-user: super

            CASE-2
            but If I reverse the order I get the following output .. (in this case, spring <authorize> tag WORKS)

            ONLY USERS OF ROLE_SUPERVISOR OR ROLE_USER will see this message.
            Logged In UserName: super

            iv-user: super



            So I figured that's the order in which I need to keep my filters to make both the filters work.
            The problem is, If I keep springSecurityFilterChain first and MockAuthFilter second ,
            and then change my securityContext.xml to make the pre-Authentication Sceario work ...

            Here's my securityContext.xml code
            Code:
            <beans:beans ....">
            
            	<global-method-security secured-annotations="enabled">
            	</global-method-security>
            
            	<http entry-point-ref="preAuthenticatedProcessingFilterEntryPoint">
            		<intercept-url pattern="/secure/*"
            			access="ROLE_SUPERVISOR,ROLE_USER" />
            		<intercept-url pattern="/spring/*"
            			access="ROLE_SUPERVISOR,ROLE_USER" />
            	</http>
            	
            	
               <beans:bean id="preAuthenticatedProcessingFilterEntryPoint"
                        class="org.springframework.security.ui.preauth.PreAuthenticatedProcessingFilterEntryPoint"/> 
                        
            	<beans:bean id="preAuthenticatedProcessingFilter"
            		class="org.springframework.security.ui.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter">
            		<custom-filter position="PRE_AUTH_FILTER" />
            		<beans:property name="principalRequestHeader" value="iv-user" />
            		<beans:property name="authenticationManager"  ref="authenticationManager" />
            	</beans:bean>
            	
            	<authentication-manager alias="authenticationManager" />
            	
            	<authentication-provider>
            		<user-service>
            			<user name="super" password="super" authorities="ROLE_SUPERVISOR" />
            		</user-service>
            	</authentication-provider>   
            </beans:beans>
            When I revisit the /secure/index.jsp page, I get the exception :
            Code:
            [04/07/08 16:08:34:108 EDT] 00000021 WebApp        E   [Servlet Error]-[Filter [springSecurityFilterChain]: filter is unavailable.]: org.springframework.security.ui.preauth.PreAuthenticatedCredentialsNotFoundException: iv-user header not found in request.
            	at org.springframework.security.ui.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter.getPreAuthenticatedPrincipal(RequestHeaderPreAuthenticatedProcessingFilter.java:42)
            	at org.springframework.security.ui.preauth.AbstractPreAuthenticatedProcessingFilter.doAuthenticate(AbstractPreAuthenticatedProcessingFilter.java:69)
            	at org.springframework.security.ui.preauth.AbstractPreAuthenticatedProcessingFilter.doFilterHttp(AbstractPreAuthenticatedProcessingFilter.java:58)
            	at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
            	at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
            	at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
            	at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
            This means i am in a catch-22 situation, if I put the mockAuthFilter before springSecurityFilterChain, spring <authorize> tag won't work, If I keep it second (after SpringSecurityFilterChain) I will get the above exception, what should i do in this case, please help,... ??

            Comment


            • #7
              Sorry for posting in an old topic again, but I have some questions regarding pre authentication.

              We also use Tivoli, but for the moment we use a form login as a stub (as a temporary solution). Now, from what I've read, I assume that for every request, the header is added to the request. But what happens behind the screens?

              In a normal flow (with form authentication), a form is submitted and validated. When a corresponding user is found, Spring security creates an authenticated session (WebApplicationContext().getContext() blabla) and redirects the user.

              But how does this flow work with an external source which authenticates the user. Does it work the same way (so authenticated session is created, with an authenticationtoken), or is it different?

              Comment


              • #8
                There is no "flow" with preauthentication. It's really very simple - if a request comes in, the framework will attempt to extract the appropriate information (header, X.509 certificate, whatever) and create an authentication object. It will load information such as roles from a UserDetailsService (or extract the from the request if they are available).

                There is no interaction with the external system in terms of asking it to authenticate the user or anything like that. But once the Authentication is created, everything is the same as if the authentication process had taken place entirely within the framework.
                Last edited by Luke Taylor; Aug 1st, 2008, 07:42 AM.

                Comment


                • #9
                  Just wanted to add a few tips that I found very useful with testing/running in pre-authenticated mode.

                  In addition to the MockHttpServletRequest approach for developers who don't have access to the pre-authenticator in the development environment you don't need a front controller/filter of some sort to insert your token. Alternatively, you can just subclass RequestHeaderPreAuthenticatedProcessingFilter and add functionality for a developer mode, for example let them set their username at build time. This way they can login as whoever they want with each build/deploy. As mentioned once Spring Security has just that username your in and behaving just like a normal authenticated client. I prefer the mock approach but it's an alternative.

                  Second if you don't set the username as above you can still test your roles with the modify headers plugin. It also seems to me that pre-authenticated mode is very useful to setup to test/eyeball roles whether your using pre-authentication or not. You can find the plugin here, https://addons.mozilla.org/en-US/firefox/addon/967.

                  Finally, I have to say I was very pleased with the rewrite, the docs are still a bit bare but the new schema approach is very powerful and I was able to bang out an additional layer of security for our application in very short order. Nice work.
                  Last edited by skroah; Aug 1st, 2008, 10:21 AM.

                  Comment


                  • #10
                    I reverted my application and now I want to use the PreAuthentication process. I don't have access to TAM, so I have to use a mock/stub to simulate the behaviour.

                    I added Spring-mock as a dependency, but the problem is that I'm getting an error when I launch my application.

                    I just copied Robinbajaj's code, so it's pretty much the same. When I fire up Tomcat, i get the following error:

                    HTTP Status 501 - Method is not defined in RFC 2068 and is not supported by the Servlet API
                    The code of my Filter:

                    Code:
                    	private FilterConfig filterConfig = null;
                    	
                    	public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; }
                    	public void destroy() { filterConfig = null; }
                    
                    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
                    	{
                    		MockHttpServletRequest mockRequest = new MockHttpServletRequest(this.filterConfig.getServletContext());
                    		mockRequest.addHeader("FT_USER", "adminuser");
                    		chain.doFilter(mockRequest, response);
                    	}
                    Does anyone have an idea why this errormessage is shown? Also, is Spring-mock an official release? I've found the release in Maven, but I haven't found any information about it on other webpages (even springframework.org).

                    Comment


                    • #11
                      The error message is occurring because you haven't set the HTTP method (POST, GET) etc on the request (hint: try using google when you have an error message, that's how I found the answer).

                      I wouldn't use a mock request object within an actual deployed application - you are better to extend the standard request wrapper class and override the getHeaders method to add what you want. That way the rest of the data from the original request is retained.

                      Something like a browser plugin might be a better option though, as suggested above, if you are running against a deployed app as it will cut down the differences between your development and production systems.

                      Alternatively you could write a simple tomcat Valve implementation for your development server - you then have the ability to modify the request object directly.

                      Comment


                      • #12
                        Browser plugin is no option I'm afraid, so I'll have to stick with the Mock object. Thanks for the information, I'll see what I can do.

                        Comment


                        • #13
                          exact same issue reported earlier with no solution...

                          I posted an exact same issue earlier (with slightly different setup but still using spring security preauth) with no solutions so far.. Here's the post -
                          http://forum.springframework.org/showthread.php?t=57164
                          I would appreciate if you can post you solution if you figure this one out.. i am currently working on another piece right now, if I get any free cycles and revisit this issue, (and get it working) , i will be sure to put my code snippets..
                          -thanks
                          robin

                          Comment


                          • #14
                            Well, I didn't solve it. I just changed the way we handle everything.

                            What we have is that users can have a different role, based on their user profile. In our application, we have 3 types of users (regular and 2 types of administrator). We also have multiple test profiles in our database, so we can automate our tests for Selenium and also change users to test the functionality while we are developing.

                            At the client, TAM is used to authenticate the user and for each request, the userid is added to the header, together with some extra data for the verification. To be able to test everything, I came up with a rather weird solution .

                            We're at our development center for the moment, so we don't have access to TAM. But to be able to test everything, with the different kind of profiles, I created a sort of login page with a dropdownlist that contains all the possible profiles. This page resides under an unprotected link (just add <security:intercept-url pattern="/public/login.jsp" filters="none" /> to your <http>-element).

                            This page contains a form, which is submitted to a Servlet. In that servlet we take the userID, add it to the session and redirect the user to a protected resource. We also made a class which extends AbstractPreAuthenticatedProcessingFilter and overrides the getPreAuthenticatedPrincipal-method. Instead of checking the header, we just get the Userid from the session (the value we added in our servlet).

                            I know this seems kind of weird, but this way we can just replace our implementation of the AbstractPreAuthenticatedProcessingFilter with the one Spring provided and we don't have to do anything anymore to make it work with TAM (at least, that's what we hope ). But overhere, we do need a sort of login mechanism, to run our tests.

                            The following problem is logging out. When a user is logged in the way I described, the user id is added to the session and redirect happens to the protected resource. Spring-Security kicks in and checks the session, creates the authentication and redirects the user to the desired page.

                            But how do we logout a user? I thought that the headers were checked _every_ request, but that's not true. Because when I just browse to the login page, login again, the credentials of the previous user are still there. Is there a workaround? I know this is mixing up 2 ways of logging in, but I want to make this work.

                            When I get the current context from the SecurityHolder, the authentication is null.

                            Comment


                            • #15
                              Originally posted by Bjorn121 View Post
                              But how do we logout a user? I thought that the headers were checked _every_ request, but that's not true. Because when I just browse to the login page, login again, the credentials of the previous user are still there. Is there a workaround? I know this is mixing up 2 ways of logging in, but I want to make this work.
                              If you have logged out and invalidated the session then the previous credentials aren't still there. Do you have some evidence from a log file?

                              Comment

                              Working...
                              X