FINERACT-1724: Web security adjustments
This commit is contained in:
committed by
Arnold Gálovics
parent
c437c5a48b
commit
d87d483665
+31
-28
@@ -23,6 +23,7 @@ import static org.apache.fineract.infrastructure.security.vote.SelfServiceUserAu
|
||||
import static org.springframework.security.authorization.AuthenticatedAuthorizationManager.fullyAuthenticated;
|
||||
import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasAuthority;
|
||||
import static org.springframework.security.authorization.AuthorizationManagers.allOf;
|
||||
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
|
||||
|
||||
import java.util.Collection;
|
||||
import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
|
||||
@@ -32,6 +33,7 @@ import org.apache.fineract.infrastructure.core.exceptionmapper.OAuth2ExceptionEn
|
||||
import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
|
||||
import org.apache.fineract.infrastructure.security.data.PlatformRequestLog;
|
||||
import org.apache.fineract.infrastructure.security.filter.InsecureTwoFactorAuthenticationFilter;
|
||||
import org.apache.fineract.infrastructure.security.filter.TenantAwareTenantIdentifierFilter;
|
||||
import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter;
|
||||
import org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
|
||||
@@ -40,6 +42,7 @@ import org.apache.fineract.infrastructure.security.service.TwoFactorService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
@@ -73,7 +76,7 @@ public class OAuth2SecurityConfig {
|
||||
private ServerProperties serverProperties;
|
||||
|
||||
@Autowired
|
||||
private TwoFactorService twoFactorService;
|
||||
private FineractProperties fineractProperties;
|
||||
|
||||
@Autowired
|
||||
private BasicAuthTenantDetailsService basicAuthTenantDetailsService;
|
||||
@@ -89,45 +92,40 @@ public class OAuth2SecurityConfig {
|
||||
|
||||
@Autowired
|
||||
private BusinessDateReadPlatformService businessDateReadPlatformService;
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private static final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
|
||||
http //
|
||||
.securityMatcher("/api/**").authorizeHttpRequests((auth) -> {
|
||||
auth.requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/echo").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/authentication").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/self/authentication").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/self/registration").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/self/registration/user").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/twofactor/validate").fullyAuthenticated() //
|
||||
.requestMatchers("/api/*/twofactor").fullyAuthenticated() //
|
||||
.requestMatchers("/api/**")
|
||||
.access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"), selfServiceUserAuthManager())); //
|
||||
});
|
||||
|
||||
if (serverProperties.getSsl().isEnabled()) {
|
||||
http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
|
||||
}
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http //
|
||||
.csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
|
||||
.securityMatcher(antMatcher("/api/**")).authorizeHttpRequests((auth) -> {
|
||||
auth.requestMatchers(antMatcher(HttpMethod.OPTIONS, "/api/**")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/echo")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/authentication")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/self/authentication")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/self/registration")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/self/registration/user")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/twofactor/validate")).fullyAuthenticated() //
|
||||
.requestMatchers(antMatcher("/api/*/twofactor")).fullyAuthenticated() //
|
||||
.requestMatchers(antMatcher("/api/**"))
|
||||
.access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"), selfServiceUserAuthManager())); //
|
||||
}).csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
|
||||
.exceptionHandling((ehc) -> ehc.authenticationEntryPoint(new OAuth2ExceptionEntryPoint()))
|
||||
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(authenticationConverter()))
|
||||
.authenticationEntryPoint(new OAuth2ExceptionEntryPoint())) //
|
||||
.sessionManagement((smc) -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
|
||||
.addFilterAfter(tenantAwareTenantIdentifierFilter(), SecurityContextHolderFilter.class) //
|
||||
.addFilterAfter(twoFactorAuthenticationFilter(), BasicAuthenticationFilter.class); //
|
||||
.addFilterAfter(tenantAwareTenantIdentifierFilter(), SecurityContextHolderFilter.class);
|
||||
|
||||
if (fineractProperties.getSecurity().getTwoFactor().isEnabled()) {
|
||||
http.addFilterAfter(twoFactorAuthenticationFilter(), BasicAuthenticationFilter.class);
|
||||
} else {
|
||||
http.addFilterAfter(insecureTwoFactorAuthenticationFilter(), BasicAuthenticationFilter.class);
|
||||
}
|
||||
|
||||
if (serverProperties.getSsl().isEnabled()) {
|
||||
http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
|
||||
http.requiresChannel(channel -> channel.requestMatchers(antMatcher("/api/**")).requiresSecure());
|
||||
}
|
||||
|
||||
return http.build();
|
||||
@@ -139,9 +137,14 @@ public class OAuth2SecurityConfig {
|
||||
}
|
||||
|
||||
public TwoFactorAuthenticationFilter twoFactorAuthenticationFilter() {
|
||||
TwoFactorService twoFactorService = applicationContext.getBean(TwoFactorService.class);
|
||||
return new TwoFactorAuthenticationFilter(twoFactorService);
|
||||
}
|
||||
|
||||
public InsecureTwoFactorAuthenticationFilter insecureTwoFactorAuthenticationFilter() {
|
||||
return new InsecureTwoFactorAuthenticationFilter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||
|
||||
+23
-30
@@ -22,6 +22,7 @@ package org.apache.fineract.infrastructure.core.config;
|
||||
import static org.springframework.security.authorization.AuthenticatedAuthorizationManager.fullyAuthenticated;
|
||||
import static org.springframework.security.authorization.AuthorityAuthorizationManager.hasAuthority;
|
||||
import static org.springframework.security.authorization.AuthorizationManagers.allOf;
|
||||
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
|
||||
|
||||
import org.apache.fineract.commands.domain.CommandSourceRepository;
|
||||
import org.apache.fineract.commands.service.CommandSourceService;
|
||||
@@ -67,7 +68,6 @@ 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.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty("fineract.security.basicauth.enabled")
|
||||
@@ -114,48 +114,41 @@ public class SecurityConfig {
|
||||
@Autowired
|
||||
private IdempotencyStoreHelper idempotencyStoreHelper;
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
|
||||
http //
|
||||
.securityMatcher("/api/**").authorizeHttpRequests((auth) -> {
|
||||
auth.requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/echo").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/authentication").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/self/authentication").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/self/registration").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/self/registration/user").permitAll() //
|
||||
.requestMatchers(HttpMethod.PUT, "/api/*/instance-mode").permitAll() //
|
||||
.requestMatchers(HttpMethod.POST, "/api/*/twofactor/validate").fullyAuthenticated() //
|
||||
.requestMatchers("/api/*/twofactor").fullyAuthenticated() //
|
||||
.requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"))); //
|
||||
}) //
|
||||
.httpBasic((httpBasic) -> httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint()));
|
||||
|
||||
if (serverProperties.getSsl().isEnabled()) {
|
||||
http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
|
||||
}
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http //
|
||||
.securityMatcher(antMatcher("/api/**")).authorizeHttpRequests((auth) -> {
|
||||
auth.requestMatchers(antMatcher(HttpMethod.OPTIONS, "/api/**")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/echo")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/authentication")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/self/authentication")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/self/registration")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/self/registration/user")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.PUT, "/api/*/instance-mode")).permitAll() //
|
||||
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/twofactor/validate")).fullyAuthenticated() //
|
||||
.requestMatchers(antMatcher("/api/*/twofactor")).fullyAuthenticated() //
|
||||
.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
|
||||
.sessionManagement((smc) -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
|
||||
.addFilterBefore(tenantAwareBasicAuthenticationFilter(), SecurityContextHolderFilter.class)
|
||||
.addFilterAfter(requestResponseFilter(), ExceptionTranslationFilter.class)
|
||||
.addFilterAfter(correlationHeaderFilter(), RequestResponseFilter.class)
|
||||
.addFilterBefore(tenantAwareBasicAuthenticationFilter(), SecurityContextHolderFilter.class) //
|
||||
.addFilterAfter(requestResponseFilter(), ExceptionTranslationFilter.class) //
|
||||
.addFilterAfter(correlationHeaderFilter(), RequestResponseFilter.class) //
|
||||
.addFilterAfter(responseCorsFilter(), CorrelationHeaderFilter.class) //
|
||||
.addFilterAfter(fineractInstanceModeApiFilter(), ResponseCorsFilter.class) //
|
||||
.addFilterAfter(loanCOBApiFilter(), FineractInstanceModeApiFilter.class) //
|
||||
.addFilterAfter(idempotencyStoreFilter(), LoanCOBApiFilter.class); //
|
||||
|
||||
if (fineractProperties.getSecurity().getTwoFactor().isEnabled()) {
|
||||
http.addFilterAfter(twoFactorAuthenticationFilter(), FineractInstanceModeApiFilter.class);
|
||||
http.addFilterAfter(twoFactorAuthenticationFilter(), ResponseCorsFilter.class);
|
||||
} else {
|
||||
http.addFilterAfter(insecureTwoFactorAuthenticationFilter(), FineractInstanceModeApiFilter.class);
|
||||
http.addFilterAfter(insecureTwoFactorAuthenticationFilter(), ResponseCorsFilter.class);
|
||||
}
|
||||
|
||||
if (serverProperties.getSsl().isEnabled()) {
|
||||
http.requiresChannel(channel -> channel.requestMatchers(antMatcher("/api/**")).requiresSecure());
|
||||
}
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@@ -196,7 +189,7 @@ public class SecurityConfig {
|
||||
TenantAwareBasicAuthenticationFilter filter = new TenantAwareBasicAuthenticationFilter(authenticationManagerBean(),
|
||||
basicAuthenticationEntryPoint(), toApiJsonSerializer, configurationDomainService, cacheWritePlatformService,
|
||||
userNotificationService, basicAuthTenantDetailsService, businessDateReadPlatformService);
|
||||
filter.setRequestMatcher(AntPathRequestMatcher.antMatcher("/api/**"));
|
||||
filter.setRequestMatcher(antMatcher("/api/**"));
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -106,6 +106,7 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
|
||||
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
|
||||
// ignore to allow 'preflight' requests from AJAX applications
|
||||
// in different origin (domain name)
|
||||
filterChain.doFilter(request, response);
|
||||
} else {
|
||||
if (requestMatcher.matches(request)) {
|
||||
String tenantIdentifier = request.getHeader(this.tenantRequestHeader);
|
||||
|
||||
-4
@@ -42,9 +42,7 @@ import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.security.data.PlatformRequestLog;
|
||||
import org.apache.fineract.infrastructure.security.exception.InvalidTenantIdentifierException;
|
||||
import org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
/**
|
||||
@@ -58,8 +56,6 @@ import org.springframework.web.filter.GenericFilterBean;
|
||||
*
|
||||
* Used to support Oauth2 authentication and the service is loaded only when "oauth" profile is active.
|
||||
*/
|
||||
@Service
|
||||
@ConditionalOnProperty("fineract.security.oauth.enabled")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TenantAwareTenantIdentifierFilter extends GenericFilterBean {
|
||||
|
||||
Reference in New Issue
Block a user