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

  • Overriding AUTHENTICATION_PROCESSING_FILTER

    Running Spring Security version 2.0.2, I'm trying to override the default authentication processing filter, and am getting this error:
    Code:
    Filters 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]'
    and 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]'
    have the same 'order' value. When using custom filters, please make sure the positions do not conflict with default filters.
    Alternatively you can disable the default filters by removing the corresponding
    child elements from <http> and not avoiding the use of <http auto-config='true'>.
    First: should that error say "and AVOIDING the use of..." (instead of "not avoiding...")

    Second: Section 2.3.5 of the reference doc seems to imply that I can override an existing filter using the <custom-filter> tag. Is that not right?

    Third: Do I need to remove the http form-login element? If I do, what would the replacement look like? (how do I figure out which beans form-login is creating for me?)

    Here's the file that's not working:
    Code:
    <?xml version="1.0" encoding="ISO-8859-1"?>
    
    <!-- Spring Security settings for rexa-front -->
    
    <beans:beans xmlns=...standard stuff from documentation...>
    
      <authentication-manager alias="authenticationManager"/>
      <beans:bean id="foo" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
        <beans:property name="authenticationManager">
          <beans:ref bean="authenticationManager"/>
        </beans:property>
        <beans:property name="defaultTargetUrl" value="/" />
        <beans:property name="targetUrlResolver">
          <beans:bean id="targetUrlResolver" class="org.springframework.security.ui.TargetUrlResolverImpl">
            <beans:property name="targetUrlParameter" value="returnTo" />
          </beans:bean>
        </beans:property>
        <custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
      </beans:bean>
    
      <http>
        <intercept-url pattern="/foo/**" access="ROLE_USER" />
        <form-login />
        <anonymous />
        <http-basic />
        <logout />
        <remember-me />
      </http>
    
      <beans:bean id="myJdbcDAO"
            class="org.springframework.security.userdetails.jdbc.JdbcDaoImpl">
        <beans:property name="dataSource">
          <beans:ref bean="varDataSource"/>
        </beans:property>
        <beans:property name="usersByUsernameQuery">
          <beans:value>SELECT email AS username, LOWER(password),'true' AS enabled FROM users WHERE email=?</beans:value>
        </beans:property>
        <beans:property name="authoritiesByUsernameQuery">
          <beans:value>SELECT email AS username, 'ROLE_USER' AS authority FROM users WHERE email=?</beans:value>
        </beans:property>
      </beans:bean>
      <authentication-provider user-service-ref="myJdbcDAO">
        <password-encoder hash="sha"/>
      </authentication-provider>
    
    </beans:beans>
    Last edited by gavinandresen; Jun 19th, 2008, 10:25 AM. Reason: Added note on Spring version

  • #2
    Originally posted by gavinandresen View Post
    First: should that error say "and AVOIDING the use of..." (instead of "not avoiding...")
    Yes, you're right. I've corrected the message. In this case the <form-login/> creates an AuthenticationProcessingFilter which is conflicting with the one you've added, so you should remove the tag. You will also need to add an AuthenticationProcessingFilterEntryPoint bean and set the custom-entry-point attribute (on <http>) to point to this.

    Comment


    • #3
      I'm happier now

      Thanks, Luke; it looks like I don't need the AuthenticationProcessingFilterEntryPoint bean, and was REALLY close to having a working xml configuration before.

      Renaming my authentication-manager alias from "authenticationManager" to something else, and removing the <form-login> makes it all work; here's the relevant bits of the config file:
      Code:
        <authentication-manager alias="authenticationManagerAlias"/>
        <beans:bean id="myAuthenticationProcessingFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
          <beans:property name="authenticationManager">
            <beans:ref bean="authenticationManagerAlias"/>
          </beans:property>
          <beans:property name="defaultTargetUrl" value="/" />
          <beans:property name="targetUrlResolver">
            <beans:bean id="targetUrlResolver" class="org.springframework.security.ui.TargetUrlResolverImpl">
              <beans:property name="targetUrlParameter" value="returnTo" />
            </beans:bean>
          </beans:property>
          <custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
        </beans:bean>
      
        <http>
          <!--  Note: can't use auto-config here, because myAuthenticationProcessingFilter replaces the one <form-login> would create: -->
          <intercept-url pattern="/foo/**" access="ROLE_USER" />
          <anonymous />
          <http-basic />
          <logout />
          <remember-me />
        </http>

      Comment


      • #4
        You need an AuthenticationProcessingFilterEntryPoint if you want a user to be automatically prompted to log in when they try to access a secured resource.

        A entry point is required by the namespace and it makes a decision based on what you have configured. In this case, you have basic authentication enabled and a basic authentication prompt will be issued automatically. If you remove the <http-basic/> element the configuration will fail.

        Comment


        • #5
          Originally posted by Luke Taylor View Post
          You need an AuthenticationProcessingFilterEntryPoint if you want a user to be automatically prompted to log in when they try to access a secured resource.

          A entry point is required by the namespace and it makes a decision based on what you have configured. In this case, you have basic authentication enabled and a basic authentication prompt will be issued automatically. If you remove the <http-basic/> element the configuration will fail.
          Is there a way of getting the nifty auto-generated login page? I see that AuthenticationProcessingFilterEntryPoint wants a loginFormUrl...

          Also, the big-picture view of what I'm trying to do is this:

          I've got a website that you can browse without being logged in. If you're not logged in, you can't edit stuff.

          Somewhere on the page, I'll put a "Login..." link (if you're not logged in-- if you are logged in, there will be a You're Logged in as: {foo} and a Logout link).

          What's the best way of creating that Login... link?

          It doesn't really fit into the "you're prompted to login when you try to access a secured resource" way of doing things, so I'm thinking that the Login... link will be a url that looks something like:
          Code:
          /spring_security_login?returnTo=...url_of_current_page...

          Comment


          • #6
            You still need an entry point, even if it's not used.

            You can still use a link to a login page (or have an embedded form in the page template, like the forums here do). I don't really know what you mean by "the best way of creating the link" - it's just a link to whatever page you write as your login page (JSP, controller, whatever). The loginFormUrl should be the same.

            Comment


            • #7
              Originally posted by Luke Taylor View Post
              I don't really know what you mean by "the best way of creating the link" - it's just a link to whatever page you write as your login page (JSP, controller, whatever). The loginFormUrl should be the same.
              OK, I'll break down the "what's the best way of creating the link
              " into two questions:

              1. Can I get the default, auto-generated login page (/spring_security_login) to work the way I want?

              2. Digging into the source code, it looks like I may not need to override the authenticationManager's targetUrlResolver at all-- the default targetUrlResolver looks for the spring-security-redirect url parameter. But using this as my link doesn't work:
              /spring_security_login?spring-security-redirect=...urlencoded-current-url...

              ... because /spring_security_login is POSTing to /j_spring_security_check (and dropping the spring-security-redirect url param).

              So: I'm going to try creating a login page that's just like the default one, except with a hidden field containing the spring-security-redirect param (if it's given), and go back to using <http auto-config="true"> ...

              It would be spiffy if a future version of Spring Security's default login page did that for me.
              Last edited by gavinandresen; Jun 19th, 2008, 01:58 PM. Reason: fix spelling of spring_security_login

              Comment


              • #8
                I have the exact same configuration as you, but I still keep getting that error:

                Code:
                <?xml version="1.0" encoding="UTF-8"?>
                
                <beans xmlns="http://www.springframework.org/schema/beans"
                
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                
                xmlns:security="http://www.springframework.org/schema/security"
                
                xsi:schemaLocation="http://www.springframework.org/schema/beans
                
                http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                
                http://www.springframework.org/schema/security
                
                http://www.springframework.org/schema/security/spring-security-2.0.xsd">
                
                
                <import resource="classpath*:FT-connectivity" />
                
                
                <security:http auto-config="false" entry-point-ref="authenticationEntryPoint">
                
                <security:intercept-url pattern="/private/**" access="ROLE_ENCODER,ROLE_FINANCE_ADMIN,ROLE_GROUP_ADMIN" />
                
                <security:form-login />
                
                <security:anonymous />
                
                <security:http-basic />
                
                <security:logout />
                
                <security:remember-me />
                
                </security:http>
                
                
                <security:authentication-manager alias="authenticationManagerAlias" />
                
                
                <bean id="ftUserService" class="...security.FtUserDetailService">
                
                <property name="droolsRulesSessionFactory" ref="RulesSessionFactory_Authentication" />
                
                </bean>
                
                
                <bean id="ftAuthenticationProvider" class="..webapp.security.FtAuthenticationProvider">
                
                <security:custom-authentication-provider />
                
                <property name="userDetailService" ref="ftUserService" />
                
                </bean>
                
                
                <bean id="ftAuthenticationProcessingFilter" class="..webapp.security.FtProcessingFilter">
                
                <security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
                
                <property name="filterProcessesUrl" value="/j_spring_security_check" />
                
                <property name="defaultTargetUrl" value="/index.jsp" />
                
                <property name="authenticationManager" ref="authenticationManagerAlias" />
                
                </bean>
                
                
                <bean id="authenticationEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
                
                <property name="loginFormUrl" value="/public/login.jsp" />
                
                <property name="forceHttps" value="false" />
                
                </bean> 
                
                </beans>
                This is the stacktrace:
                Code:
                SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
                org.springframework.beans.factory.BeanCreationException: Error creating bean with name '_filterChainProxy': Initialization of bean failed; nested exception is org.springframework.security.config.SecurityConfigurationException: Filters 'be.ing.freeticket.webapp.security.FtProcessingFilter[ order=0; ]' and 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]' have the same 'order' value. When using custom filters, please make sure the positions do not conflict with default filters. Alternatively you can disable the default filters by removing the corresponding child elements from <http> and not avoiding the use of <http auto-config='true'>.
                Related cause: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '_defaultLoginPageFilter': Unsatisfied dependency expressed through constructor argument with index 1 of type [org.springframework.security.ui.AbstractProcessingFilter]: Ambiguous constructor argument types - did you specify the correct bean references as constructor arguments?
                
                
                Caused by: org.springframework.security.config.SecurityConfigurationException: Filters 'be.ing.freeticket.webapp.security.FtProcessingFilter[ order=0; ]' and 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]' have the same 'order' value. When using custom filters, please make sure the positions do not conflict with default filters. Alternatively you can disable the default filters by removing the corresponding child elements from <http> and not avoiding the use of <http auto-config='true'>.
                
                org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '_defaultLoginPageFilter': Unsatisfied dependency expressed through constructor argument with index 1 of type

                Comment


                • #9
                  When in doubt, read the source...

                  Bjorn121: you've got to prevent the default org.springframework.security.ui.webapp.Authenticat ionProcessingFilter from being created; I don't remember how to do that.

                  To tie up this thread, and answer my own questions:

                  1. Can I get the default login page to do what I want?
                  -- I think the answer is "no". I was going to end up writing my own login page anyway at some point, so I created this login.jsp:
                  HTML Code:
                      <form method="POST" name="myForm" action="/j_spring_security_check">
                      <center>
                        <span id='cbrowse' style="background-color: #ff0; text-align: center;"></span>
                        <b>Log in to your account</b><br/>
                        Username: <input type="text" name="j_username" value="[email protected]" onclick="usernameReset()"/><br/>
                        Password: <input type="password" name="j_password"/><br/>
                        <input type="checkbox" name="_spring_security_remember_me">Remember my ID<br/><br/>
                        <input type="hidden" name="spring-security-redirect" value="${param.returnTo}"/>
                        <input type="hidden" name="url" value="${param.url}"/>
                        <input type="submit" name="Login" value="Login">
                        </center>
                      </form>
                  ... and create links to "Login now" that go to login.jsp?returnTo=/url_of_page.../

                  My spring security configuration xml file is very simple:
                  Code:
                    <http auto-config="true">
                      <intercept-url pattern="/foo/**" access="ROLE_USER" />
                    </http>
                  
                    <beans:bean id="myUserDetailService"
                          class="org.rexa.security.RexaUserDetailsService">
                      <beans:property name="dataSource">
                        <beans:ref bean="varDataSource"/>  <!--  See rexo project rexa/persistence/spring/spring-var-datasource-context -->
                      </beans:property>
                    </beans:bean>
                    <authentication-provider user-service-ref="myUserDetailService">
                      <password-encoder hash="sha"/>
                    </authentication-provider>
                  RexaUserDetailsService does the user database lookup (we use email addresses for user ids):
                  Code:
                  package org.rexa.security;
                  
                  import java.math.BigInteger;
                  import java.util.ArrayList;
                  import java.util.List;
                  import java.util.Map;
                  
                  import javax.sql.DataSource;
                  
                  import org.rexo.database.MysqlDB;
                  import org.springframework.dao.DataAccessException;
                  import org.springframework.jdbc.core.JdbcTemplate;
                  import org.springframework.security.GrantedAuthority;
                  import org.springframework.security.GrantedAuthorityImpl;
                  import org.springframework.security.userdetails.User;
                  import org.springframework.security.userdetails.UserDetails;
                  import org.springframework.security.userdetails.UserDetailsService;
                  import org.springframework.security.userdetails.UsernameNotFoundException;
                  
                  import sun.security.util.BigInt;
                  
                  /**
                   * Fetch a RexaUser from the database, given the username (email addresses are used as the user names)
                   * 
                   * @author andresen
                   */
                  public class RexaUserDetailsService implements UserDetailsService {
                  
                    @Override
                    public UserDetails loadUserByUsername(String username)
                        throws UsernameNotFoundException, DataAccessException {
                      
                      List<Map<String, Object>> rows = _db.queryForList("SELECT userID, email AS username, LOWER(password) AS password FROM users WHERE email=?",
                         new Object[]{ username });
                      
                      if (rows.size() == 0) {
                        throw new UsernameNotFoundException("email "+username+" not found in users table.");
                      }
                      Map<String, Object> row = rows.get(0);
                      assert(username.equals(row.get("username")));
                      String password = (String)row.get("password");
                      long userID = ((BigInteger)row.get("userID")).longValue();
                  
                      List<String> authorities = _db.queryForList("SELECT CONCAT('ROLE_',UPPER(authority)) FROM userauthority WHERE userID=?", new Object[]{ userID }, String.class);
                      UserDetails result = new RexaUser(userID, username, password, authorities);
                  
                      return result;
                    }
                  
                    // Getters/setters:
                    private JdbcTemplate _db;
                  
                    public DataSource getDataSource() {
                      return _db.getDataSource();
                    }
                  
                    public void setDataSource(DataSource d) {
                      _db = new JdbcTemplate(d);
                    }
                  }
                  ... and the RexaUser just stores a long userID along with the username/password that the default security.User stores:
                  Code:
                  package org.rexa.security;
                  
                  import java.util.List;
                  
                  import org.springframework.security.GrantedAuthority;
                  import org.springframework.security.GrantedAuthorityImpl;
                  import org.springframework.security.userdetails.User;
                  
                  /**
                   * Extend standard Spring User to add userID.
                   * 
                   * @author andresen
                   */
                  public class RexaUser extends User {
                    private static final long serialVersionUID = 1L;
                  
                    private long _userID;
                    
                    public RexaUser(Long userID, String username, String password, List<String> authorities)
                        throws IllegalArgumentException {
                  
                      super(username, password, true /* enabled */, true /* accountNonExpired */,
                          true /* credentialsNonExpired */, true /* accountNonLocked */, convertAuthorities(authorities));
                      
                        if (((username == null) || "".equals(username)) || (password == null)) {
                            throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
                        }
                        this._userID = userID;
                    }
                    
                    private static GrantedAuthority[] convertAuthorities(List<String> authorities) {
                      GrantedAuthority a[] = new GrantedAuthority[authorities.size()];
                      for (int i = 0; i < authorities.size(); i++) {
                        a[i] = new GrantedAuthorityImpl(authorities.get(i));
                      }
                      return a;
                    }
                  
                    public long getUserID() {
                      return _userID;
                    }
                  
                    public void setUserID(long userID) {
                      _userID = userID;
                    }
                  }

                  Comment


                  • #10
                    @Bjorn121

                    Don't use "auto-config" or <form-login>.

                    Comment


                    • #11
                      Ok, I misinterpreted that sentence in the previous posts .

                      Maybe it's a good idea to add this to the reference guide, because that's not very clear at all when you read that part.

                      Comment


                      • #12
                        Update to Spring Security 2.0.2

                        Hello,
                        I'm using SWF 2.0.2 with Facelets. After updating to Spring Security 2.0.2 (from 2.0.0) my Configuration below is no more working, so I removed the form-login tag and added the AuthenticationProcessingFilterEntryPoint bean as Luke suggested but I still get the following exception:

                        Code:
                        ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
                        org.springframework.beans.factory.BeanCreationException: Error creating bean with name '_filterChainProxy': Initialization of bean failed; nested exception is org.springframework.security.config.SecurityConfigurationException: Filters 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]' and 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]' have the same 'order' value. When using custom filters, please make sure the positions do not conflict with default filters. Alternatively you can disable the default filters by removing the corresponding child elements from <http> and not avoiding the use of <http auto-config='true'>.
                        Related cause: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '_defaultLoginPageFilter': Unsatisfied dependency expressed through constructor argument with index 1 of type [org.springframework.security.ui.AbstractProcessingFilter]: Ambiguous constructor argument types - did you specify the correct bean references as constructor arguments?
                                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:478)
                                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
                                at java.security.AccessController.doPrivileged(Native Method)
                                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
                                at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
                                at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:220)
                        .
                        .
                        .
                        Caused by: org.springframework.security.config.SecurityConfigurationException: Filters 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]' and 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]' have the same 'order' value. When using custom filters, please make sure the positions do not conflict with default filters. Alternatively you can disable the default filters by removing the corresponding child elements from <http> and not avoiding the use of <http auto-config='true'>.
                                at org.springframework.security.config.FilterChainProxyPostProcessor.postProcessBeforeInitialization(FilterChainProxyPostProcessor.java:65)
                                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:350)
                                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1329)
                                at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:471)
                                ... 90 more
                        My Config is:

                        Code:
                            <security:http auto-config="true" >
                                 <security:intercept-url pattern="/spring/login/login*" access="ROLE_ANONYMOUS"  requires-channel="https" />
                                 <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" /> 
                                <!--<security:form-login login-page="/spring/login/login" /> -->
                                <security:logout logout-url="/spring/login/logout" logout-success-url="/spring/home" />
                            </security:http>
                        
                            <security:authentication-provider>
                                   <security:password-encoder ref="encoder" >
                                       <security:salt-source system-wide="*****" />
                                   </security:password-encoder>
                                   <security:jdbc-user-service data-source-ref="dataSource"  
                                   users-by-username-query="SELECT ******"
                                   authorities-by-username-query="SELECT *****" />
                            </security:authentication-provider>
                        	
                            <security:authentication-manager alias="authenticationManager"/>
                            
                          <bean id="authenticationEntryPoint"
                                class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
                            <property name="loginFormUrl" value="/spring/login/login" />
                            <property name="forceHttps" value="true" />
                          </bean>
                          
                        <bean id="authenticationProcessingFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
                                <property name="authenticationManager" ref="authenticationManager"/>
                                <property name="authenticationFailureUrl" value="/spring/login/login?login_error=1"/>
                                <property name="defaultTargetUrl" value="/spring/auction"/>
                                <property name="filterProcessesUrl" value="/spring/login/loginProcess"/>
                                <property name="targetUrlResolver">
                                    <bean class="org.springframework.security.ui.TargetUrlResolverImpl">
                                        <property name="justUseSavedRequestOnGet" value="false"/>
                                    </bean>       
                                </property>
                                <security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/> 
                            </bean>
                        
                          <bean id="encoder" class="org.springframework.security.providers.encoding.Md5PasswordEncoder" />
                              
                          <bean id="saltSource"
                              class="org.springframework.security.providers.dao.salt.SystemWideSaltSource">
                            <property name="systemWideSalt" value="yw4a79" />
                          </bean>
                        
                            <bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener"/>
                        Can anybody help?
                        Thanks in advance.

                        Comment


                        • #13
                          I don't know if that's the solution, but try adding <security:custom-entry-point /> (use code completion, because I don't know the correct code by heart) to your custom EntryPoint bean. And set aut-config to false too.

                          Comment


                          • #14
                            So, now it works. The right config is as below and the added two lines in bold seems to be important otherwise it doesn't works!

                            Code:
                                <security:http auto-config="false" entry-point-ref="authenticationEntryPoint" >
                                     <security:intercept-url pattern="/spring/login/login*" access="ROLE_ANONYMOUS"  requires-channel="https" />
                                     <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" /> 
                                    <security:logout logout-url="/spring/login/logout" logout-success-url="/spring/home" />
                                    <security:http-basic />
                                    <security:anonymous />
                                </security:http>
                            Bye.

                            Comment


                            • #15
                              wrong error message

                              Originally posted by Luke Taylor View Post
                              Yes, you're right. I've corrected the message.
                              Hi Luke, the error message is still:
                              Code:
                              not avoiding the use of <http auto-config='true'>.
                              Bye

                              Comment

                              Working...
                              X