Skip to content

Commit 0fd0b4e

Browse files
authored
#329: Added CORS starter (#330)
1 parent 7e3b2ff commit 0fd0b4e

File tree

12 files changed

+328
-34
lines changed

12 files changed

+328
-34
lines changed

documentation/guide-cors-support.asciidoc

+49-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ toc::[]
33

44
= CORS support
55

6-
When you are developing Javascript client and server application separately, you have to deal with cross domain issues. We have to request from a origin domain distinct to target domain and browser does not allow this.
6+
When you are developing Javascript client and server application separately, you have to deal with cross domain issues. We have to request from a origin domain distinct to target domain and browser does not allow this.
77

88
So , we need to prepare server side to accept request from other domains. We need to cover the following points:
99

@@ -17,12 +17,56 @@ It is important to note that if you are using security in your request (sending
1717

1818
== Configuring CORS support
1919

20-
On the server side we have defined a new filter in Spring security chain filters to support CORS and we have configured devonfw security chain filter to use it.
20+
=== Dependency
2121

22-
You only have to change `CORSDisabled` property value in `application-default.properties` properties file.
22+
To enable the CORS support from the server side add the below dependency.
23+
24+
[source,xml]
25+
----
26+
<dependency>
27+
<groupId>com.devonfw.java.starters</groupId>
28+
<artifactId>devon4j-starter-security-cors</artifactId>
29+
</dependency>
30+
----
31+
32+
=== Configuration
33+
34+
Add the below properties in your application.properties file.
2335

2436
[source]
2537
----
2638
#CORS support
27-
security.cors.enabled=false
28-
----
39+
security.cors.spring.allowCredentials=true
40+
security.cors.spring.allowedOrigins=*
41+
security.cors.spring.allowedHeaders=*
42+
security.cors.spring.allowedMethods=OPTIONS,HEAD,GET,PUT,POST,DELETE,PATCH
43+
security.cors.pathPattern=/**
44+
----
45+
46+
47+
[cols="1,1,1"]
48+
|===
49+
|Attribute |Description |HTTP Header
50+
51+
|allowCredentials
52+
|Decides the browser should include any cookies associated with the request (`true` if cookies should be included).
53+
|Access-Control-Allow-Credentials
54+
55+
|allowedOrigins
56+
|List of allowed origins (use `*` to allow all orgins).
57+
|Access-Control-Allow-Origin
58+
59+
|allowedMethods
60+
|List of allowed HTTP request methods (`OPTIONS`, `HEAD`, `GET`, `PUT`, `POST`, `DELETE`, `PATCH`, etc.).
61+
|-
62+
63+
|allowedHeaders
64+
|List of allowed headers that can be used during the request (use `*` to allow all headers requested by the client)
65+
|Access-Control-Allow-Headers
66+
67+
|pathPattern
68+
|Ant-style pattern for the URL paths where to apply CORS. Use "/**" to match all URL paths.
69+
|
70+
|===
71+
72+
More information about the CORS headers can be found https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#cors[here]

modules/security-cors/pom.xml

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>com.devonfw.java.dev</groupId>
7+
<artifactId>devon4j-modules</artifactId>
8+
<version>dev-SNAPSHOT</version>
9+
</parent>
10+
<groupId>com.devonfw.java.modules</groupId>
11+
<artifactId>devon4j-security-cors</artifactId>
12+
<version>${devon4j.version}</version>
13+
<packaging>jar</packaging>
14+
<name>${project.artifactId}</name>
15+
<description>Security Module of the Open Application Standard Platform for Java (devon4j) specifically for Cors protection.</description>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>org.springframework.boot</groupId>
20+
<artifactId>spring-boot-starter</artifactId>
21+
</dependency>
22+
<dependency>
23+
<groupId>com.devonfw.java.modules</groupId>
24+
<artifactId>devon4j-security</artifactId>
25+
</dependency>
26+
<dependency>
27+
<groupId>com.devonfw.java.modules</groupId>
28+
<artifactId>devon4j-rest</artifactId>
29+
</dependency>
30+
<dependency>
31+
<groupId>javax.servlet</groupId>
32+
<artifactId>javax.servlet-api</artifactId>
33+
<scope>provided</scope>
34+
</dependency>
35+
<dependency>
36+
<groupId>org.springframework.boot</groupId>
37+
<artifactId>spring-boot-configuration-processor</artifactId>
38+
<optional>true</optional>
39+
</dependency>
40+
<dependency>
41+
<groupId>com.devonfw.java.modules</groupId>
42+
<artifactId>devon4j-test</artifactId>
43+
<scope>test</scope>
44+
</dependency>
45+
</dependencies>
46+
47+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.devonfw.module.security.cors.common.impl;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
6+
import com.devonfw.module.security.common.api.config.WebSecurityConfigurerAspect;
7+
8+
/**
9+
* Auto-{@link Configuration} for spring to enable CORS protection.
10+
*
11+
* @since 2020.12.002
12+
*/
13+
@Configuration
14+
public class CorsAutoConfiguration {
15+
16+
/**
17+
* @return the {@link WebSecurityConfigurerAspect} to enable CORS.
18+
*/
19+
@Bean
20+
public WebSecurityConfigurerAspect corsConfigAspect() {
21+
22+
return new WebSecurityConfigurerAspectCors();
23+
}
24+
25+
/**
26+
* @return the {@link CorsConfigProperties} to configure CORS.
27+
*/
28+
@Bean
29+
public CorsConfigProperties corsConfigProperties() {
30+
31+
return new CorsConfigProperties();
32+
}
33+
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.devonfw.module.security.cors.common.impl;
2+
3+
import org.springframework.boot.context.properties.ConfigurationProperties;
4+
import org.springframework.web.cors.CorsConfiguration;
5+
6+
/**
7+
* {@link ConfigurationProperties} to configure Cross-Origin Resource Sharing (CORS).
8+
*
9+
* @since 2020.12.002
10+
*/
11+
@ConfigurationProperties(prefix = "security.cors")
12+
public class CorsConfigProperties extends CorsConfiguration {
13+
private CorsConfiguration spring;
14+
15+
private String pathPattern = "/**";
16+
17+
/**
18+
* @return the {@link CorsConfiguration} from spring-web.
19+
*/
20+
public CorsConfiguration getSpring() {
21+
22+
return this.spring;
23+
}
24+
25+
/**
26+
* Sets the cors configuration from the properties file.
27+
*
28+
* @param spring
29+
* @return
30+
*/
31+
public void setSpring(CorsConfiguration spring) {
32+
33+
this.spring = spring;
34+
}
35+
36+
/**
37+
* @return the ant-style pattern for the URL paths where to apply CORS. Use "/**" to match all URL paths.
38+
* @see org.springframework.web.cors.UrlBasedCorsConfigurationSource#registerCorsConfiguration(String,
39+
* CorsConfiguration)
40+
*/
41+
public String getPathPattern() {
42+
43+
return this.pathPattern;
44+
}
45+
46+
/**
47+
* @param pathPattern the new value of {@link #getPathPattern()}.
48+
*/
49+
public void setPathPattern(String pathPattern) {
50+
51+
this.pathPattern = pathPattern;
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.devonfw.module.security.cors.common.impl;
2+
3+
import javax.inject.Inject;
4+
5+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6+
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
7+
import org.springframework.web.filter.CorsFilter;
8+
9+
import com.devonfw.module.security.common.api.config.WebSecurityConfigurerAspect;
10+
11+
/**
12+
* Implementation of {@link WebSecurityConfigurerAspect} for CORS protection.
13+
*
14+
* @since 2020.12.002
15+
*/
16+
public class WebSecurityConfigurerAspectCors implements WebSecurityConfigurerAspect {
17+
18+
private CorsConfigProperties corsConfigProperties;
19+
20+
/**
21+
* @param corsConfigProperties new value of {@link #getcorsConfigProperties}.
22+
*/
23+
@Inject
24+
public void setCorsConfigProperties(CorsConfigProperties corsConfigProperties) {
25+
26+
this.corsConfigProperties = corsConfigProperties;
27+
}
28+
29+
private CorsFilter getCorsFilter() {
30+
31+
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
32+
source.registerCorsConfiguration(this.corsConfigProperties.getPathPattern(), this.corsConfigProperties.getSpring());
33+
return new CorsFilter(source);
34+
}
35+
36+
@Override
37+
public HttpSecurity configure(HttpSecurity http) throws Exception {
38+
39+
return http.addFilter(getCorsFilter());
40+
}
41+
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.devonfw.test.app;
2+
3+
import org.springframework.boot.autoconfigure.SpringBootApplication;
4+
import org.springframework.context.annotation.Import;
5+
6+
import com.devonfw.module.security.cors.common.impl.CorsAutoConfiguration;
7+
8+
/**
9+
* Spring-boot app for testing.
10+
*/
11+
@SpringBootApplication
12+
@Import({ CorsAutoConfiguration.class })
13+
public class TestApplication {
14+
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.devonfw.test.app;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.mockito.Mockito.mock;
5+
6+
import java.util.HashMap;
7+
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.extension.ExtendWith;
11+
import org.mockito.junit.jupiter.MockitoExtension;
12+
import org.springframework.security.config.annotation.ObjectPostProcessor;
13+
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
14+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
15+
16+
import com.devonfw.module.security.cors.common.impl.CorsConfigProperties;
17+
import com.devonfw.module.security.cors.common.impl.WebSecurityConfigurerAspectCors;
18+
19+
/**
20+
* WebSecurityConfigurerAspectCorsTest
21+
*/
22+
23+
@ExtendWith(MockitoExtension.class)
24+
public class WebSecurityConfigurerAspectCorsTest {
25+
26+
private WebSecurityConfigurerAspectCors webSecurityConfigurerAspectCors;
27+
28+
@BeforeEach
29+
public void init() {
30+
31+
this.webSecurityConfigurerAspectCors = new WebSecurityConfigurerAspectCors();
32+
CorsConfigProperties corsConfigProperties = new CorsConfigProperties();
33+
this.webSecurityConfigurerAspectCors.setCorsConfigProperties(corsConfigProperties);
34+
}
35+
36+
/**
37+
* To test webSecurityConfigurer configure
38+
*
39+
* @throws Exception
40+
*/
41+
@Test
42+
public void shouldConfigure_withProperties() throws Exception {
43+
44+
// Arrange
45+
HttpSecurity expectedHttp = new HttpSecurity(mock(ObjectPostProcessor.class),
46+
mock(AuthenticationManagerBuilder.class), new HashMap<>());
47+
// Act
48+
HttpSecurity resultHttp = this.webSecurityConfigurerAspectCors.configure(expectedHttp);
49+
// Assert
50+
assertThat(resultHttp).isEqualTo(expectedHttp);
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
security.cors.spring.allowCredentials=true
2+
security.cors.spring.allowedOrigins=*
3+
security.cors.spring.allowedHeaders=*
4+
security.cors.spring.allowedMethods=OPTIONS,HEAD,GET,PUT,POST,DELETE,PATCH
5+
security.cors.pathPattern=/**
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>com.devonfw.java.dev</groupId>
7+
<artifactId>devon4j-starters</artifactId>
8+
<version>dev-SNAPSHOT</version>
9+
</parent>
10+
<groupId>com.devonfw.java.starters</groupId>
11+
<artifactId>devon4j-starter-security-cors</artifactId>
12+
<version>${devon4j.version}</version>
13+
<packaging>jar</packaging>
14+
<name>${project.artifactId}</name>
15+
<description>Spring-boot starter for CORS protection.</description>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>com.devonfw.java.starters</groupId>
20+
<artifactId>devon4j-starter-security</artifactId>
21+
</dependency>
22+
<dependency>
23+
<groupId>com.devonfw.java.modules</groupId>
24+
<artifactId>devon4j-security-cors</artifactId>
25+
</dependency>
26+
</dependencies>
27+
28+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.devonfw.module.security.cors.common.impl.CorsAutoConfiguration

0 commit comments

Comments
 (0)