Search code examples
springauthenticationspring-securityspring-websocket

Auth websocket session after manual web auth


I am using Spring Security with STOMP WebSocket on SpringBoot. Auth on websocket worked fine with this config when I used simple login form:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        .antMatchers("/webjars/**", "/resources/**").permitAll()
        .antMatchers("/register").anonymous()
        .anyRequest()
            .fullyAuthenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .successHandler(customLoginSuccessHandler)
        .failureUrl("/login?error")
            .permitAll()
            .and()
        .csrf().disable()
            .logout().logoutSuccessHandler(customLogoutSuccessHandler);
}


@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
    messages
            .nullDestMatcher().authenticated()
            .simpTypeMatchers(CONNECT).authenticated()
            .simpSubscribeDestMatchers(Channel.SYSTEM_ERROR.value()).permitAll()
            .simpDestMatchers("/app/publish*").hasRole("USER")
            .simpSubscribeDestMatchers("/user/**", "/topic/**", "/system/*").hasRole("USER")
            .anyMessage().denyAll();
}

But when I wanted to manually auth client after register new user in RegisterController:

@RequestMapping(value = "/register", method = RequestMethod.POST)
public String signup(@Valid @ModelAttribute SignupForm signupForm, Errors errors) {
    if (errors.hasErrors()) {
        return SIGNUP_VIEW_NAME;
    }
    User user = signupForm.createAccount();
    try {
        userService.persist(user);
    } catch (EntityExistsException ex) {
        errors.rejectValue("login", "user.exists");
        return SIGNUP_VIEW_NAME;
    }
    SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(user, null, Collections.singletonList(new SimpleGrantedAuthority("USER"))));

    return "redirect:/";
}

I've got problem with auth websocket. When I get redirected to page where websocket connects I am getting org.springframework.security.access.AccessDeniedException: Access is denied


Solution

  • So. Problem was in define Role. In controller when I defined new SimpleGrantedAuthority("USER") it should be "ROLE_USER" because Spring adds refix ROLLE_ by default. Sure we can change default behaviour of this by add next in WebSecurity configuration

        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/resources/**", "/favicon.ico");
            web.expressionHandler(new DefaultWebSecurityExpressionHandler() {
                @Override
                protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
                    WebSecurityExpressionRoot root = (WebSecurityExpressionRoot) super.createSecurityExpressionRoot(authentication, fi);
                    root.setDefaultRolePrefix(""); //remove the prefix ROLE_
                    return root;
                }
            });
        }
    

    . Yes, dummy mistake but so common. So I will leave it here