1

Trying to combine Spring Session (to Redis) with Spring Security (DB-based). Authentication works just fine, and if I add listener:

import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpSession;

@Component
public class AuthenticationSuccessListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {


    @Override
    public void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        System.out.println("authentication: " + authentication.getName());

        ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpSession currentSession = attr.getRequest().getSession();
        System.out.println("session: " + currentSession.getAttribute("SESSION_DETAILS"));
    }
}

Then it nicely prints:

authentication: admin
session: app.session.SessionDetails@694daf33

And Redis store is updated as well:

127.0.0.1:6379> keys *
1) "spring:session:sessions:c7b0fc2c-3148-4895-9aef-78dfc8443585"
2) "spring:session:expirations:1523615100000"
3) "spring:session:sessions:expires:02acfbd4-93e7-44dc-9b61-38473a8a9ae7"
4) "spring:session:sessions:expires:c7b0fc2c-3148-4895-9aef-78dfc8443585"
5) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:admin"

But when I do in @Controller:

@RequestMapping("/")
public String index(Principal principal, Model model) {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    System.out.println("authentication: " + authentication.getName());

    ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
    HttpSession currentSession = attr.getRequest().getSession();
    System.out.println("session: " + currentSession.getAttribute("SESSION_DETAILS"));

    return "index";
}

Then I see the following:

authentication: null
session: app.session.SessionDetails@1225ad92

New session is created and that is OK, but authentication details are gone. Which is a big surprise, as security configuration allows only authorized requests:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .permitAll();
}

To sum things up, I see secured content, but authorization details are set to null. How come?

1 Answer 1

3

Found a resolution. Even if your CustomUserDetails class implements Serializable and created in a way:

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    Optional<User> optionalUsers = userRepository.findByUsername(username);

    optionalUsers
            .orElseThrow(() -> new UsernameNotFoundException("Username not found"));
    return optionalUsers
            .map(CustomUserDetails::new).get();
}

Then Spring Secruity requires User also implement Serializable. Don't ask me why. Magic.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.