Spring security websocket and HTTP authentication/authorization

本秂侑毒 提交于 2019-12-22 05:11:59

问题


Summary I would like to implement websocket communication over STOMP. Authenticate The user in the time of the first (HTTP request) websocket handshake and use this Principal for authorizing websocket messages later.

Problem The system authenticates the client at the first time when it tries to connect to the websocket endpoint (the time of HTTP handshake). My spring security filter and Authentication provider does its job and authenticates the client properly. After this I can check that the client gets the Roles and my Authentication object is stored in the SecurityContext as well. (At this point websocket connection established and the HTTP protocol has been thrown away.) BUT from the first websocket communication I get that the Authentication object is Anonymous because the SecurityContextHolder was cleared somehow because the SecurityContextChannelInterceptor clears it.

Spring documentation claims the following: http://docs.spring.io/autorepo/docs/spring-security/current/reference/htmlsingle/#websocket-authentication

WebSockets reuse the same authentication information that is found in the HTTP request when the WebSocket connection was made. This means that the Principal on the HttpServletRequest will be handed off to WebSockets. If you are using Spring Security, the Principal on the HttpServletRequest is overridden automatically.

My very simple filter

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

    try {


        Authentication authResult =
                new CertAuthenticationToken(null, Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN")));

        authResult = getAuthenticationManager().authenticate(authResult);

        if (authResult.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(authResult);
            LOGGER.info("Client was authenticated.");
        }
        chain.doFilter(request, response);

    } catch (AuthenticationException ae) {
        LOGGER.error("Client was not authenticated. {}", ae);
        SecurityContextHolder.clearContext();
        onUnsuccessfulAuthentication((HttpServletRequest) request, (HttpServletResponse) response, ae);
        throw ae;
    }
}

My very simple authentication provider

 public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        authentication.setAuthenticated(true);
        return authentication;
    }

Spring boot is used with 1.3.0.BUILD-SNAPSHOT version. One additonal dependency is spring-security-messaging with 4.0.1.RELEASE version that I use beside the default spring boot dependencies.

Any question help is appreciated.

Application Security:

@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {


    @Autowired
    AuthenticationManager authenticationManager;


    @Bean
    CertAuthenticationFilter certAuthenticationFilter() {
        return new CertAuthenticationFilter(authenticationManager);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
            .csrf().disable()
            .authorizeRequests().expressionHandler(new         CustomExpressionHandler()) 
            .antMatchers("/hello", "/websocket/**").access( "isCustomAuthorized()" )
            .and()
            .httpBasic()
            .and()
            .addFilter( certAuthenticationFilter() ); 

    }

}

Authentication Security:

@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class AuthenticationSecurity extends
        GlobalAuthenticationConfigurerAdapter {

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(new CertHeaderAuthenticationProvider());
        auth.authenticationProvider(new CustomWebsocketAuthenticationProvider());
        auth.inMemoryAuthentication();
    }
}

Websocket security:

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    @Autowired
    AuthenticationManager authenticationManager;

    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
                .simpTypeMatchers(SimpMessageType.CONNECT).access("isCustomAuthorized()");
    }

    @Override
    public ChannelSecurityInterceptor inboundChannelSecurity() {
        ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(
                inboundMessageSecurityMetadataSource());
        channelSecurityInterceptor.setAccessDecisionManager(setupDecisionManager());
        return channelSecurityInterceptor;
    }


    private AffirmativeBased setupDecisionManager() {
        MessageExpressionVoter messageExpressionVoter = new MessageExpressionVoter<Object>();
        messageExpressionVoter.setExpressionHandler(new CustomMessageSecurityExpressionHandler());
        List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<AccessDecisionVoter<? extends Object>>();
        voters.add(messageExpressionVoter);
        AffirmativeBased manager = new AffirmativeBased(voters);
        return manager;
    }

    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }
    }

来源:https://stackoverflow.com/questions/30662903/spring-security-websocket-and-http-authentication-authorization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!