0

I am making a basic Tic tac toe Project with Spring , Spring Security and Hibernate. Application can save game for each logged user in database and allow to load it whenever we want. That is not a problem , but it appears when it comes to multi-threading. When i run single application in single browser window everything is working good. But when i open another window , two players are playing the same game.

I know it may be caused by bean singletons created by Spring but I am sure that it is not. To check currently logged user, i made an method to get him from SecurityContextHolder

private User getUserFromSpringContext() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    String name = authentication.getName();
    System.out.println("Currently logged users = " + name);
    return userService.findUserByUsername(name);
}

When multiple users are logged in , that metod prints name of only one of them. I have no idea why. Here are some important code lines my Security configuration and userDetails classes:

Security Configuration:

@Autowired
UserDetailsService userDetailsService;

@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder builder) throws Exception {
    builder.userDetailsService(userDetailsService);
    builder.authenticationProvider(authenticationProvider());
}

@Bean
public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
    auth.setUserDetailsService(userDetailsService);
    return auth;
}

Custom Users Details Service

@Autowired
private UserService userService;

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    User user = userService.findUserByUsername(username);
    if (user == null) {
        throw new UsernameNotFoundException("Username not found");
    }
    return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), true, true, true, true, getAuthoriries(user));
}

public void setUserService(UserService userService) {
    this.userService = userService;
}

private List<GrantedAuthority> getAuthoriries(User user) {
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new SimpleGrantedAuthority(user.getRole().getRole()));
    return authorities;
}

Does anybody knows cause of this problem?

During testing that I came up with another problem. When i click Logout , all users are logged out. I am posting here rest of my Spring Security Configuration.

 @Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/start", "/", "/login", "/registry","/success","/new").permitAll()
            .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
            .antMatchers("/**").access("hasAnyRole('ROLE_USER','ROLE_ADMIN')")
            .and().formLogin().loginPage("/login").defaultSuccessUrl("/user")
            .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
            .and().csrf()
            .and().exceptionHandling().accessDeniedPage("/access_denied");
}

What can be a problem?

  • assuming it works the way i think it does, have you asserted (however) that as users log in, their entries are created in your database? perhaps it only works for the very first user only? – matias elgart Nov 18 '16 at 13:34
  • I edited post because i found another issue. –  Nov 18 '16 at 13:39
  • Define opening a new window? If you that is pressing CTRL+T or CTRL+N from you existing browser that is not a new browser. The session state, cache and cookies will be copied. You are actually not playing with multiple players but with a single user in multiple browser windows. I would say it works as it should and you are just testing it in the wrong way. – M. Deinum Nov 18 '16 at 13:45
  • Only if i open two different browsers like Chrome and Edge , my app works correctly. So does it means that everything is fine but i should always run it in multiple browsers? –  Nov 18 '16 at 13:52

1 Answers1

3

SecurityContextHolder gives you access to the security context associated with the current thread, thus only the current user - the one whose request triggered the call to getAuthentication(), so it's behaving exactly the way it should.

If you, on the other hand, want all active sessions (i.e. all logged in users) you should inject the SessionRegistry and call sessionRegistry.getAllPrincipals() on it.

The details are already given here.

Community
  • 1
  • 1
kaqqao
  • 12,984
  • 10
  • 64
  • 118