Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enable wildcard in CORS spring security + webFlux

I have spring security + CORS enable into a project that is made with spring webFlux. My problem here is that we accept for example requests from: http://localhost:4200. How I can make that CORS will accept reqs from http://*.localhost:4200 like http://a.localhost:4200, http://b.localhost:4200 ?

My CORS config looks like:

@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public CorsWebFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);

    config.setAllowedOrigins(corsConfigData.getAllowedOrigins());
    config.setAllowedHeaders(corsConfigData.getAllowedHeaders());
    config.setAllowedMethods(corsConfigData.getAllowedMethods());

    source.registerCorsConfiguration("/**", config);
    return new CorsWebFilter(source);
}

Do you have any ideas ???

like image 504
brebDev Avatar asked Nov 21 '18 12:11

brebDev


People also ask

How do you turn on CORS at Spring security level?

To enable CORS support through Spring security, configure CorsConfigurationSource bean and use HttpSecurity. cors() configuration. @LahiruGamage it doesn't matter, it's a Spring bean like any others, so as long as it's within a (sub)package relative to the main class, it will work.


2 Answers

I think I found a solution that works. That simply means creating a custom CorsConfiguration, overriding the checkOrigin method and create a custom matcher that will interpret http://*.localhost:4200 correctly. The code looks like this:

public class RegexCorsConfiguration extends CorsConfiguration {

private List<String> allowedOriginsRegexes = new ArrayList<>();

/**
 * Check the origin of the request against the configured allowed origins.
 * @param requestOrigin the origin to check
 * @return the origin to use for the response, possibly {@code null} which
 * means the request origin is not allowed
 */
public String checkOrigin(String requestOrigin) {
    if (!StringUtils.hasText(requestOrigin)) {
        return null;
    }

    if (this.allowedOriginsRegexes.isEmpty()) {
        return null;
    }

    if (this.allowedOriginsRegexes.contains(ALL)) {
        if (getAllowCredentials() != Boolean.TRUE) {
            return ALL;
        } else {
            return requestOrigin;
        }
    }

    for (String allowedOriginRegex : this.allowedOriginsRegexes) {
        if (createMatcher(requestOrigin, allowedOriginRegex).matches()) {
            return requestOrigin;
        }
    }

    return null;
}

public void setAllowedOriginRegex(List<String> allowedOriginsRegexes) {
    this.allowedOriginsRegexes = allowedOriginsRegexes;
}

private Matcher createMatcher(String origin, String allowedOrigin) {
    String regex = this.parseAllowedWildcardOriginToRegex(allowedOrigin);
    Pattern pattern = Pattern.compile(regex);
    return pattern.matcher(origin);
}

private String parseAllowedWildcardOriginToRegex(String allowedOrigin) {
    String regex = allowedOrigin.replace(".", "\\.");
    return regex.replace("*", ".*");
}}

and of course, inject corsConfig from configuration classes like this:

    @Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public CorsWebFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    RegexCorsConfiguration regexCorsConfiguration = new RegexCorsConfiguration();
    regexCorsConfiguration.setAllowCredentials(true);

    regexCorsConfiguration.setAllowedOriginRegex(corsConfigData.getAllowedOrigins());
    regexCorsConfiguration.setAllowedHeaders(corsConfigData.getAllowedHeaders());
    regexCorsConfiguration.setAllowedMethods(corsConfigData.getAllowedMethods());

    source.registerCorsConfiguration("/**", regexCorsConfiguration);
    return new CorsWebFilter(source);
}
like image 131
brebDev Avatar answered Oct 17 '22 08:10

brebDev


I think, as indicated in responses to this question, the CORS specification doesn't allow for wildcarding a subdomain. Specifically see https://www.w3.org/TR/cors/#access-control-allow-origin-response-header

You could follow their advice on that answer and move the processing into some middleware layer like NGINX or Apache which could set the CORS header dynamically based on the domain in the request, or specify all the the subdomains you'd want in the spring boot config if that doesn't total into an unmanageable amount.

Although, in the first part of your question you state that you accept requests from http://localhost:4200., this shouldn't be a problem if you don't need subdomains then you can just explicitly whitelist that one domain, or did I misunderstand?

like image 25
David Avatar answered Oct 17 '22 07:10

David