From 8aa56aad588f41879750f67db072b193b8c61321 Mon Sep 17 00:00:00 2001 From: Peter Bagrij Date: Wed, 24 Jan 2024 15:06:28 +0100 Subject: [PATCH] FINERACT-1971 Fixing CORS config --- .../core/filters/ResponseCorsFilter.java | 49 ------------------- .../core/config/SecurityConfig.java | 32 ++++++++---- 2 files changed, 22 insertions(+), 59 deletions(-) delete mode 100644 fineract-core/src/main/java/org/apache/fineract/infrastructure/core/filters/ResponseCorsFilter.java diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/filters/ResponseCorsFilter.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/filters/ResponseCorsFilter.java deleted file mode 100644 index 478c9b525..000000000 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/filters/ResponseCorsFilter.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.infrastructure.core.filters; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import org.springframework.util.StringUtils; -import org.springframework.web.filter.OncePerRequestFilter; - -/** - * Filter that returns a response with headers that allows for Cross-Origin Requests (CORs) to be performed against the - * platform API. - */ - -public class ResponseCorsFilter extends OncePerRequestFilter { - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - response.addHeader("Access-Control-Allow-Origin", "*"); - response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); - - final String reqHead = request.getHeader("Access-Control-Request-Headers"); - - if (StringUtils.hasText(reqHead)) { - response.addHeader("Access-Control-Allow-Headers", reqHead); - } - filterChain.doFilter(request, response); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java index 9a7d45d87..f8ac86015 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java @@ -24,6 +24,7 @@ import static org.springframework.security.authorization.AuthorityAuthorizationM import static org.springframework.security.authorization.AuthorizationManagers.allOf; import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher; +import java.util.List; import java.util.Objects; import org.apache.fineract.commands.domain.CommandSourceRepository; import org.apache.fineract.commands.service.CommandSourceService; @@ -35,7 +36,6 @@ import org.apache.fineract.infrastructure.core.filters.CorrelationHeaderFilter; import org.apache.fineract.infrastructure.core.filters.IdempotencyStoreFilter; import org.apache.fineract.infrastructure.core.filters.IdempotencyStoreHelper; import org.apache.fineract.infrastructure.core.filters.RequestResponseFilter; -import org.apache.fineract.infrastructure.core.filters.ResponseCorsFilter; import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; import org.apache.fineract.infrastructure.core.service.MDCWrapper; import org.apache.fineract.infrastructure.instancemode.filter.FineractInstanceModeApiFilter; @@ -60,6 +60,7 @@ import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; @@ -69,6 +70,9 @@ import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.access.ExceptionTranslationFilter; import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; import org.springframework.security.web.context.SecurityContextHolderFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @Configuration @ConditionalOnProperty("fineract.security.basicauth.enabled") @@ -131,13 +135,13 @@ public class SecurityConfig { .requestMatchers(antMatcher("/api/**")) .access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"))); // }).httpBasic((httpBasic) -> httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint())) // - .csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients + .cors(Customizer.withDefaults()).csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that + // is used by non-browser clients .sessionManagement((smc) -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // .addFilterBefore(tenantAwareBasicAuthenticationFilter(), SecurityContextHolderFilter.class) // .addFilterAfter(requestResponseFilter(), ExceptionTranslationFilter.class) // .addFilterAfter(correlationHeaderFilter(), RequestResponseFilter.class) // - .addFilterAfter(responseCorsFilter(), CorrelationHeaderFilter.class) // - .addFilterAfter(fineractInstanceModeApiFilter(), ResponseCorsFilter.class); // + .addFilterAfter(fineractInstanceModeApiFilter(), CorrelationHeaderFilter.class); // if (!Objects.isNull(loanCOBFilterHelper)) { http.addFilterAfter(loanCOBApiFilter(), FineractInstanceModeApiFilter.class) // .addFilterAfter(idempotencyStoreFilter(), LoanCOBApiFilter.class); // @@ -146,9 +150,9 @@ public class SecurityConfig { } if (fineractProperties.getSecurity().getTwoFactor().isEnabled()) { - http.addFilterAfter(twoFactorAuthenticationFilter(), ResponseCorsFilter.class); + http.addFilterAfter(twoFactorAuthenticationFilter(), CorrelationHeaderFilter.class); } else { - http.addFilterAfter(insecureTwoFactorAuthenticationFilter(), ResponseCorsFilter.class); + http.addFilterAfter(insecureTwoFactorAuthenticationFilter(), CorrelationHeaderFilter.class); } if (serverProperties.getSsl().isEnabled()) { @@ -186,10 +190,6 @@ public class SecurityConfig { return new CorrelationHeaderFilter(fineractProperties, mdcWrapper); } - public ResponseCorsFilter responseCorsFilter() { - return new ResponseCorsFilter(); - } - public TenantAwareBasicAuthenticationFilter tenantAwareBasicAuthenticationFilter() throws Exception { TenantAwareBasicAuthenticationFilter filter = new TenantAwareBasicAuthenticationFilter(authenticationManagerBean(), basicAuthenticationEntryPoint(), toApiJsonSerializer, configurationDomainService, cacheWritePlatformService, @@ -224,4 +224,16 @@ public class SecurityConfig { providerManager.setEraseCredentialsAfterAuthentication(false); return providerManager; } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOriginPatterns(List.of("*")); + configuration.setAllowedMethods(List.of("*")); + configuration.setAllowCredentials(true); + configuration.setAllowedHeaders(List.of("*")); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } }