Skip to content

Commit 8391614

Browse files
committed
FINERACT-2326: Add configuration options for CORS handling
1 parent df4f430 commit 8391614

File tree

5 files changed

+73
-9
lines changed

5 files changed

+73
-9
lines changed

fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ public static class FineractSecurityProperties {
519519
private FineractSecurityTwoFactorAuth twoFactor;
520520
private FineractSecurityHsts hsts;
521521
private FineractSecurityOAuth2Properties oauth2;
522+
private CorsProperties cors;
522523

523524
public void set2fa(FineractSecurityTwoFactorAuth twoFactor) {
524525
this.twoFactor = twoFactor;
@@ -688,4 +689,16 @@ public static class ExecuteCommandProperties {
688689
}
689690
}
690691
}
692+
693+
@Getter
694+
@Setter
695+
public static class CorsProperties {
696+
697+
private boolean enabled;
698+
private List<String> allowedOrigins;
699+
private List<String> allowedMethods;
700+
private List<String> allowedHeaders;
701+
private List<String> exposedHeaders;
702+
private boolean allowCredentials;
703+
}
691704
}

fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
160160
.requestMatchers(antMatcher("/api/**"))
161161
.access(allOf(authorizationManagers.toArray(new AuthorizationManager[0]))); //
162162
}).httpBasic((httpBasic) -> httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint())) //
163-
.cors(Customizer.withDefaults()).csrf(AbstractHttpConfigurer::disable) // NOSONAR only creating a
164-
// service that
163+
.csrf(AbstractHttpConfigurer::disable) // NOSONAR only creating a
164+
// service that
165165
// is used by non-browser clients
166166
.sessionManagement((smc) -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
167167
.addFilterBefore(tenantAwareBasicAuthenticationFilter(), SecurityContextHolderFilter.class) //
@@ -189,6 +189,9 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
189189
http.requiresChannel(channel -> channel.anyRequest().requiresSecure()).headers(
190190
headers -> headers.httpStrictTransportSecurity(hsts -> hsts.includeSubDomains(true).maxAgeInSeconds(31536000)));
191191
}
192+
if (fineractProperties.getSecurity().getCors().isEnabled()) {
193+
http.cors(Customizer.withDefaults());
194+
}
192195
return http.build();
193196
}
194197

@@ -258,13 +261,16 @@ public AuthenticationManager authenticationManagerBean() throws Exception {
258261

259262
@Bean
260263
public CorsConfigurationSource corsConfigurationSource() {
261-
CorsConfiguration configuration = new CorsConfiguration();
262-
configuration.setAllowedOriginPatterns(List.of("*"));
263-
configuration.setAllowedMethods(List.of("*"));
264-
configuration.setAllowCredentials(true);
265-
configuration.setAllowedHeaders(List.of("*"));
264+
CorsConfiguration config = new CorsConfiguration();
265+
FineractProperties.CorsProperties corsConfiguration = fineractProperties.getSecurity().getCors();
266+
config.setAllowedOrigins(corsConfiguration.getAllowedOrigins());
267+
config.setAllowedMethods(corsConfiguration.getAllowedMethods());
268+
config.setAllowedHeaders(corsConfiguration.getAllowedHeaders());
269+
config.setExposedHeaders(corsConfiguration.getExposedHeaders());
270+
config.setAllowCredentials(corsConfiguration.isAllowCredentials()); // if you use cookies / Authorization header
271+
266272
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
267-
source.registerCorsConfiguration("/**", configuration);
273+
source.registerCorsConfiguration("/**", config);
268274
return source;
269275
}
270276
}

fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/config/AuthorizationServerConfig.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.springframework.core.annotation.Order;
5656
import org.springframework.security.authentication.AuthenticationDetailsSource;
5757
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
58+
import org.springframework.security.config.Customizer;
5859
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
5960
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
6061
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
@@ -78,6 +79,9 @@
7879
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
7980
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
8081
import org.springframework.security.web.context.SecurityContextHolderFilter;
82+
import org.springframework.web.cors.CorsConfiguration;
83+
import org.springframework.web.cors.CorsConfigurationSource;
84+
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
8185
import org.springframework.web.filter.OncePerRequestFilter;
8286

8387
@Configuration
@@ -121,6 +125,10 @@ public SecurityFilterChain publicEndpoints(HttpSecurity http) throws Exception {
121125
http.securityMatcher("/swagger-ui/**", "/fineract.json", "/actuator/**", "/legacy-docs/apiLive.htm")
122126
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll()).csrf(AbstractHttpConfigurer::disable);
123127

128+
if (fineractProperties.getSecurity().getCors().isEnabled()) {
129+
http.cors(Customizer.withDefaults());
130+
}
131+
124132
return http.build();
125133
}
126134

@@ -137,14 +145,17 @@ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity h
137145
.exceptionHandling(exceptions -> exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")))
138146
.apply(authorizationServerConfigurer);
139147

148+
if (fineractProperties.getSecurity().getCors().isEnabled()) {
149+
http.cors(Customizer.withDefaults());
150+
}
151+
140152
return http.build();
141153
}
142154

143155
@Bean
144156
@Order(3)
145157
public SecurityFilterChain protectedEndpoints(HttpSecurity http) throws Exception {
146158
http
147-
// .securityMatcher(new AntPathRequestMatcher("/api/**"))
148159
// TODO: Make it configurable
149160
.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(auth -> {
150161
auth.anyRequest().authenticated();
@@ -171,9 +182,27 @@ public SecurityFilterChain protectedEndpoints(HttpSecurity http) throws Exceptio
171182
if (fineractProperties.getSecurity().getTwoFactor().isEnabled()) {
172183
http.addFilterAfter(twoFactorAuthenticationFilter(), CorrelationHeaderFilter.class);
173184
}
185+
if (fineractProperties.getSecurity().getCors().isEnabled()) {
186+
http.cors(Customizer.withDefaults());
187+
}
174188
return http.build();
175189
}
176190

191+
@Bean
192+
public CorsConfigurationSource corsConfigurationSource() {
193+
CorsConfiguration config = new CorsConfiguration();
194+
FineractProperties.CorsProperties corsConfiguration = fineractProperties.getSecurity().getCors();
195+
config.setAllowedOrigins(corsConfiguration.getAllowedOrigins());
196+
config.setAllowedMethods(corsConfiguration.getAllowedMethods());
197+
config.setAllowedHeaders(corsConfiguration.getAllowedHeaders());
198+
config.setExposedHeaders(corsConfiguration.getExposedHeaders());
199+
config.setAllowCredentials(corsConfiguration.isAllowCredentials()); // if you use cookies / Authorization header
200+
201+
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
202+
source.registerCorsConfiguration("/**", config);
203+
return source;
204+
}
205+
177206
@Bean
178207
public OncePerRequestFilter tenantAwareAuthenticationFilter() {
179208
return new TenantAwareAuthenticationFilter(resolver(), tenantDetailsService);

fineract-provider/src/main/resources/application.properties

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ fineract.security.oauth2.enabled=${FINERACT_SECURITY_OAUTH_ENABLED:false}
2626
fineract.security.2fa.enabled=${FINERACT_SECURITY_2FA_ENABLED:false}
2727
fineract.security.hsts.enabled=${FINERACT_SECURITY_HSTS_ENABLED:false}
2828

29+
#CORS configuration
30+
fineract.security.cors.enabled=${FINERACT_SECURITY_CORS_ENABLED:true}
31+
fineract.security.cors.allowed-origins=${FINERACT_SECURITY_CORS_ALLOWED_ORIGINS:"*"}
32+
fineract.security.cors.allowed-methods=${FINERACT_SECURITY_CORS_ALLOWED_METHODS:"*"}
33+
fineract.security.cors.allowed-headers=${FINERACT_SECURITY_CORS_ALLOWED_HEADERS:"*"}
34+
fineract.security.cors.exposed-headers=${FINERACT_SECURITY_CORS_EXPOSED_HEADERS:"*"}
35+
fineract.security.cors.allow-credentials=${FINERACT_SECURITY_CORS_ALLOW_CREDENTIALS:true}
36+
2937
# EXAMPLE: OAuth2 client configuration (frontend-client)
3038
fineract.security.oauth2.client.registrations.frontend-client.client-id=${FINERACT_SECURITY_OAUTH2_CLIENTS_FRONTEND_ID:frontend-client}
3139
fineract.security.oauth2.client.registrations.frontend-client.scopes=${FINERACT_SECURITY_OAUTH2_CLIENTS_FRONTEND_SCOPES:read,write}

fineract-provider/src/test/resources/application-test.properties

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ fineract.security.oauth2.enabled=false
2525
fineract.security.2fa.enabled=false
2626
fineract.security.hsts.enabled=false
2727

28+
#CORS configuration
29+
fineract.security.cors.enabled=true
30+
fineract.security.cors.allowed-origins="*"
31+
fineract.security.cors.allowed-methods="*"
32+
fineract.security.cors.allowed-headers="*"
33+
fineract.security.cors.exposed-headers="*"
34+
fineract.security.cors.allow-credentials=true
35+
2836
fineract.tenant.host=localhost
2937
fineract.tenant.port=3306
3038
fineract.tenant.username=root

0 commit comments

Comments
 (0)