spring-attic / tut-react-and-spring-data-rest

React.js and Spring Data REST :: A tutorial based on the 5-part blog series by Greg Turnquist
https://spring.io/guides/tutorials/react-and-spring-data-rest
882 stars 1.58k forks source link

Enable CORS at AbstractWebSocketMessageBrokerConfigurer #16

Closed tur-ing closed 8 years ago

tur-ing commented 8 years ago

I want to access the WebSocket from another host. I tried to set the .setAllowedOrigins("*") to enable CORS like this, which does not work:


@Component
@EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {

    public static final String MESSAGE_PREFIX = "/topic";

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

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker(MESSAGE_PREFIX);
        registry.setApplicationDestinationPrefixes("/app");
    }

}
tur-ing commented 8 years ago

OK, seems that this is not related to a CORS problem - it is more an authorization problem! The host is protected by Spring Security, so the socket listener can not access it (401 error):

bildschirmfoto 2016-03-02 um 14 16 22

Acutually, I would like to go through Zuul. Everything is working fine there now. But Zuul does not seem to have WebSocket proxy abilities.

bildschirmfoto 2016-03-02 um 14 15 36

UI Server


@SpringBootApplication
@EnableZuulProxy
@EnableOAuth2Sso
@EnableDiscoveryClient
public class SaCenterApplication extends WebSecurityConfigurerAdapter {

    public static void main(String[] args) {
        SpringApplication.run(SaCenterApplication.class, args);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**").authorizeRequests()
                .antMatchers("/index.html", "/home.html", "/").permitAll().anyRequest()
                .authenticated().and().csrf().csrfTokenRepository(csrfTokenRepository())
                .and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
    }

    private Filter csrfHeaderFilter() {
        return new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request,
                    HttpServletResponse response, FilterChain filterChain)
                            throws ServletException, IOException {
                CsrfToken csrf = (CsrfToken) request
                        .getAttribute(CsrfToken.class.getName());
                if (csrf != null) {
                    Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                    String token = csrf.getToken();
                    if (cookie == null
                            || token != null && !token.equals(cookie.getValue())) {
                        cookie = new Cookie("XSRF-TOKEN", token);
                        cookie.setPath("/");
                        response.addCookie(cookie);
                    }
                }
                filterChain.doFilter(request, response);
            }
        };
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }

}

Authorization Server

@SpringBootApplication
@Configuration
@RestController
@EnableDiscoveryClient
@EnableResourceServer
@EnableAutoConfiguration
@EnableAuthorizationServer
public class SaAuthApplication {

    @Autowired
    private DataSource dataSource;

    @RequestMapping("/user")
    public Principal user(Principal user) {
        return user;
    }

    public static void main(String[] args) {
        SpringApplication.run(SaAuthApplication.class, args);
    }

    @Configuration
    @EnableResourceServer
    protected static class ResourceServer extends ResourceServerConfigurerAdapter {

        @Autowired
        private TokenStore tokenStore;

        @Override
        public void configure(ResourceServerSecurityConfigurer resources)
                throws Exception {
            resources.tokenStore(tokenStore);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().authenticated();
        }

    }

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

        @Autowired
        private AuthenticationManager auth;

        @Autowired
        private DataSource dataSource;

        private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

        @Bean
        public JdbcTokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }

        @Bean
        protected AuthorizationCodeServices authorizationCodeServices() {
            return new JdbcAuthorizationCodeServices(dataSource);
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer security)
                throws Exception {
            security.passwordEncoder(passwordEncoder);
        }

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                throws Exception {
            endpoints.authorizationCodeServices(authorizationCodeServices())
                    .authenticationManager(auth).tokenStore(tokenStore())
                    .approvalStoreDisabled();
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            // @formatter:off
            clients.jdbc(dataSource)
                    .passwordEncoder(passwordEncoder)
                .withClient("my-trusted-client")
                    .authorizedGrantTypes("password", "authorization_code",
                            "refresh_token", "implicit")
                    .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
                    .scopes("read", "write", "trust")
                    .resourceIds("oauth2-resource")
                    .accessTokenValiditySeconds(600).and()
                .withClient("my-client-with-registered-redirect")
                    .authorizedGrantTypes("authorization_code")
                    .authorities("ROLE_CLIENT").scopes("read", "trust")
                    .resourceIds("oauth2-resource")
                    .redirectUris("http://anywhere?key=value").and()
                .withClient("my-client-with-secret")
                    .authorizedGrantTypes("client_credentials", "password")
                    .authorities("ROLE_CLIENT").scopes("read")
                    .resourceIds("oauth2-resource").secret("secret");
            // @formatter:on
        }

    }

    @Autowired
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        // @formatter:off
            auth.jdbcAuthentication().dataSource(dataSource).withUser("dave")
                    .password("secret").roles("USER");
            // @formatter:on
    }

}

Resource Server


@SpringBootApplication
@EnableDiscoveryClient
@EnableResourceServer
public class SaEmployeeApplication {

    public static void main(String[] args) {
        SpringApplication.run(SaEmployeeApplication.class, args);
    }

}
gregturn commented 8 years ago

That may a bit out of scope for what we want to cover in this tutorial.

Have you looked at https://spring.io/guides/tutorials/spring-security-and-angular-js/? I realize it's Angular and you are using React, but they cover a lot of stuff you are alluding to such as Spring Security, Zuul, and OAuth2. You might want to skim over it, and see if it addresses the issues you interested in tackling.

tur-ing commented 8 years ago

OK. @gregturn if you need ideas for a new tutorial, I have a lot of them ;-)

gregturn commented 8 years ago

My desire for new tutorials is hedged by my ability to maintain them. ;)