Search code examples
spring-mvcspring-securityspring-bootcorsstormpath

CorsFilter with Stormpath


I am trying to build my first application using Stormpath and Spring Boot. I don't find how to add a CORS Filter to the Stormpath servlet. As a result, my front end app cannot get the authentication token because the Access-Control-Allow-Origin header is missing.

With logs, I am sure that my CORS filter is called on methods that I control but, not on the request /oauth/token.

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {

    private final Logger log = LoggerFactory.getLogger(SimpleCorsFilter.class);

    public SimpleCorsFilter() {
        log.info("SimpleCORSFilter init");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

        log.debug("*********Enter Cors Filter***********");
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");

        chain.doFilter(req, res);
        log.debug("******* Exit Cors Filter ****");
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }

}

I also tried the approach in this blog https://shuaib.me/stormpath-java-backend/ and added the following lines in application.properties.

stormpath.web.accessToken.origin.authorizer.originUris = http://localhost:3002
stormpath.web.filters.cors = something.SimpleCorsFilter
stormpath.web.uris./logout = cors
stormpath.web.uris./register = cors
stormpath.web.uris./oauth/token = cors

I also tried to add a FilterRegistrationBean

@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("http://localhost");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(0);
    return bean;
}

All those attempts have the same results, they work for the methods in my Controllers but not, for the /oauth/token request.

Finally, this my pom

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>stormpath-basic</groupId>
<artifactId>stormpath-basic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.1.RELEASE</version>
    <relativePath /> 
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <stormpath.version>1.1.1</stormpath.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.stormpath.spring</groupId>
        <artifactId>stormpath-default-spring-boot-starter</artifactId>
        <version>${stormpath.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
        <version>1.4.1.RELEASE</version>
    </dependency>


    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.10</version>
    </dependency>

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
    <dependency>
        <groupId>com.jayway.jsonpath</groupId>
        <artifactId>json-path</artifactId>
    </dependency>


    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Am I missing something?


Solution

  • Spring Boot supports Cross-Origin Resource Sharing (CORS), but it only works for Spring MVC, not Spring Security. Spring Framework provides a CorsFilter you can use for filter-based frameworks. It looks like you're already doing this with your FilterRegistrationBean.

    I encountered this same issue last week while writing a blog post about it. After debugging, I figured out this was because the main StormpathFilter comes before the CorsFilter.

    To fix this, add the following to application.properties.

    stormpath.web.stormpathFilter.order=1