Results 1 to 7 of 7

Thread: ProcessingFilter: login without password

  1. #1
    Join Date
    Feb 2010
    Posts
    5

    Unhappy ProcessingFilter: login without password

    Hi there,

    For an application, I'd like to login with an activationhash that is sent to the user by email. I created a filter and tried to login with a UsernamePasswordAuthenticationToken, but this won't work since I'm not able to retrieve the password from the user since this is SHA-encoded in the database. I can get the complete record of the User though, but untill now, this hasn't been very useful.

    Can anyone give me any direction on how to solve this problem?

    Regards,
    Apie Mug

  2. #2
    Join Date
    Sep 2004
    Location
    Manchester, NH
    Posts
    1,236

    Default

    You'll have to write your own filter that will recognize this type of incoming request, construct a token, and then log the user in. It will probably be a custom token (a subclass of UsernamePasswordToken would be easiest), and you'll want to write a custom AuthenticationProvider which will recognize the token and be able to validate the activation code so that the user can be truly authenticated.
    Peter Mularien | Blog
    Author, Spring Security 3 (Book) - Packt Publishing, Available in print and eBook form
    SCJP 5, Oracle DBA
    Any postings are my own opinion, and should not be attributed to my employer or clients.


  3. #3
    Join Date
    Feb 2010
    Posts
    5

    Default

    Thanks for your reply. But I'm having problems with what value to return in my HashAuthenticationProvider class, in Authentication authenticate(Authentication authentication).

    I can't use:

    Code:
       return new UsernamePasswordToken(u, p)
    Since I don't know the password. Should I return the hashToken? That doesn't make sense because how would Spring know that it is valid?

  4. #4
    Join Date
    Sep 2004
    Location
    Manchester, NH
    Posts
    1,236

    Default

    It is the responsibility of your AuthenticationProvider to assert whether or not the provided Token is valid. What you return (once you have verified that the token is valid) is simply used for reference throughout the rest of the user's session - so it doesn't matter what you provide for password, for example. The only caveat to that in particular is that certain functions (such as non-persistent remember me) expect a password.
    Peter Mularien | Blog
    Author, Spring Security 3 (Book) - Packt Publishing, Available in print and eBook form
    SCJP 5, Oracle DBA
    Any postings are my own opinion, and should not be attributed to my employer or clients.


  5. #5
    Join Date
    Feb 2010
    Posts
    5

    Default

    Thanks for your help so far. I think I'm almost there, could you please take a look at the code, since I'm just guessing a bit how to fix this.

    The URL that should be responded to is /member/activate.htm?code=12345
    where member 2 has activationCode 12345

    (Spring 2.5)

    spring-security.xml:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:beans="http://www.springframework.org/schema/beans"
    	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">
    
    	<http auto-config="true" lowercase-comparisons="true" entry-point-ref="authenticationProcessingFilterEntryPoint">
    		<!-- URLs -->
    		<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
    		<intercept-url pattern="/member/activated.htm" access="ROLE_ANONYMOUS,ROLE_USER"/>
    		<intercept-url pattern="/**" access="ROLE_ANONYMOUS,ROLE_USER" />
    		
    		<form-login
    			login-page="/login.htm"
    			login-processing-url="/processLogin"
    			authentication-failure-url="/login.htm?login_error=1"
    			always-use-default-target="false"
    			default-target-url="/index.htm"
    		/>
    		<logout logout-url="/logout" />
    	</http>
    
    	<authentication-provider user-service-ref="securityService">
    		<password-encoder ref="passwordEncoder" />
    	</authentication-provider>
    	
    	<beans:bean id="hashAuthenticationProvider" class="nl.sticky.website.web.HashAuthenticationProvider">
    		<custom-authentication-provider/>
    	</beans:bean>
    	
    
    	<global-method-security />
    	<beans:bean id="authenticationProcessingFilter" class="nl.sticky.website.web.HashProcessingFilter">
    		<custom-filter position="LAST" />
    		<custom-authentication-provider/>
    		<beans:property name="defaultTargetUrl" value="/index.htm" />
    		<beans:property name="authenticationManager" ref="authenticationManager" />
    	</beans:bean>
    	<authentication-manager alias="authenticationManager"/>
    	<beans:bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
    		<beans:property name="loginFormUrl" value="/login.htm" />
    		<beans:property name="forceHttps" value="false" />
    	</beans:bean>
    </beans:beans>
    HashProcessingFilter
    Code:
    public class HashProcessingFilter extends AuthenticationProcessingFilter implements ApplicationEventPublisherAware {
    	private final SecurityService securityService;
    
    	@Autowired
    	public HashProcessingFilter(SecurityService ss) {
    		securityService = ss;
    	}
    
    	@Override
    	public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
    		if(!request.getRequestURI().endsWith("/member/activated.htm") && !request.getRequestURI().endsWith("/member/changePassword.htm")) {
    			chain.doFilter(request, response);
    			return;
    		}
    		
    		String hash = ServletRequestUtils.getStringParameter(request, "code");
    		if(hash == null) {
    			chain.doFilter(request, response);
    			return;
    		}		
    
    		HashToken paat = new HashToken(hash);
    		try {
    			Authentication auth = new HashAuthenticationProvider(securityService).authenticate(paat);
    			SecurityContextHolder.getContext().setAuthentication(auth);
    		} catch(Exception e) {
    			System.out.println(e);
    		}
    		chain.doFilter(request, response);
    	}
    }
    HashAuthenticationProvider
    Code:
    public class HashAuthenticationProvider implements AuthenticationProvider {
    	private SecurityService securityService;
    	
    	@Autowired
    	public HashAuthenticationProvider(SecurityService ss) {
    		this.securityService = ss;
    	}
    
    	@Override
    	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    		String hash = (String) authentication.getPrincipal();
    		Member member = securityService.getMemberByHash(hash);
    		
    		if(member == null) {
    			throw new BadCredentialsException("The user with hash " + hash + " could not be found.");
    		}
    		
    		UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(member.getUsername(), null);
    		return token;
    	}
    
    	@SuppressWarnings("unchecked")
    	@Override
    	public boolean supports(Class authentication) {
    		return HashToken.class.equals(authentication);
    	}
    
    }
    Last edited by apiemug; Feb 20th, 2010 at 09:58 AM.

  6. #6
    Join Date
    Sep 2004
    Location
    Manchester, NH
    Posts
    1,236

    Default

    Looks great! My only suggestion would be to call the AuthenticationManager.authenticate method instead of your AuthenticationProvider directly - this way things like session management, remember me, etc. will also work as they are supposed to. You can look at the username/password authentication filter for an example of how to do this.
    Peter Mularien | Blog
    Author, Spring Security 3 (Book) - Packt Publishing, Available in print and eBook form
    SCJP 5, Oracle DBA
    Any postings are my own opinion, and should not be attributed to my employer or clients.


  7. #7
    Join Date
    Feb 2010
    Posts
    5

    Default

    Thanks. Works like a charm now!

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •