Search code examples
spring-securityspring-session

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?


Solution

  • 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);
        }
    }