Search code examples
spring-bootjhipsterjhipster-gateway

JHipster Microservice CORS


Is there a way to access a microservice API via the gateway without authentication? For example, if I have a public landing page that needs to read data from a microservice API. I enabled CORS and tested the API via Swagger and it works fine from within the gateway app; however, if I call the API using CURL I get an unauthorized error.

This is the CURL command I am trying to execute:

curl -X 'GET' \
  'http://localhost:8080/services/tajvoteservice/api/landing-page-by-organizations' \
  -H 'accept: */*' \
  -H 'X-XSRF-TOKEN: 5d3e3faf-3a3d-4905-bdea-f5ce305d3672'

This is the error I get:

{"type":"https://www.jhipster.tech/problem/problem-with-message","title":"Unauthorized","status":401,"detail":"Not Authenticated","path":"/services/tajvoteservice/api/landing-page-by-organizations","message":"error.http.401"}%

This is my SecurityConfiguration.java configure method:

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
            .csrf()
            .disable()
            .exceptionHandling()
                .authenticationEntryPoint(problemSupport)
                .accessDeniedHandler(problemSupport)
        .and()
            .headers()
            .contentSecurityPolicy(jHipsterProperties.getSecurity().getContentSecurityPolicy())
        .and()
            .referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
        .and()
            .featurePolicy("geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'self'; payment 'none'")
        .and()
            .frameOptions()
            .deny()
        .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
            .authorizeRequests()
            .antMatchers("/api/auth-info").permitAll()
            .antMatchers("/api/admin/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/api/landing-page-by-organizations/**").permitAll()
            .antMatchers("/api/**").authenticated()
            .antMatchers("/management/health").permitAll()
            .antMatchers("/management/health/**").permitAll()
            .antMatchers("/management/info").permitAll()
            .antMatchers("/management/prometheus").permitAll()
            .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
        .and()
            .oauth2ResourceServer()
                .jwt()
                .jwtAuthenticationConverter(authenticationConverter())
                .and()
            .and()
                .oauth2Client();
        // @formatter:on
    }

Please advise.


Solution

  • Thank you Mr. Marziou. I added to the springSecurityFilterChain method in my gateway's SecurityConfiguration.java the path matcher:

              .pathMatchers("/services/tajvoteservice/api/landing-page-by-organizations/**").permitAll()
    

    So my gateway SecurityConfiguration's springSecurityFilterChain method is as follows:

        @Bean
        public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
            // @formatter:off
            http
                .securityMatcher(new NegatedServerWebExchangeMatcher(new OrServerWebExchangeMatcher(
                    pathMatchers("/app/**", "/i18n/**", "/content/**", "/swagger-ui/**", "/swagger-resources/**", "/v2/api-docs", "/v3/api-docs", "/test/**"),
                    pathMatchers(HttpMethod.OPTIONS, "/**")
                )))
                .csrf()
                    .csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
            .and()
                // See https://github.com/spring-projects/spring-security/issues/5766
                .addFilterAt(new CookieCsrfFilter(), SecurityWebFiltersOrder.REACTOR_CONTEXT)
                .addFilterAt(new SpaWebFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
                .exceptionHandling()
                    .accessDeniedHandler(problemSupport)
                    .authenticationEntryPoint(problemSupport)
            .and()
                .headers()
                .contentSecurityPolicy(jHipsterProperties.getSecurity().getContentSecurityPolicy())
                .and()
                    .referrerPolicy(ReferrerPolicyServerHttpHeadersWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
                .and()
                    .featurePolicy("geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; fullscreen 'self'; payment 'none'")
                .and()
                    .frameOptions().disable()
            .and()
                .authorizeExchange()
                .pathMatchers("/").permitAll()
                .pathMatchers("/*.*").permitAll()
                .pathMatchers("/api/auth-info").permitAll()
                .pathMatchers("/services/tajvoteservice/api/landing-page-by-organizations/**").permitAll()
                .pathMatchers("/api/admin/**").hasAuthority(AuthoritiesConstants.ADMIN)
                .pathMatchers("/api/**").authenticated()
                .pathMatchers("/services/**").authenticated()
                .pathMatchers("/management/health").permitAll()
                .pathMatchers("/management/health/**").permitAll()
                .pathMatchers("/management/info").permitAll()
                .pathMatchers("/management/prometheus").permitAll()
                .pathMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN);
    
            http.oauth2Login()
                .and()
                .oauth2ResourceServer()
                    .jwt()
                    .jwtAuthenticationConverter(jwtAuthenticationConverter());
            http.oauth2Client();
    
            // WebFlux
            http.redirectToHttps(redirect -> redirect
                .httpsRedirectWhen(e -> e.getRequest().getHeaders().containsKey("X-Forwarded-Proto")));
    
            // @formatter:on
            return http.build();
        }
    

    Now I can run the CURL command:

    curl -X 'GET' \
      'http://localhost:8080/services/tajvoteservice/api/landing-page-by-organizations/acfad1dd-2570-4900-a5c2-8f496f88527c' 
    

    And low and behold, I have JSON data with organization information!

    Thanks again, Mr. Marziou!