Skip to content

Commit

Permalink
See #61. Use Spring Security built-in CORS support.
Browse files Browse the repository at this point in the history
  • Loading branch information
mwarman committed Dec 11, 2018
1 parent 1632ba2 commit 366ded9
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 75 deletions.
178 changes: 178 additions & 0 deletions src/main/java/com/leanstacks/ws/security/CorsProperties.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package com.leanstacks.ws.security;

import java.util.Arrays;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* A container for CORS configuration values.
*
* @author Matt Warman
*
*/
@ConfigurationProperties("leanstacks.cors")
public class CorsProperties {

/**
* The path at which the CorsFilter is registered. The CorsFilter will handle all requests matching this path.
*/
private String filterRegistrationPath = "/**";

/**
* The value of the Access-Control-Allow-Credentials header.
*/
private Boolean allowCredentials = false;

/**
* The value of the Access-Control-Allow-Headers header.
*/
private List<String> allowedHeaders = Arrays.asList("accept", "content-type");

/**
* The value of the Access-Control-Allow-Methods header.
*/
private List<String> allowedMethods = Arrays.asList("GET");

/**
* The value of the Access-Control-Allow-Origin header.
*/
private List<String> allowedOrigins = Arrays.asList("*");

/**
* The value of the Access-Control-Expose-Headers header.
*/
private List<String> exposedHeaders;

/**
* The value of the Access-Control-Max-Age header.
*/
private Long maxAgeSeconds = 1800L;

/**
* Returns the filter registration path.
*
* @return A String.
*/
public String getFilterRegistrationPath() {
return filterRegistrationPath;
}

/**
* Sets the filter registration path.
*
* @param filterRegistrationPath A String.
*/
public void setFilterRegistrationPath(final String filterRegistrationPath) {
this.filterRegistrationPath = filterRegistrationPath;
}

/**
* Returns the value of the Access-Control-Allow-Credentials header.
*
* @return A Boolean.
*/
public Boolean getAllowCredentials() {
return allowCredentials;
}

/**
* Sets the value of the Access-Control-Allow-Credentials header.
*
* @param allowCredentials A Boolean.
*/
public void setAllowCredentials(final Boolean allowCredentials) {
this.allowCredentials = allowCredentials;
}

/**
* Returns the value of the Access-Control-Allow-Headers header.
*
* @return A List of Strings.
*/
public List<String> getAllowedHeaders() {
return allowedHeaders;
}

/**
* Sets the value of the Access-Control-Allow-Headers header.
*
* @param allowedHeaders A List of Strings.
*/
public void setAllowedHeaders(final List<String> allowedHeaders) {
this.allowedHeaders = allowedHeaders;
}

/**
* Returns the value of the Access-Control-Allow-Methods header.
*
* @return A List of Strings.
*/
public List<String> getAllowedMethods() {
return allowedMethods;
}

/**
* Sets the value of the Access-Control-Allow-Methods header.
*
* @param allowedMethods A List of Strings.
*/
public void setAllowedMethods(final List<String> allowedMethods) {
this.allowedMethods = allowedMethods;
}

/**
* Returns the value of the Access-Control-Allow-Origin header.
*
* @return A List of Strings.
*/
public List<String> getAllowedOrigins() {
return allowedOrigins;
}

/**
* Sets the value of the Access-Control-Allow-Origin header.
*
* @param allowedOrigins A List of Strings.
*/
public void setAllowedOrigins(final List<String> allowedOrigins) {
this.allowedOrigins = allowedOrigins;
}

/**
* Returns the value of the Access-Control-Expose-Headers header.
*
* @return A List of Strings.
*/
public List<String> getExposedHeaders() {
return exposedHeaders;
}

/**
* Sets the value of the Access-Control-Expose-Headers header.
*
* @param exposedHeaders A List of Strings.
*/
public void setExposedHeaders(final List<String> exposedHeaders) {
this.exposedHeaders = exposedHeaders;
}

/**
* Returns the value of the Access-Control-Max-Age header in seconds.
*
* @return A Long.
*/
public Long getMaxAgeSeconds() {
return maxAgeSeconds;
}

/**
* Sets the value of the Access-Control-Max-Age header in seconds.
*
* @param maxAgeSeconds A Long.
*/
public void setMaxAgeSeconds(final Long maxAgeSeconds) {
this.maxAgeSeconds = maxAgeSeconds;
}

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.leanstacks.ws;
package com.leanstacks.ws.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
Expand All @@ -14,9 +16,9 @@
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;

import com.leanstacks.ws.security.AccountAuthenticationProvider;
import com.leanstacks.ws.security.RestBasicAuthenticationEntryPoint;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

/**
* The SecurityConfiguration class provides a centralized location for application security configuration. This class
Expand All @@ -26,6 +28,7 @@
*/
@Configuration
@EnableWebSecurity
@EnableConfigurationProperties(CorsProperties.class)
public class SecurityConfiguration {

/**
Expand Down Expand Up @@ -67,21 +70,51 @@ public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exce
@Order(1)
public static class ApiWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

/**
* The CORS configuration.
*/
@Autowired
private transient CorsProperties corsProperties;

/**
* Defines a ConfigurationSource for CORS attributes.
*
* @return A CorsConfigurationSource.
*/
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(corsProperties.getAllowedOrigins());
configuration.setAllowedMethods(corsProperties.getAllowedMethods());
configuration.setAllowedHeaders(corsProperties.getAllowedHeaders());
configuration.setAllowCredentials(corsProperties.getAllowCredentials());
configuration.setExposedHeaders(corsProperties.getExposedHeaders());
configuration.setMaxAge(corsProperties.getMaxAgeSeconds());

final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration(corsProperties.getFilterRegistrationPath(), configuration);
return source;
}

@Override
protected void configure(final HttpSecurity http) throws Exception {

// @formatter:off

http
.csrf().disable()
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.httpBasic().authenticationEntryPoint(apiAuthenticationEntryPoint())
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
.cors()
.and()
.csrf().disable()
.requestMatchers().antMatchers("/api/**")
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().hasRole("USER")
.and()
.httpBasic().authenticationEntryPoint(apiAuthenticationEntryPoint())
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);

// @formatter:on

Expand Down Expand Up @@ -118,18 +151,18 @@ protected void configure(final HttpSecurity http) throws Exception {
// @formatter:off

http
.csrf().disable()
.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests()
// Permit access to health check
.requestMatchers(EndpointRequest.to("health")).permitAll()
// Require authorization for everthing else
.anyRequest().hasRole("SYSADMIN")
.and()
.httpBasic().authenticationEntryPoint(actuatorAuthenticationEntryPoint())
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
.csrf().disable()
.requestMatcher(EndpointRequest.toAnyEndpoint())
.authorizeRequests()
// Permit access to health check
.requestMatchers(EndpointRequest.to("health")).permitAll()
// Require authorization for everthing else
.anyRequest().hasRole("SYSADMIN")
.and()
.httpBasic().authenticationEntryPoint(actuatorAuthenticationEntryPoint())
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);

// @formatter:on

Expand Down Expand Up @@ -167,11 +200,11 @@ protected void configure(final HttpSecurity http) throws Exception {
// @formatter:off

http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();

// @formatter:on

Expand Down
45 changes: 0 additions & 45 deletions src/main/java/com/leanstacks/ws/web/filter/SimpleCorsFilter.java

This file was deleted.

11 changes: 11 additions & 0 deletions src/main/resources/config/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,14 @@ logging.level.org.springframework.security=INFO
# Uncomment the 2 hibernate appenders below to show SQL and params in logs
logging.level.org.hibernate.SQL=DEBUG
#logging.level.org.hibernate.type.descriptor.sql=TRACE

##
# CORS Configuration
##
leanstacks.cors.filter-registration-path=/**
leanstacks.cors.allow-credentials=false
leanstacks.cors.allowed-headers=accept,authorization,content-type
leanstacks.cors.allowed-methods=GET,OPTIONS,POST,PUT,PATCH,DELETE
leanstacks.cors.allowed-origins=*
leanstacks.cors.exposed-headers=
leanstacks.cors.max-age-seconds=3600

0 comments on commit 366ded9

Please sign in to comment.