From 2cc636cb923d5932d990541cc6f63c54291e70a0 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Tue, 21 Nov 2023 21:28:20 +0100 Subject: [PATCH] [kbss-cvut/record-manager#10] Support configuring allowedOrigins via explicit config parameter. --- README.md | 2 +- .../kbss/study/config/SecurityConfig.java | 45 ++++++++++--------- .../cz/cvut/kbss/study/util/ConfigParam.java | 4 +- src/main/resources/config.properties | 5 ++- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 35f45232..795e6b8e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Manager of records based on OFN (https://data.gov.cz/ofn/). ## Required Technologies - JDK 17 -- Apache Maven 3.5.x +- Apache Maven 3.5.x or later ## System Architecture diff --git a/src/main/java/cz/cvut/kbss/study/config/SecurityConfig.java b/src/main/java/cz/cvut/kbss/study/config/SecurityConfig.java index 5fb17609..f2afb558 100644 --- a/src/main/java/cz/cvut/kbss/study/config/SecurityConfig.java +++ b/src/main/java/cz/cvut/kbss/study/config/SecurityConfig.java @@ -5,8 +5,6 @@ import cz.cvut.kbss.study.security.SecurityConstants; import cz.cvut.kbss.study.service.ConfigReader; import cz.cvut.kbss.study.util.ConfigParam; -import java.net.MalformedURLException; -import java.net.URL; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -31,8 +29,9 @@ import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import java.util.Collections; -import java.util.List; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; @ConditionalOnProperty(prefix = "security", name = "provider", havingValue = "internal", matchIfMissing = true) @Configuration @@ -99,11 +98,7 @@ CorsConfigurationSource corsConfigurationSource(ConfigReader config) { static CorsConfigurationSource createCorsConfiguration(ConfigReader configReader) { final CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues(); corsConfiguration.setAllowedMethods(Collections.singletonList("*")); - URL appUrl = getApplicationContext(configReader); - if (appUrl != null) { - corsConfiguration.setAllowedOrigins(List.of(parseOrigin(appUrl))); - corsConfiguration.setAllowCredentials(true); - } + configureAllowedOrigins(corsConfiguration, configReader); corsConfiguration.addExposedHeader(HttpHeaders.AUTHORIZATION); corsConfiguration.addExposedHeader(HttpHeaders.LOCATION); corsConfiguration.addExposedHeader(HttpHeaders.CONTENT_DISPOSITION); @@ -113,23 +108,29 @@ static CorsConfigurationSource createCorsConfiguration(ConfigReader configReader return source; } - private static URL getApplicationContext(ConfigReader configReader) { - String appUrl = configReader.getConfig(ConfigParam.APP_CONTEXT); + private static void configureAllowedOrigins(CorsConfiguration corsConfig, ConfigReader config) { + final Optional appUrlOrigin = getApplicationUrlOrigin(config); + final List allowedOrigins = new ArrayList<>(); + appUrlOrigin.ifPresent(allowedOrigins::add); + final String allowedOriginsConfig = config.getConfig(ConfigParam.CORS_ALLOWED_ORIGINS); + allowedOrigins.addAll(Arrays.asList(allowedOriginsConfig.split(","))); + if (!allowedOrigins.isEmpty()) { + corsConfig.setAllowedOrigins(allowedOrigins); + corsConfig.setAllowCredentials(true); + } + } + + private static Optional getApplicationUrlOrigin(ConfigReader configReader) { + String appUrlConfig = configReader.getConfig(ConfigParam.APP_CONTEXT); - if (appUrl.isBlank()) { - return null; + if (appUrlConfig.isBlank()) { + return Optional.empty(); } try { - return new URL(appUrl); + final URL appUrl = new URL(appUrlConfig); + return Optional.of(appUrl.getProtocol() + "://" + appUrl.getHost() + (appUrl.getPort() != -1 ? ":" + appUrl.getPort() : "")); } catch (MalformedURLException e) { - throw new RecordManagerException( - "Invalid configuration parameter " + ConfigParam.APP_CONTEXT + ".", - e); + throw new RecordManagerException("Invalid configuration parameter " + ConfigParam.APP_CONTEXT + ".", e); } } - - private static String parseOrigin(URL url) { - return url.getProtocol() + "://" + url.getHost() - + (url.getPort() != -1 ? ":" + url.getPort() : ""); - } } diff --git a/src/main/java/cz/cvut/kbss/study/util/ConfigParam.java b/src/main/java/cz/cvut/kbss/study/util/ConfigParam.java index 4cc4c006..9a9c3360 100644 --- a/src/main/java/cz/cvut/kbss/study/util/ConfigParam.java +++ b/src/main/java/cz/cvut/kbss/study/util/ConfigParam.java @@ -33,7 +33,9 @@ public enum ConfigParam { E_PROFILE_UPDATE_SUBJECT("email.profileUpdateSubject"), E_PROFILE_UPDATE_CONTENT("email.profileUpdateContent"), - OIDC_ROLE_CLAIM("oidc.roleClaim"); + OIDC_ROLE_CLAIM("oidc.roleClaim"), + + CORS_ALLOWED_ORIGINS("cors.allowedOrigins"); private final String name; diff --git a/src/main/resources/config.properties b/src/main/resources/config.properties index 6349a441..acbe1cc0 100644 --- a/src/main/resources/config.properties +++ b/src/main/resources/config.properties @@ -58,4 +58,7 @@ security.provider=internal # Claim containing user roles in the OIDC access token (applies only when 'oidc' security provider is selected). Use # dot notation for nested objects -oidc.roleClaim=realm_access.roles \ No newline at end of file +oidc.roleClaim=realm_access.roles + +# Configures allowed origins for CORS. Use a comma to separate multiple values +cors.allowedOrigins= \ No newline at end of file