0

I'm having small REST API application that is running on Spring boot. For security I'm using external provider (Auth0 in this case), and frontend Angular application provide token for each API call. This works great with minimal configuration:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        JwtWebSecurityConfigurer
                .forRS256(apiAudience, issuer)
                .configure(http)
                .authorizeRequests()
                .antMatchers("/websocket/**").permitAll()
                .anyRequest().authenticated();
    }

}

Now I'm trying to add some websocket support in it for notify users on some events. Some basic things:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket").withSockJS();
    }
}

Connection is working and I can introduce some HandshakeInterceptor to validate user's token that is sent throw url on connect:

public class HttpSessionHandshakeInterceptor implements HandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {

        ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
        HttpServletRequest httpServletRequest = servletRequest.getServletRequest();

        String token = httpServletRequest.getParameter("token");

        AuthAPI auth = new AuthAPI("account url", "user id", "secret");
        Request<UserInfo> authRequest = auth.userInfo(token);
        try {
            UserInfo info = authRequest.execute();
            if (info.getValues().get("name") != null) {
                return true;
            }
        } catch (APIException exception) {
        } catch (Auth0Exception exception) {
        }
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return false;
    }
}

I'm having problem with current API calls that I want to be available also on sockets:

@Controller
public class TestController {
    @PreAuthorize("hasAuthority('read:photos')")
    @RequestMapping(value = "/photos", method = RequestMethod.GET)
    @MessageMapping("/photos")
    @ResponseBody
    public String getPhotos() {
        return "All good. You can see this because you are Authenticated with a Token granted the 'read:photos' scope";
    }
}

Calling this from socket throws that, An Authentication object was not found in the SecurityContext exception. Is their any why to provide SecurityContext on socket calls? Maybe throw ChannelInterceptorAdapter.preSend? I found a lot of questions about this, but no answers have given (example). Auth0 team also not provide any working example of this.

I also tried to use WebSocket Security, but cant rewire it to Auth0.

Do anyone have any working solution with this more granular approach? Small note, on frontend using SockJS and Stomp. Can send token throw headers or throw url.

CoYoTe
  • 95
  • 1
  • 7

0 Answers0