Skip to content

add spring security DSL #304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions autoconfigure-adapter/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ dependencies {
compileOnly("io.r2dbc:r2dbc-h2")
compileOnly("io.r2dbc:r2dbc-mssql")
compileOnly("com.zaxxer:HikariCP")
compileOnly("org.springframework.security:spring-security-web")
compileOnly("org.springframework.security:spring-security-config")
}

repositories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public EnableWebMvcConfiguration get() {
context.registerBean(SimpleControllerHandlerAdapter.class, () -> enableWebMvcConfiguration.get().simpleControllerHandlerAdapter());
context.registerBean(HandlerExceptionResolver.class, () -> enableWebMvcConfiguration.get().handlerExceptionResolver(context.getBean(ContentNegotiationManager.class)));
context.registerBean(ViewResolver.class, () -> enableWebMvcConfiguration.get().mvcViewResolver(context.getBean(ContentNegotiationManager.class)));
context.registerBean(HandlerMappingIntrospector.class, () -> enableWebMvcConfiguration.get().mvcHandlerMappingIntrospector(), bd -> bd.setLazyInit(true));
context.registerBean("mvcHandlerMappingIntrospector", HandlerMappingIntrospector.class, () -> enableWebMvcConfiguration.get().mvcHandlerMappingIntrospector(), bd -> bd.setLazyInit(true));
context.registerBean(WelcomePageHandlerMapping.class, () -> enableWebMvcConfiguration.get().welcomePageHandlerMapping(context, context.getBean(FormattingConversionService.class), context.getBean(ResourceUrlProvider.class)));
context.registerBean(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class, () -> enableWebMvcConfiguration.get().localeResolver());
context.registerBean(DispatcherServlet.THEME_RESOLVER_BEAN_NAME, ThemeResolver.class, () -> enableWebMvcConfiguration.get().themeResolver());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.springframework.security.config.annotation.web.configuration;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.function.Consumer;
import java.util.function.Supplier;

/**
* {@link ApplicationContextInitializer} adapter for {@link HttpSecurityConfiguration}.
*/
public class HttpSecurityInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
private static final String BEAN_NAME_PREFIX = "org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.";
static final String HTTPSECURITY_BEAN_NAME = BEAN_NAME_PREFIX + "httpSecurity";

private final Consumer<HttpSecurity> httpSecurityDsl;
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
private final PasswordEncoder passwordEncoder;
private final UserDetailsPasswordService userDetailsPasswordService;

public HttpSecurityInitializer(Consumer<HttpSecurity> httpSecurityDsl, AuthenticationManager authenticationManager,
UserDetailsService userDetailsService, PasswordEncoder passwordEncoder,
UserDetailsPasswordService userDetailsPasswordService) {
this.httpSecurityDsl = httpSecurityDsl;
this.authenticationManager = authenticationManager;
this.userDetailsService = userDetailsService;
this.passwordEncoder = passwordEncoder;
this.userDetailsPasswordService = userDetailsPasswordService;
}

@SuppressWarnings("unchecked")
@Override
public void initialize(GenericApplicationContext context) {
HttpSecurityConfiguration configuration = new HttpSecurityConfiguration();
configuration.setApplicationContext(context);

if (authenticationManager != null) {
configuration.setAuthenticationManager(authenticationManager);
} else {
// build authenticationManager, otherwise HttpSecurityConfiguration will throw NPE
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setUserDetailsPasswordService(userDetailsPasswordService);

if (passwordEncoder != null) {
authProvider.setPasswordEncoder(passwordEncoder);
} else {
authProvider.setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
}

configuration.setAuthenticationManager(new ProviderManager(authProvider));
}

Supplier<HttpSecurity> httpSecuritySupplier = () -> {
configuration.setObjectPostProcessor(context.getBean(ObjectPostProcessor.class));

HttpSecurity httpSecurity;
try {
httpSecurity = configuration.httpSecurity();
} catch (Exception e) {
throw new IllegalStateException(e);
}

this.httpSecurityDsl.accept(httpSecurity);

return httpSecurity;
};

context.registerBean(
HTTPSECURITY_BEAN_NAME,
HttpSecurity.class,
httpSecuritySupplier,
bd -> {
bd.setScope("prototype");
bd.setAutowireCandidate(true);
}
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.springframework.security.config.annotation.web.configuration;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;

/**
* {@link ApplicationContextInitializer} adapter for {@link ObjectPostProcessorConfiguration}.
*/
public class ObjectPostProcessorInitializer implements ApplicationContextInitializer<GenericApplicationContext> {

@Override
public void initialize(GenericApplicationContext context) {
ObjectPostProcessorConfiguration configuration = new ObjectPostProcessorConfiguration();
context.registerBean(ObjectPostProcessor.class, () -> configuration.objectPostProcessor(context.getBeanFactory()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.springframework.security.config.annotation.web.configuration;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.web.servlet.support.RequestDataValueProcessor;

import java.util.function.Supplier;

/**
* {@link ApplicationContextInitializer} adapter for {@link WebMvcSecurityConfiguration}.
*/
public class WebMvcSecurityInitializer implements ApplicationContextInitializer<GenericApplicationContext> {

@Override
public void initialize(GenericApplicationContext context) {
final WebMvcSecurityConfiguration configuration = new WebMvcSecurityConfiguration();
Supplier<WebMvcSecurityConfiguration> configurationSupplier = () -> {
configuration.setApplicationContext(context);
return configuration;
};

context.registerBean(RequestDataValueProcessor.class, () -> configurationSupplier.get().requestDataValueProcessor());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.springframework.security.config.annotation.web.configuration;

import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;

/**
* {@link ApplicationContextInitializer} adapter for {@link WebSecurityConfiguration}.
*/
public class WebSecurityInitializer implements ApplicationContextInitializer<GenericApplicationContext> {

@SuppressWarnings("unchecked")
@Override
public void initialize(GenericApplicationContext context) {

Supplier<WebSecurityConfiguration> configurationSupplier = new Supplier<WebSecurityConfiguration>() {
private WebSecurityConfiguration configuration;

@Override
public WebSecurityConfiguration get() {
if (configuration == null) {
configuration = new WebSecurityConfiguration();
HttpSecurity security = context.getBean(HttpSecurityInitializer.HTTPSECURITY_BEAN_NAME, HttpSecurity.class);
try {
configuration.setFilterChains(Collections.singletonList(security.build()));
} catch (Exception e) {
throw new IllegalStateException(e);
}

List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<>();
String[] webSecurityConfigurerBeanNames = context.getBeanNamesForType(
ResolvableType.forClassWithGenerics(SecurityConfigurer.class, Filter.class, WebSecurity.class));
for (String webSecurityConfigurerBeanName : webSecurityConfigurerBeanNames) {
webSecurityConfigurers.add((SecurityConfigurer<Filter, WebSecurity>) context.getBean(webSecurityConfigurerBeanName));
}
try {
configuration.setFilterChainProxySecurityConfigurer(context.getBean(ObjectPostProcessor.class), webSecurityConfigurers);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
return configuration;
}
};

context.registerBean(
SecurityExpressionHandler.class,
() -> configurationSupplier.get().webSecurityExpressionHandler(),
bd -> bd.setDependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
);
context.registerBean(
AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME,
Filter.class,
() -> {
try {
return configurationSupplier.get().springSecurityFilterChain();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
);
context.registerBean(
WebInvocationPrivilegeEvaluator.class,
() -> configurationSupplier.get().privilegeEvaluator(),
bd -> bd.setDependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.springframework.security.config.annotation.web.reactive;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.reactive.result.method.annotation.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.web.reactive.result.method.annotation.CurrentSecurityContextArgumentResolver;

import java.util.function.Supplier;

/**
* {@link ApplicationContextInitializer} adapter for {@link org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration}.
*/
public class ServerHttpSecurityInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
private static final String BEAN_NAME_PREFIX = "org.springframework.security.config.annotation.web.reactive.HttpSecurityConfiguration.";
private static final String HTTPSECURITY_BEAN_NAME = BEAN_NAME_PREFIX + "httpSecurity";

private final ReactiveAuthenticationManager authenticationManager;
private final ReactiveUserDetailsService reactiveUserDetailsService;
private final PasswordEncoder passwordEncoder;
private final ReactiveUserDetailsPasswordService userDetailsPasswordService;
private ServerHttpSecurity httpSecurity;

/**
* @param authenticationManager {@link ServerHttpSecurityConfiguration}
* @param reactiveUserDetailsService {@link ServerHttpSecurityConfiguration}
* @param passwordEncoder {@link ServerHttpSecurityConfiguration}
* @param userDetailsPasswordService {@link ServerHttpSecurityConfiguration}
*/
public ServerHttpSecurityInitializer(
ReactiveAuthenticationManager authenticationManager,
ReactiveUserDetailsService reactiveUserDetailsService,
PasswordEncoder passwordEncoder,
ReactiveUserDetailsPasswordService userDetailsPasswordService) {
this.authenticationManager = authenticationManager;
this.reactiveUserDetailsService = reactiveUserDetailsService;
this.passwordEncoder = passwordEncoder;
this.userDetailsPasswordService = userDetailsPasswordService;
}

@Override
public void initialize(GenericApplicationContext context) {
final ServerHttpSecurityConfiguration configuration = new ServerHttpSecurityConfiguration();
if (authenticationManager != null) {
configuration.setAuthenticationManager(authenticationManager);
}
if (reactiveUserDetailsService != null) {
configuration.setReactiveUserDetailsService(reactiveUserDetailsService);
}
if (passwordEncoder != null) {
configuration.setPasswordEncoder(passwordEncoder);
}
if (userDetailsPasswordService != null) {
configuration.setUserDetailsPasswordService(userDetailsPasswordService);
}

this.httpSecurity = configuration.httpSecurity();

Supplier<ServerHttpSecurityConfiguration> configurationSupplier = () -> {
configuration.setAdapterRegistry(context.getBean(ReactiveAdapterRegistry.class));
return configuration;
};

context.registerBean(AuthenticationPrincipalArgumentResolver.class, () -> configurationSupplier.get().authenticationPrincipalArgumentResolver());
context.registerBean(CurrentSecurityContextArgumentResolver.class, () -> configurationSupplier.get().reactiveCurrentSecurityContextArgumentResolver());
context.registerBean(
HTTPSECURITY_BEAN_NAME,
ServerHttpSecurity.class,
() -> this.httpSecurity,
bd -> {
bd.setScope("prototype");
bd.setAutowireCandidate(true);
}
);
}

public ServerHttpSecurity getHttpSecurity() {
return httpSecurity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.springframework.security.config.annotation.web.reactive;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.security.web.reactive.result.view.CsrfRequestDataValueProcessor;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.WebFilterChainProxy;
import org.springframework.web.reactive.result.view.AbstractView;

import java.util.Collections;

/**
* {@link ApplicationContextInitializer} adapter for {@link WebFluxSecurityConfiguration}.
*/
public class WebFluxSecurityInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
private static final String BEAN_NAME_PREFIX = "org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration.";
private static final String SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME = BEAN_NAME_PREFIX + "WebFilterChainFilter";

private final SecurityWebFilterChain webFilterChain;

public WebFluxSecurityInitializer(SecurityWebFilterChain webFilterChain) {
this.webFilterChain = webFilterChain;
}

@Override
public void initialize(GenericApplicationContext context) {
WebFluxSecurityConfiguration configuration = new WebFluxSecurityConfiguration();
configuration.context = context;

if (webFilterChain != null) {
configuration.setSecurityWebFilterChains(Collections.singletonList(webFilterChain));
}

context.registerBean(
SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME,
WebFilterChainProxy.class,
configuration::springSecurityWebFilterChainFilter
);
context.registerBean(
AbstractView.REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME,
CsrfRequestDataValueProcessor.class,
configuration::requestDataValueProcessor
);
}
}
6 changes: 6 additions & 0 deletions kofu/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ dependencies {

compileOnly("org.springframework:spring-webmvc")
compileOnly("org.springframework:spring-webflux")
compileOnly("org.springframework.security:spring-security-web")
compileOnly("org.springframework.security:spring-security-config")
compileOnly("de.flapdoodle.embed:de.flapdoodle.embed.mongo")
compileOnly("org.springframework.data:spring-data-mongodb")
compileOnly("org.springframework.data:spring-data-r2dbc")
Expand Down Expand Up @@ -44,6 +46,7 @@ dependencies {
testImplementation("org.springframework.boot:spring-boot-starter-data-redis-reactive")
testImplementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
testImplementation("org.springframework.boot:spring-boot-starter-jdbc")
testImplementation("org.springframework.boot:spring-boot-starter-security")
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin")
testRuntimeOnly("de.flapdoodle.embed:de.flapdoodle.embed.mongo")
testImplementation("io.mockk:mockk:1.9")
Expand Down Expand Up @@ -76,6 +79,9 @@ tasks.withType<DokkaTask> {
externalDocumentationLink {
url = URL("https://docs.spring.io/spring-framework/docs/current/kdoc-api/spring-framework/")
}
externalDocumentationLink {
url = URL("https://docs.spring.io/spring-security/site/docs/current/api/")
}
externalDocumentationLink {
url = URL("https://fasterxml.github.io/jackson-core/javadoc/2.9/")
}
Expand Down
Loading