This is an automated email from the ASF dual-hosted git repository.
thenatog pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new a4ea92ea3b NIFI-10217 Refactored Registry Spring Security Configuration
a4ea92ea3b is described below
commit a4ea92ea3bc647e5afe40790fb121948d1fee2fe
Author: exceptionfactory <[email protected]>
AuthorDate: Mon Jul 11 15:04:22 2022 -0500
NIFI-10217 Refactored Registry Spring Security Configuration
Signed-off-by: Nathan Gough <[email protected]>
This closes #6196.
---
.../web/security/NiFiRegistrySecurityConfig.java | 147 ++++++---------------
1 file changed, 43 insertions(+), 104 deletions(-)
diff --git
a/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
b/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
index 86f956fe6f..cfcc8a3a6c 100644
---
a/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
+++
b/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
@@ -33,28 +33,24 @@ import
org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
-import
org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.authentication.ProviderManager;
import
org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity;
import
org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.SecurityFilterChain;
import
org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import
org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
-import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
/**
- * NiFi Registry Web Api Spring security
+ * Spring Security Filter Configuration
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
-public class NiFiRegistrySecurityConfig extends WebSecurityConfigurerAdapter {
+public class NiFiRegistrySecurityConfig {
private static final Logger logger =
LoggerFactory.getLogger(NiFiRegistrySecurityConfig.class);
@@ -67,28 +63,32 @@ public class NiFiRegistrySecurityConfig extends
WebSecurityConfigurerAdapter {
@Autowired
private Authorizer authorizer;
- private final AnonymousIdentityFilter anonymousAuthenticationFilter = new
AnonymousIdentityFilter();
-
@Autowired
private X509IdentityProvider x509IdentityProvider;
- private IdentityFilter x509AuthenticationFilter;
- private IdentityAuthenticationProvider x509AuthenticationProvider;
@Autowired
private JwtIdentityProvider jwtIdentityProvider;
- private IdentityFilter jwtAuthenticationFilter;
- private IdentityAuthenticationProvider jwtAuthenticationProvider;
-
- private ResourceAuthorizationFilter resourceAuthorizationFilter;
- public NiFiRegistrySecurityConfig() {
- super(true); // disable defaults
- }
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
+ @Bean
+ public SecurityFilterChain securityFilterChain(final HttpSecurity http)
throws Exception {
+ return http
+ .addFilterBefore(x509AuthenticationFilter(),
AnonymousAuthenticationFilter.class)
+ .addFilterBefore(jwtAuthenticationFilter(),
AnonymousAuthenticationFilter.class)
+ // Add Resource Authorization after Spring Security but before
Jersey Resources
+ .addFilterAfter(resourceAuthorizationFilter(),
FilterSecurityInterceptor.class)
+ .anonymous().authenticationFilter(new
AnonymousIdentityFilter()).and()
+ .csrf().disable()
+ .logout().disable()
.rememberMe().disable()
+ .requestCache().disable()
+ .servletApi().disable()
+ .securityContext().disable()
+ .sessionManagement().disable()
+ .headers()
+ .xssProtection().and()
+ .contentSecurityPolicy("frame-ancestors 'self'").and()
+
.httpStrictTransportSecurity().maxAgeInSeconds(31540000).and()
+ .frameOptions().sameOrigin().and()
.authorizeRequests()
.antMatchers(
"/access/token",
@@ -101,116 +101,55 @@ public class NiFiRegistrySecurityConfig extends
WebSecurityConfigurerAdapter {
.anyRequest().fullyAuthenticated()
.and()
.exceptionHandling()
-
.authenticationEntryPoint(http401AuthenticationEntryPoint())
- .and()
- .sessionManagement()
- .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
-
- // Apply security headers for registry API. Security headers for docs
and UI are applied with Jetty filters in registry-core.
- http.headers().xssProtection();
- http.headers().contentSecurityPolicy("frame-ancestors 'self'");
- http.headers().httpStrictTransportSecurity().maxAgeInSeconds(31540000);
- http.headers().frameOptions().sameOrigin();
-
- // x509
- http.addFilterBefore(x509AuthenticationFilter(),
AnonymousAuthenticationFilter.class);
-
- // jwt
- http.addFilterBefore(jwtAuthenticationFilter(),
AnonymousAuthenticationFilter.class);
-
- // otp
- // todo, if needed one-time password auth filter goes here
-
- // add an anonymous authentication filter that will populate the
authenticated,
- // anonymous user if no other user identity is detected earlier in the
Spring filter chain
- http.anonymous().authenticationFilter(anonymousAuthenticationFilter);
-
- // After Spring Security filter chain is complete (so authentication
is done),
- // but before the Jersey application endpoints get the request,
- // insert the ResourceAuthorizationFilter to do its authorization
checks
- http.addFilterAfter(resourceAuthorizationFilter(),
FilterSecurityInterceptor.class);
- }
-
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws
Exception {
- auth
- .authenticationProvider(x509AuthenticationProvider())
- .authenticationProvider(jwtAuthenticationProvider());
+
.authenticationEntryPoint(http401AuthenticationEntryPoint()).and()
+ .build();
}
- /**
- * Provide Authentication Manager Bean to disable unnecessary
UserDetailsServiceAutoConfiguration
- * @return Authentication Manager
- * @throws Exception Thrown when failing to initialize Authentication
Manager
- */
@Bean
- @Override
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
+ public AuthenticationManager authenticationManager() {
+ return new ProviderManager(x509AuthenticationProvider(),
jwtAuthenticationProvider());
}
private IdentityFilter x509AuthenticationFilter() {
- if (x509AuthenticationFilter == null) {
- x509AuthenticationFilter = new
IdentityFilter(x509IdentityProvider);
- }
- return x509AuthenticationFilter;
+ return new IdentityFilter(x509IdentityProvider);
}
private IdentityAuthenticationProvider x509AuthenticationProvider() {
- if (x509AuthenticationProvider == null) {
- x509AuthenticationProvider = new
X509IdentityAuthenticationProvider(authorizer, x509IdentityProvider,
identityMapper);
- }
- return x509AuthenticationProvider;
+ return new X509IdentityAuthenticationProvider(authorizer,
x509IdentityProvider, identityMapper);
}
private IdentityFilter jwtAuthenticationFilter() {
- if (jwtAuthenticationFilter == null) {
- jwtAuthenticationFilter = new IdentityFilter(jwtIdentityProvider);
- }
- return jwtAuthenticationFilter;
+ return new IdentityFilter(jwtIdentityProvider);
}
private IdentityAuthenticationProvider jwtAuthenticationProvider() {
- if (jwtAuthenticationProvider == null) {
- jwtAuthenticationProvider = new
IdentityAuthenticationProvider(authorizer, jwtIdentityProvider, identityMapper);
- }
- return jwtAuthenticationProvider;
+ return new IdentityAuthenticationProvider(authorizer,
jwtIdentityProvider, identityMapper);
}
private ResourceAuthorizationFilter resourceAuthorizationFilter() {
- if (resourceAuthorizationFilter == null) {
- resourceAuthorizationFilter = ResourceAuthorizationFilter.builder()
+ return ResourceAuthorizationFilter.builder()
.setAuthorizationService(authorizationService)
.addResourceType(ResourceType.Actuator)
.addResourceType(ResourceType.Swagger)
.build();
- }
- return resourceAuthorizationFilter;
}
private AuthenticationEntryPoint http401AuthenticationEntryPoint() {
// This gets used for both secured and unsecured configurations. It
will be called by Spring Security if a request makes it through the filter
chain without being authenticated.
// For unsecured, this should never be reached because the custom
AnonymousAuthenticationFilter should always populate a fully-authenticated
anonymous user
// For secured, this will cause attempt to access any API endpoint
(except those explicitly ignored) without providing credentials to return a 401
Unauthorized challenge
- return new AuthenticationEntryPoint() {
- @Override
- public void commence(HttpServletRequest request,
- HttpServletResponse response,
- AuthenticationException
authenticationException)
- throws IOException {
-
- // return a 401 response
- final int status = HttpServletResponse.SC_UNAUTHORIZED;
- logger.info("Client could not be authenticated due to: {}
Returning 401 response.", authenticationException.toString());
- logger.debug("", authenticationException);
-
- if (!response.isCommitted()) {
- response.setStatus(status);
- response.setContentType("text/plain");
- response.getWriter().println(String.format("%s Contact the
system administrator.", authenticationException.getLocalizedMessage()));
- }
+ return (request, response, authenticationException) -> {
+
+ // return a 401 response
+ final int status = HttpServletResponse.SC_UNAUTHORIZED;
+ logger.info("Client could not be authenticated due to: {}
Returning 401 response.", authenticationException.toString());
+ logger.debug("", authenticationException);
+
+ if (!response.isCommitted()) {
+ response.setStatus(status);
+ response.setContentType("text/plain");
+ response.getWriter().println(String.format("%s Contact the
system administrator.", authenticationException.getLocalizedMessage()));
}
};
}
-
}