Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Session and Spring Security

I have questions on the following areas: spring-session and spring-security.

Spring Session

I have a application protected with Spring Security through basic in-memory authentication as provided in the example sample.

I see spring is creating session id's even the authentication is not successful, meaning I am seeing x-auth-token in my response header as well in the Redis DB even if I don't supply basic authentication credential details. How do we avoid creating sessions for authentication failures?

Spring Security

Want to use spring security to protect resources assuming spring session creates session only for the protected resources.

Assuming a Signin API (/signin - HTTP Post) validates (username & password) credentials against a third-party REST API .

Once the external API validates the credentials, how do I update the spring security context on the successful authentication?

Access to other secured resources with the x-auth-token needs to be validated and based on the information access to the secured resource should be provided.

Do we need to have Spring Security in this case or shall I use a basic filter and spring session? What is recommended?

like image 439
gg_1234 Avatar asked Apr 06 '15 21:04

gg_1234


2 Answers

Typically it would be best to break your questions into multiple StackOverflow questions since you are more likely to find someone that knows the answer to a single question than both.

How do we avoid creating sessions for authentication failures ?

By default Spring Security will save the last unauthenticated request to session so that after you authenticate it can automatically make the request again. For example, in a browser if you request example.com/a/b/c and are not authenticated, it will save example.com/a/b/c to the HttpSession and then have the user authenticate. After you are authenticated, it will automatically give you the result of example.com/a/b/c. This provides a nice user experience so that your users do not need to type the URL again.

In the case of a REST service this is not necessary since the client would remember which URL needs to be re-requested. You can prevent the saving by modifying the configuration to use a NullRequestCache as shown below:

protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .requestCache()
            .requestCache(new NullRequestCache())
            .and()
        .httpBasic();
}

You can provide custom authentication by providing your own AuthenticationProvider. For example:

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;

public class RestAuthenticationProvider implements AuthenticationProvider {

    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;

        String username = token.getName();
        String password = (String) token.getCredentials();

        // validate making REST call
        boolean success = true;
        // likely your REST call will return the roles for the user
        String[] roles = new String[] { "ROLE_USER" };

        if(!success) {
            throw new BadCredentialsException("Bad credentials");
        }

        return new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(roles));
    }

    public boolean supports(Class<?> authentication) {
        return (UsernamePasswordAuthenticationToken.class
                .isAssignableFrom(authentication));
    }

}

You can then configure your RestAuthenticationProvider using something like this:

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    ...

    @Bean
    public RestAuthenticationProvider restAuthenticationProvider() {
        return new RestAuthenticationProvider();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth, AuthenticationProvider provider) throws Exception {
        auth
            .authenticationProvider(provider);
    }
}
like image 109
Rob Winch Avatar answered Sep 28 '22 02:09

Rob Winch


Session IDs are getting stored in Redis even when authentication fails.

Rob's answer of setting NullRequestCache didn't work for me. That is, there were redis entries even after setting request cache to NullRequestCache. To make it work, I had to use an authentication failure handler.

http.formLogin().failureHandler(authenticationFailureHandler()).permitAll();

private AuthenticationFailureHandler authenticationFailureHandler() {
    return new AuthenticationFailureHandler();
}

public class AuthenticationFailureHandler 
    extends SimpleUrlAuthenticationFailureHandler {
}

Note that the failure handler does nothing but extend the default handler explicitly. It returns a 401 in case of failure. If you were doing redirects, you can configure it in the handler easily.

like image 37
Srikanth Avatar answered Sep 28 '22 03:09

Srikanth