diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurity.java index a4f75ee1ec..d1f2b2bb0f 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurity.java @@ -55,7 +55,7 @@ import java.lang.annotation.Target; * @EnableWebFluxSecurity * public class MyExplicitSecurityConfiguration { * @Bean - * SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { * http * .authorizeExchange() * .anyExchange().authenticated() diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index 4fe1a02f4a..6c55d97484 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -15,6 +15,17 @@ */ package org.springframework.security.config.web.server; +import static org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.http.HttpMethod; @@ -75,20 +86,61 @@ import org.springframework.util.Assert; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; + import reactor.core.publisher.Mono; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import static org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry; /** + * A {@link ServerHttpSecurity} is similar to Spring Security's {@code HttpSecurity} but for WebFlux. + * It allows configuring web based security for specific http requests. By default it will be applied + * to all requests, but can be restricted using {@link #securityMatcher(ServerWebExchangeMatcher)} or + * other similar methods. + * + * A minimal configuration can be found below: + * + *
+ * @EnableWebFluxSecurity
+ * public class MyMinimalSecurityConfiguration {
+ *
+ * @Bean
+ * public MapReactiveUserDetailsService userDetailsService() {
+ * UserDetails user = User.withDefaultPasswordEncoder()
+ * .username("user")
+ * .password("password")
+ * .roles("USER")
+ * .build();
+ * return new MapReactiveUserDetailsService(user);
+ * }
+ * }
+ *
+ * Below is the same as our minimal configuration, but explicitly declaring the
+ * {@code ServerHttpSecurity}.
+ *
+ *
+ * @EnableWebFluxSecurity
+ * public class MyExplicitSecurityConfiguration {
+ * @Bean
+ * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ * http
+ * .authorizeExchange()
+ * .anyExchange().authenticated()
+ * .and()
+ * .httpBasic().and()
+ * .formLogin();
+ * return http.build();
+ * }
+ *
+ * @Bean
+ * public MapReactiveUserDetailsService userDetailsService() {
+ * UserDetails user = User.withDefaultPasswordEncoder()
+ * .username("user")
+ * .password("password")
+ * .roles("USER")
+ * .build();
+ * return new MapReactiveUserDetailsService(user);
+ * }
+ * }
+ *
* @author Rob Winch
* @since 5.0
*/
@@ -135,6 +187,12 @@ public class ServerHttpSecurity {
return this;
}
+ /**
+ * Adds a {@link WebFilter} at a specific position.
+ * @param webFilter the {@link WebFilter} to add
+ * @param order the place to insert the {@link WebFilter}
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity addFilterAt(WebFilter webFilter, SecurityWebFiltersOrder order) {
this.webFilters.add(new OrderedWebFilter(webFilter, order.getOrder()));
return this;
@@ -148,12 +206,53 @@ public class ServerHttpSecurity {
return this.securityMatcher;
}
+ /**
+ * The strategy used with {@code ReactorContextWebFilter}. It does not impact how the {@code SecurityContext} is
+ * saved which is configured on a per {@link AuthenticationWebFilter} basis.
+ * @param securityContextRepository the repository to use
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity securityContextRepository(ServerSecurityContextRepository securityContextRepository) {
Assert.notNull(securityContextRepository, "securityContextRepository cannot be null");
this.securityContextRepository = securityContextRepository;
return this;
}
+ /**
+ * Configures CSRF Protection
+ * which is enabled by default. You can disable it using:
+ *
+ *
+ * @Bean
+ * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ * http
+ * // ...
+ * .csrf().disabled();
+ * return http.build();
+ * }
+ *
+ *
+ * Additional configuration options can be seen below:
+ *
+ *
+ *
+ * @Bean
+ * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ * http
+ * // ...
+ * .csrf()
+ * // Handle CSRF failures
+ * .accessDeniedHandler(accessDeniedHandler)
+ * // Custom persistence of CSRF Token
+ * .csrfTokenRepository(csrfTokenRepository)
+ * // custom matching when CSRF protection is enabled
+ * .requireCsrfProtectionMatcher(matcher);
+ * return http.build();
+ * }
+ *
+ *
+ * @return the {@link CsrfSpec} to customize
+ */
public CsrfSpec csrf() {
if(this.csrf == null) {
this.csrf = new CsrfSpec();
@@ -161,6 +260,25 @@ public class ServerHttpSecurity {
return this.csrf;
}
+ /**
+ * Configures HTTP Basic authentication. An example configuration is provided below:
+ *
+ *
+ * @Bean
+ * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ * http
+ * // ...
+ * .httpBasic()
+ * // used for authenticating the credentials
+ * .authenticationManager(authenticationManager)
+ * // Custom persistence of the authentication
+ * .securityContextRepository(securityContextRepository);
+ * return http.build();
+ * }
+ *
+ *
+ * @return the {@link HttpBasicSpec} to customize
+ */
public HttpBasicSpec httpBasic() {
if(this.httpBasic == null) {
this.httpBasic = new HttpBasicSpec();
@@ -168,6 +286,29 @@ public class ServerHttpSecurity {
return this.httpBasic;
}
+ /**
+ * Configures form based authentication. An example configuration is provided below:
+ *
+ *
+ * @Bean
+ * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ * http
+ * // ...
+ * .formLogin()
+ * // used for authenticating the credentials
+ * .authenticationManager(authenticationManager)
+ * // Custom persistence of the authentication
+ * .securityContextRepository(securityContextRepository)
+ * // expect a log in page at "/authenticate"
+ * // a POST "/authenticate" is where authentication occurs
+ * // error page at "/authenticate?error"
+ * .formLogin("/authenticate");
+ * return http.build();
+ * }
+ *
+ *
+ * @return the {@link FormLoginSpec} to customize
+ */
public FormLoginSpec formLogin() {
if(this.formLogin == null) {
this.formLogin = new FormLoginSpec();
@@ -175,6 +316,41 @@ public class ServerHttpSecurity {
return this.formLogin;
}
+ /**
+ * Configures HTTP Response Headers. The default headers are:
+ *
+ *
+ * Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+ * Pragma: no-cache
+ * Expires: 0
+ * X-Content-Type-Options: nosniff
+ * Strict-Transport-Security: max-age=31536000 ; includeSubDomains
+ * X-Frame-Options: DENY
+ * X-XSS-Protection: 1; mode=block
+ *
+ *
+ * such that "Strict-Transport-Security" is only added on secure requests.
+ *
+ * An example configuration is provided below:
+ *
+ *
+ * @Bean
+ * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ * http
+ * // ...
+ * .headers()
+ * // customize frame options to be same origin
+ * .frameOptions()
+ * .mode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN)
+ * .and()
+ * // disable cache control
+ * .cache().disable();
+ * return http.build();
+ * }
+ *
+ *
+ * @return the {@link HeaderSpec} to customize
+ */
public HeaderSpec headers() {
if(this.headers == null) {
this.headers = new HeaderSpec();
@@ -182,6 +358,24 @@ public class ServerHttpSecurity {
return this.headers;
}
+ /**
+ * Configures exception handling (i.e. handles when authentication is requested). An example configuration can
+ * be found below:
+ *
+ *
+ * @Bean
+ * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ * http
+ * // ...
+ * .exceptionHandling()
+ * // customize how to request for authentication
+ * .authenticationEntryPoint(entryPoint);
+ * return http.build();
+ * }
+ *
+ *
+ * @return the {@link ExceptionHandlingSpec} to customize
+ */
public ExceptionHandlingSpec exceptionHandling() {
if(this.exceptionHandling == null) {
this.exceptionHandling = new ExceptionHandlingSpec();
@@ -189,6 +383,37 @@ public class ServerHttpSecurity {
return this.exceptionHandling;
}
+ /**
+ * Configures authorization. An example configuration can be found below:
+ *
+ *
+ * @Bean
+ * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ * http
+ * // ...
+ * .authorizeExchange()
+ * // any URL that starts with /admin/ requires the role "ROLE_ADMIN"
+ * .pathMatchers("/admin/**").hasRole("ADMIN")
+ * // a POST to /users requires the role "USER_POST"
+ * .pathMatchers(HttpMethod.POST, "/users").hasAuthority("USER_POST")
+ * // a request to /users/{username} requires the current authentication's username
+ * // to be equal to the {username}
+ * .pathMatchers("/users/{username}").access((authentication, context) ->
+ * authentication
+ * .map(Authentication::getName)
+ * .map(username -> username.equals(context.getVariables().get("username")))
+ * .map(AuthorizationDecision::new)
+ * )
+ * // allows providing a custom matching strategy that requires the role "ROLE_CUSTOM"
+ * .matchers(customMatcher).hasRole("CUSTOM")
+ * // any other request requires the user to be authenticated
+ * .anyExchange().authenticated();
+ * return http.build();
+ * }
+ *
+ *
+ * @return the {@link AuthorizeExchangeSpec} to customize
+ */
public AuthorizeExchangeSpec authorizeExchange() {
if(this.authorizeExchange == null) {
this.authorizeExchange = new AuthorizeExchangeSpec();
@@ -196,6 +421,26 @@ public class ServerHttpSecurity {
return this.authorizeExchange;
}
+ /**
+ * Configures log out. An example configuration can be found below:
+ *
+ *
+ * @Bean
+ * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ * http
+ * // ...
+ * .logout()
+ * // configures how log out is done
+ * .logoutHandler(logoutHandler)
+ * // log out will be performed on POST /signout
+ * .logoutUrl("/signout")
+ * // configure what is done on logout success
+ * .logoutSuccessHandler(successHandler);
+ * return http.build();
+ * }
+ *
+ * @return the {@link LogoutSpec} to customize
+ */
public LogoutSpec logout() {
if (this.logout == null) {
this.logout = new LogoutSpec();
@@ -203,15 +448,42 @@ public class ServerHttpSecurity {
return this.logout;
}
+ /**
+ * Configures the request cache which is used when a flow is interrupted (i.e. due to requesting credentials) so
+ * that the request can be replayed after authentication. An example configuration can be found below:
+ *
+ *
+ * @Bean
+ * public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
+ * http
+ * // ...
+ * .requestCache()
+ * // configures how the request is cached
+ * .requestCache(requestCache);
+ * return http.build();
+ * }
+ *
+ *
+ * @return the {@link RequestCacheSpec} to customize
+ */
public RequestCacheSpec requestCache() {
return this.requestCache;
}
+ /**
+ * Configure the default authentication manager.
+ * @param manager the authentication manager to use
+ * @return the {@code ServerHttpSecurity} to customize
+ */
public ServerHttpSecurity authenticationManager(ReactiveAuthenticationManager manager) {
this.authenticationManager = manager;
return this;
}
+ /**
+ * Builds the {@link SecurityWebFilterChain}
+ * @return the {@link SecurityWebFilterChain
+ */
public SecurityWebFilterChain build() {
if(this.built != null) {
throw new IllegalStateException("This has already been built with the following stacktrace. " + buildToString());
@@ -295,6 +567,10 @@ public class ServerHttpSecurity {
return result;
}
+ /**
+ * Creates a new instance.
+ * @return the new {@link ServerHttpSecurity} instance
+ */
public static ServerHttpSecurity http() {
return new ServerHttpSecurity();
}
@@ -311,8 +587,11 @@ public class ServerHttpSecurity {
private ServerHttpSecurity() {}
/**
+ * Configures authorization
+ *
* @author Rob Winch
* @since 5.0
+ * @see #authorizeExchange()
*/
public class AuthorizeExchangeSpec
extends AbstractServerWebExchangeMatcherRegistry {
@@ -320,10 +599,18 @@ public class ServerHttpSecurity {
private ServerWebExchangeMatcher matcher;
private boolean anyExchangeRegistered;
+ /**
+ * Allows method chaining to continue configuring the {@link ServerHttpSecurity}
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity and() {
return ServerHttpSecurity.this;
}
+ /**
+ * Disables authorization.
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
@Override
public Access anyExchange() {
Access result = super.anyExchange();
@@ -351,28 +638,58 @@ public class ServerHttpSecurity {
http.addFilterAt(result, SecurityWebFiltersOrder.AUTHORIZATION);
}
+ /**
+ * Configures the access for a particular set of exchanges.
+ */
public final class Access {
+ /**
+ * Allow access for anyone
+ * @return the {@link AuthorizeExchangeSpec} to configure
+ */
public AuthorizeExchangeSpec permitAll() {
return access( (a, e) -> Mono.just(new AuthorizationDecision(true)));
}
+ /**
+ * Deny access for everyone
+ * @return the {@link AuthorizeExchangeSpec} to configure
+ */
public AuthorizeExchangeSpec denyAll() {
return access( (a, e) -> Mono.just(new AuthorizationDecision(false)));
}
+ /**
+ * Require a specific role. This is a shorcut for {@link #hasAuthority(String)}
+ * @param role the role (i.e. "USER" would require "ROLE_USER")
+ * @return the {@link AuthorizeExchangeSpec} to configure
+ */
public AuthorizeExchangeSpec hasRole(String role) {
return access(AuthorityReactiveAuthorizationManager.hasRole(role));
}
+ /**
+ * Require a specific authority.
+ * @param authority the authority to require (i.e. "USER" woudl require authority of "USER").
+ * @return the {@link AuthorizeExchangeSpec} to configure
+ */
public AuthorizeExchangeSpec hasAuthority(String authority) {
return access(AuthorityReactiveAuthorizationManager.hasAuthority(authority));
}
+ /**
+ * Require an authenticated user
+ * @return the {@link AuthorizeExchangeSpec} to configure
+ */
public AuthorizeExchangeSpec authenticated() {
return access(AuthenticatedReactiveAuthorizationManager.authenticated());
}
+ /**
+ * Allows plugging in a custom authorization strategy
+ * @param manager the authorization manager to use
+ * @return the {@link AuthorizeExchangeSpec} to configure
+ */
public AuthorizeExchangeSpec access(ReactiveAuthorizationManager manager) {
AuthorizeExchangeSpec.this.managerBldr
.add(new ServerWebExchangeMatcherEntry<>(
@@ -384,34 +701,67 @@ public class ServerHttpSecurity {
}
/**
+ * Configures CSRF Protection
+ *
* @author Rob Winch
* @since 5.0
+ * @see #csrf()
*/
public class CsrfSpec {
private CsrfWebFilter filter = new CsrfWebFilter();
+ /**
+ * Configures the {@link ServerAccessDeniedHandler} used when a CSRF token is invalid. Default is
+ * to send an {@link org.springframework.http.HttpStatus#FORBIDDEN}.
+ *
+ * @param accessDeniedHandler the access denied handler.
+ * @return the {@link CsrfSpec} for additional configuration
+ */
public CsrfSpec accessDeniedHandler(
ServerAccessDeniedHandler accessDeniedHandler) {
this.filter.setAccessDeniedHandler(accessDeniedHandler);
return this;
}
+ /**
+ * Configures the {@link ServerCsrfTokenRepository} used to persist the CSRF Token. Default is
+ * {@link org.springframework.security.web.server.csrf.WebSessionServerCsrfTokenRepository}.
+ *
+ * @param csrfTokenRepository the repository to use
+ * @return the {@link CsrfSpec} for additional configuration
+ */
public CsrfSpec csrfTokenRepository(
ServerCsrfTokenRepository csrfTokenRepository) {
this.filter.setCsrfTokenRepository(csrfTokenRepository);
return this;
}
+ /**
+ * Configures the {@link ServerWebExchangeMatcher} used to determine when CSRF protection is enabled. Default is
+ * PUT, POST, DELETE requests.
+ *
+ * @param requireCsrfProtectionMatcher the matcher to use
+ * @return the {@link CsrfSpec} for additional configuration
+ */
public CsrfSpec requireCsrfProtectionMatcher(
ServerWebExchangeMatcher requireCsrfProtectionMatcher) {
this.filter.setRequireCsrfProtectionMatcher(requireCsrfProtectionMatcher);
return this;
}
+ /**
+ * Allows method chaining to continue configuring the {@link ServerHttpSecurity}
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity and() {
return ServerHttpSecurity.this;
}
+ /**
+ * Disables CSRF Protection. Disabling CSRF Protection is only recommended when the application is never used
+ * within a browser.
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity disable() {
ServerHttpSecurity.this.csrf = null;
return ServerHttpSecurity.this;
@@ -425,16 +775,28 @@ public class ServerHttpSecurity {
}
/**
+ * Configures exception handling
+ *
* @author Rob Winch
* @since 5.0
+ * @see #exceptionHandling()
*/
public class ExceptionHandlingSpec {
+ /**
+ * Configures what to do when the application request authentication
+ * @param authenticationEntryPoint the entry point to use
+ * @return the {@link ExceptionHandlingSpec} to configure
+ */
public ExceptionHandlingSpec authenticationEntryPoint(ServerAuthenticationEntryPoint authenticationEntryPoint) {
ServerHttpSecurity.this.authenticationEntryPoint = authenticationEntryPoint;
return this;
}
+ /**
+ * Allows method chaining to continue configuring the {@link ServerHttpSecurity}
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity and() {
return ServerHttpSecurity.this;
}
@@ -443,12 +805,21 @@ public class ServerHttpSecurity {
}
/**
+ * Configures the request cache which is used when a flow is interrupted (i.e. due to requesting credentials) so
+ * that the request can be replayed after authentication.
+ *
* @author Rob Winch
* @since 5.0
+ * @see #requestCache()
*/
public class RequestCacheSpec {
private ServerRequestCache requestCache = new WebSessionServerRequestCache();
+ /**
+ * Configures the cache used
+ * @param requestCache the request cache
+ * @return the {@link RequestCacheSpec} to configure
+ */
public RequestCacheSpec requestCache(ServerRequestCache requestCache) {
Assert.notNull(requestCache, "requestCache cannot be null");
this.requestCache = requestCache;
@@ -461,10 +832,18 @@ public class ServerHttpSecurity {
http.addFilterAt(filter, SecurityWebFiltersOrder.SERVER_REQUEST_CACHE);
}
+ /**
+ * Allows method chaining to continue configuring the {@link ServerHttpSecurity}
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity and() {
return ServerHttpSecurity.this;
}
+ /**
+ * Disables the {@link RequestCacheSpec}
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity disable() {
this.requestCache = NoOpServerRequestCache.getInstance();
return and();
@@ -474,8 +853,11 @@ public class ServerHttpSecurity {
}
/**
+ * Configures HTTP Basic Authentication
+ *
* @author Rob Winch
* @since 5.0
+ * @see #httpBasic()
*/
public class HttpBasicSpec {
private ReactiveAuthenticationManager authenticationManager;
@@ -484,20 +866,44 @@ public class ServerHttpSecurity {
private ServerAuthenticationEntryPoint entryPoint = new HttpBasicServerAuthenticationEntryPoint();
+ /**
+ * The {@link ReactiveAuthenticationManager} used to authenticate. Defaults to
+ * {@link ServerHttpSecurity#authenticationManager(ReactiveAuthenticationManager)}.
+ *
+ * @param authenticationManager the authentication manager to use
+ * @return the {@link HttpBasicSpec} to continue configuring
+ */
public HttpBasicSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
return this;
}
+ /**
+ * The {@link ServerSecurityContextRepository} used to save the {@code Authentication}. Defaults to
+ * {@link NoOpServerSecurityContextRepository}. For the {@code SecurityContext} to be loaded on subsequent
+ * requests the {@link ReactorContextWebFilter} must be configured to be able to load the value (they are not
+ * implicitly linked).
+ *
+ * @param securityContextRepository the repository to use
+ * @return the {@link HttpBasicSpec} to continue configuring
+ */
public HttpBasicSpec securityContextRepository(ServerSecurityContextRepository securityContextRepository) {
this.securityContextRepository = securityContextRepository;
return this;
}
+ /**
+ * Allows method chaining to continue configuring the {@link ServerHttpSecurity}
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity and() {
return ServerHttpSecurity.this;
}
+ /**
+ * Disables HTTP Basic authentication.
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity disable() {
ServerHttpSecurity.this.httpBasic = null;
return ServerHttpSecurity.this;
@@ -525,8 +931,11 @@ public class ServerHttpSecurity {
}
/**
+ * Configures Form Based authentication
+ *
* @author Rob Winch
* @since 5.0
+ * @see #formLogin()
*/
public class FormLoginSpec {
private final RedirectServerAuthenticationSuccessHandler defaultSuccessHandler = new RedirectServerAuthenticationSuccessHandler("/");
@@ -545,11 +954,24 @@ public class ServerHttpSecurity {
private ServerAuthenticationSuccessHandler authenticationSuccessHandler = this.defaultSuccessHandler;
+ /**
+ * The {@link ReactiveAuthenticationManager} used to authenticate. Defaults to
+ * {@link ServerHttpSecurity#authenticationManager(ReactiveAuthenticationManager)}.
+ *
+ * @param authenticationManager the authentication manager to use
+ * @return the {@link FormLoginSpec} to continue configuring
+ */
public FormLoginSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
return this;
}
+ /**
+ * The {@link ServerAuthenticationSuccessHandler} used after authentication success. Defaults to
+ * {@link RedirectServerAuthenticationSuccessHandler}.
+ * @param authenticationSuccessHandler the success handler to use
+ * @return the {@link FormLoginSpec} to continue configuring
+ */
public FormLoginSpec authenticationSuccessHandler(
ServerAuthenticationSuccessHandler authenticationSuccessHandler) {
Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null");
@@ -557,6 +979,22 @@ public class ServerHttpSecurity {
return this;
}
+ /**
+ * Configures the log in page to redirect to, the authentication failure page, and when authentication is
+ * performed. The default is that Spring Security will generate a log in page at "/login" and a log out page at
+ * "/logout". If this is customized:
+ *
+ * - The default log in & log out page are no longer provided
+ * - The application must render a log in page at the provided URL
+ * - The application must render an authentication error page at the provided URL + "?error"
+ * - Authentication will occur for POST to the provided URL
+ *
+ * @param loginPage the url to redirect to which provides a form to log in (i.e. "/login")
+ * @return the {@link FormLoginSpec} to continue configuring
+ * @see #authenticationEntryPoint(ServerAuthenticationEntryPoint)
+ * @see #requiresAuthenticationMatcher(ServerWebExchangeMatcher)
+ * @see #authenticationFailureHandler(ServerAuthenticationFailureHandler)
+ */
public FormLoginSpec loginPage(String loginPage) {
this.defaultEntryPoint = new RedirectServerAuthenticationEntryPoint(loginPage);
this.authenticationEntryPoint = this.defaultEntryPoint;
@@ -565,30 +1003,66 @@ public class ServerHttpSecurity {
return this;
}
+ /**
+ * How to request for authentication. The default is that Spring Security will
+ * generate a log in page at "/login".
+ * @param authenticationEntryPoint the entry point to use
+ * @return the {@link FormLoginSpec} to continue configuring
+ * @see #loginPage(String)
+ */
public FormLoginSpec authenticationEntryPoint(ServerAuthenticationEntryPoint authenticationEntryPoint) {
this.authenticationEntryPoint = authenticationEntryPoint;
return this;
}
+ /**
+ * Configures when authentication is performed. The default is a POST to "/login".
+ * @param requiresAuthenticationMatcher the matcher to use
+ * @return the {@link FormLoginSpec} to continue configuring
+ * @see #loginPage(String)
+ */
public FormLoginSpec requiresAuthenticationMatcher(ServerWebExchangeMatcher requiresAuthenticationMatcher) {
this.requiresAuthenticationMatcher = requiresAuthenticationMatcher;
return this;
}
+ /**
+ * Configures how a failed authentication is handled. The default is to redirect to "/login?error".
+ * @param authenticationFailureHandler the handler to use
+ * @return the {@link FormLoginSpec} to continue configuring
+ * @see #loginPage(String)
+ */
public FormLoginSpec authenticationFailureHandler(ServerAuthenticationFailureHandler authenticationFailureHandler) {
this.authenticationFailureHandler = authenticationFailureHandler;
return this;
}
+ /**
+ * The {@link ServerSecurityContextRepository} used to save the {@code Authentication}. Defaults to
+ * {@link NoOpServerSecurityContextRepository}. For the {@code SecurityContext} to be loaded on subsequent
+ * requests the {@link ReactorContextWebFilter} must be configured to be able to load the value (they are not
+ * implicitly linked).
+ *
+ * @param securityContextRepository the repository to use
+ * @return the {@link FormLoginSpec} to continue configuring
+ */
public FormLoginSpec securityContextRepository(ServerSecurityContextRepository securityContextRepository) {
this.securityContextRepository = securityContextRepository;
return this;
}
+ /**
+ * Allows method chaining to continue configuring the {@link ServerHttpSecurity}
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity and() {
return ServerHttpSecurity.this;
}
+ /**
+ * Disables HTTP Basic authentication.
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity disable() {
ServerHttpSecurity.this.formLogin = null;
return ServerHttpSecurity.this;
@@ -624,8 +1098,11 @@ public class ServerHttpSecurity {
}
/**
+ * Configures HTTP Response Headers.
+ *
* @author Rob Winch
* @since 5.0
+ * @see #headers()
*/
public class HeaderSpec {
private final List writers;
@@ -640,27 +1117,51 @@ public class ServerHttpSecurity {
private XXssProtectionServerHttpHeadersWriter xss = new XXssProtectionServerHttpHeadersWriter();
+ /**
+ * Allows method chaining to continue configuring the {@link ServerHttpSecurity}
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity and() {
return ServerHttpSecurity.this;
}
+ /**
+ * Disables http response headers
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity disable() {
ServerHttpSecurity.this.headers = null;
return ServerHttpSecurity.this;
}
+ /**
+ * Configures cache control headers
+ * @return the {@link CacheSpec} to configure
+ */
public CacheSpec cache() {
return new CacheSpec();
}
+ /**
+ * Configures content type response headers
+ * @return the {@link ContentTypeOptionsSpec} to configure
+ */
public ContentTypeOptionsSpec contentTypeOptions() {
return new ContentTypeOptionsSpec();
}
+ /**
+ * Configures frame options response headers
+ * @return the {@link FrameOptionsSpec} to configure
+ */
public FrameOptionsSpec frameOptions() {
return new FrameOptionsSpec();
}
+ /**
+ * Configures the Strict Transport Security response headers
+ * @return the {@link HstsSpec} to configure
+ */
public HstsSpec hsts() {
return new HstsSpec();
}
@@ -671,11 +1172,23 @@ public class ServerHttpSecurity {
http.addFilterAt(result, SecurityWebFiltersOrder.HTTP_HEADERS_WRITER);
}
+ /**
+ * Configures x-xss-protection response header.
+ * @return the {@link XssProtectionSpec} to configure
+ */
public XssProtectionSpec xssProtection() {
return new XssProtectionSpec();
}
+ /**
+ * Configures cache control headers
+ * @see #cache()
+ */
public class CacheSpec {
+ /**
+ * Disables cache control response headers
+ * @return the {@link HeaderSpec} to configure
+ */
public HeaderSpec disable() {
HeaderSpec.this.writers.remove(HeaderSpec.this.cacheControl);
return HeaderSpec.this;
@@ -684,7 +1197,15 @@ public class ServerHttpSecurity {
private CacheSpec() {}
}
+ /**
+ * The content type headers
+ * @see #contentTypeOptions()
+ */
public class ContentTypeOptionsSpec {
+ /**
+ * Disables the content type options response header
+ * @return the {@link HeaderSpec} to configure
+ */
public HeaderSpec disable() {
HeaderSpec.this.writers.remove(HeaderSpec.this.contentTypeOptions);
return HeaderSpec.this;
@@ -693,16 +1214,34 @@ public class ServerHttpSecurity {
private ContentTypeOptionsSpec() {}
}
+ /**
+ * Configures frame options response header
+ * @see #frameOptions()
+ */
public class FrameOptionsSpec {
+ /**
+ * The mode to configure. Default is
+ * {@link org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter.Mode#DENY}
+ * @param mode the mode to use
+ * @return the {@link FrameOptionsSpec} to configure
+ */
public FrameOptionsSpec mode(XFrameOptionsServerHttpHeadersWriter.Mode mode) {
HeaderSpec.this.frameOptions.setMode(mode);
return this;
}
+ /**
+ * Allows method chaining to continue configuring the {@link ServerHttpSecurity}
+ * @return the {@link HeaderSpec} to continue configuring
+ */
public HeaderSpec and() {
return HeaderSpec.this;
}
+ /**
+ * Disables frame options response header
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public HeaderSpec disable() {
HeaderSpec.this.writers.remove(HeaderSpec.this.frameOptions);
return HeaderSpec.this;
@@ -711,19 +1250,39 @@ public class ServerHttpSecurity {
private FrameOptionsSpec() {}
}
+ /**
+ * Configures Strict Transport Security response header
+ * @see #hsts()
+ */
public class HstsSpec {
+ /**
+ * Configures the max age. Default is one year.
+ * @param maxAge the max age
+ */
public void maxAge(Duration maxAge) {
HeaderSpec.this.hsts.setMaxAge(maxAge);
}
+ /**
+ * Configures if subdomains should be included. Default is true
+ * @param includeSubDomains if subdomains should be included
+ */
public void includeSubdomains(boolean includeSubDomains) {
HeaderSpec.this.hsts.setIncludeSubDomains(includeSubDomains);
}
+ /**
+ * Allows method chaining to continue configuring the {@link ServerHttpSecurity}
+ * @return the {@link HeaderSpec} to continue configuring
+ */
public HeaderSpec and() {
return HeaderSpec.this;
}
+ /**
+ * Disables strict transport security response header
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public HeaderSpec disable() {
HeaderSpec.this.writers.remove(HeaderSpec.this.hsts);
return HeaderSpec.this;
@@ -732,7 +1291,15 @@ public class ServerHttpSecurity {
private HstsSpec() {}
}
+ /**
+ * Configures x-xss-protection response header
+ * @see #xssProtection()
+ */
public class XssProtectionSpec {
+ /**
+ * Disables the x-xss-protection response header
+ * @return
+ */
public HeaderSpec disable() {
HeaderSpec.this.writers.remove(HeaderSpec.this.xss);
return HeaderSpec.this;
@@ -749,23 +1316,41 @@ public class ServerHttpSecurity {
}
/**
+ * Configures log out
* @author Shazin Sadakath
* @since 5.0
+ * @see #logout()
*/
public final class LogoutSpec {
private LogoutWebFilter logoutWebFilter = new LogoutWebFilter();
+ /**
+ * Configures the logout handler. Default is {@code SecurityContextServerLogoutHandler}
+ * @param logoutHandler
+ * @return
+ */
public LogoutSpec logoutHandler(ServerLogoutHandler logoutHandler) {
this.logoutWebFilter.setLogoutHandler(logoutHandler);
return this;
}
+ /**
+ * Configures what URL a POST to will trigger a log out.
+ * @param logoutUrl the url to trigger a log out (i.e. "/signout" would mean a POST to "/signout" would trigger
+ * log out)
+ * @return the {@link LogoutSpec} to configure
+ */
public LogoutSpec logoutUrl(String logoutUrl) {
Assert.notNull(logoutUrl, "logoutUrl must not be null");
ServerWebExchangeMatcher requiresLogout = ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, logoutUrl);
return requiresLogout(requiresLogout);
}
+ /**
+ * Configures when the log out will be triggered.
+ * @param requiresLogout the matcher to determine when log out is triggered
+ * @return the {@link LogoutSpec} to configure
+ */
public LogoutSpec requiresLogout(ServerWebExchangeMatcher requiresLogout) {
this.logoutWebFilter.setRequiresLogoutMatcher(requiresLogout);
return this;
@@ -776,16 +1361,24 @@ public class ServerHttpSecurity {
return this;
}
+ /**
+ * Allows method chaining to continue configuring the {@link ServerHttpSecurity}
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
+ public ServerHttpSecurity and() {
+ return ServerHttpSecurity.this;
+ }
+
+ /**
+ * Disables log out
+ * @return the {@link ServerHttpSecurity} to continue configuring
+ */
public ServerHttpSecurity disable() {
ServerHttpSecurity.this.logout = null;
return and();
}
- public ServerHttpSecurity and() {
- return ServerHttpSecurity.this;
- }
-
- public void configure(ServerHttpSecurity http) {
+ protected void configure(ServerHttpSecurity http) {
http.addFilterAt(this.logoutWebFilter, SecurityWebFiltersOrder.LOGOUT);
}
diff --git a/core/src/main/java/org/springframework/security/access/prepost/PrePostAdviceReactiveMethodInterceptor.java b/core/src/main/java/org/springframework/security/access/prepost/PrePostAdviceReactiveMethodInterceptor.java
index 9988156201..2f96a3ca87 100644
--- a/core/src/main/java/org/springframework/security/access/prepost/PrePostAdviceReactiveMethodInterceptor.java
+++ b/core/src/main/java/org/springframework/security/access/prepost/PrePostAdviceReactiveMethodInterceptor.java
@@ -36,6 +36,9 @@ import java.lang.reflect.Method;
import java.util.Collection;
/**
+ * A {@link MethodInterceptor} that supports {@link PreAuthorize} and {@link PostAuthorize} for methods that return
+ * {@link Mono} or {@link Flux}
+ *
* @author Rob Winch
* @since 5.0
*/
@@ -49,6 +52,12 @@ public class PrePostAdviceReactiveMethodInterceptor implements MethodInterceptor
private final PostInvocationAuthorizationAdvice postAdvice;
+ /**
+ * Creates a new instance
+ * @param attributeSource the {@link MethodSecurityMetadataSource} to use
+ * @param preInvocationAdvice the {@link PreInvocationAuthorizationAdvice} to use
+ * @param postInvocationAdvice the {@link PostInvocationAuthorizationAdvice} to use
+ */
public PrePostAdviceReactiveMethodInterceptor(MethodSecurityMetadataSource attributeSource, PreInvocationAuthorizationAdvice preInvocationAdvice, PostInvocationAuthorizationAdvice postInvocationAdvice) {
Assert.notNull(attributeSource, "attributeSource cannot be null");
Assert.notNull(preInvocationAdvice, "preInvocationAdvice cannot be null");
diff --git a/core/src/main/java/org/springframework/security/authentication/ReactiveAuthenticationManager.java b/core/src/main/java/org/springframework/security/authentication/ReactiveAuthenticationManager.java
index 4cce2f63ae..fa01ec0281 100644
--- a/core/src/main/java/org/springframework/security/authentication/ReactiveAuthenticationManager.java
+++ b/core/src/main/java/org/springframework/security/authentication/ReactiveAuthenticationManager.java
@@ -25,6 +25,7 @@ import reactor.core.publisher.Mono;
* @author Rob Winch
* @since 5.0
*/
+@FunctionalInterface
public interface ReactiveAuthenticationManager {
/**
diff --git a/core/src/main/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManager.java b/core/src/main/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManager.java
index 1a0279313d..0dbab23978 100644
--- a/core/src/main/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManager.java
+++ b/core/src/main/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManager.java
@@ -26,6 +26,9 @@ import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
/**
+ * A {@link ReactiveAuthenticationManager} that uses a {@link ReactiveUserDetailsService} to validate the provided
+ * username and password.
+ *
* @author Rob Winch
* @since 5.0
*/
@@ -49,6 +52,11 @@ public class UserDetailsRepositoryReactiveAuthenticationManager implements React
.map( u -> new UsernamePasswordAuthenticationToken(u, u.getPassword(), u.getAuthorities()) );
}
+ /**
+ * The {@link PasswordEncoder} that is used for validating the password. The default is
+ * {@link PasswordEncoderFactories#createDelegatingPasswordEncoder()}
+ * @param passwordEncoder the {@link PasswordEncoder} to use. Cannot be null
+ */
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
this.passwordEncoder = passwordEncoder;
diff --git a/core/src/main/java/org/springframework/security/core/userdetails/MapReactiveUserDetailsService.java b/core/src/main/java/org/springframework/security/core/userdetails/MapReactiveUserDetailsService.java
index 96dc152a91..ce44d886cd 100644
--- a/core/src/main/java/org/springframework/security/core/userdetails/MapReactiveUserDetailsService.java
+++ b/core/src/main/java/org/springframework/security/core/userdetails/MapReactiveUserDetailsService.java
@@ -26,6 +26,7 @@ import org.springframework.util.Assert;
import reactor.core.publisher.Mono;
/**
+ * A {@link Map} based implementation of {@link ReactiveUserDetailsService}
*
* @author Rob Winch
* @since 5.0
@@ -33,14 +34,26 @@ import reactor.core.publisher.Mono;
public class MapReactiveUserDetailsService implements ReactiveUserDetailsService {
private final Map users;
+ /**
+ * Creates a new instance using a {@link Map} that must be non blocking.
+ * @param users a {@link Map} of users to use.
+ */
public MapReactiveUserDetailsService(Map users) {
this.users = users;
}
+ /**
+ * Creates a new instance
+ * @param users the {@link UserDetails} to use
+ */
public MapReactiveUserDetailsService(UserDetails... users) {
this(Arrays.asList(users));
}
+ /**
+ * Creates a new instance
+ * @param users the {@link UserDetails} to use
+ */
public MapReactiveUserDetailsService(Collection users) {
Assert.notEmpty(users, "users cannot be null or empty");
this.users = users.stream().collect(Collectors.toConcurrentMap( u -> getKey(u.getUsername()), Function.identity()));
diff --git a/core/src/main/java/org/springframework/security/core/userdetails/ReactiveUserDetailsService.java b/core/src/main/java/org/springframework/security/core/userdetails/ReactiveUserDetailsService.java
index a5df83b523..ace0f5e7c2 100644
--- a/core/src/main/java/org/springframework/security/core/userdetails/ReactiveUserDetailsService.java
+++ b/core/src/main/java/org/springframework/security/core/userdetails/ReactiveUserDetailsService.java
@@ -16,11 +16,20 @@
package org.springframework.security.core.userdetails;
-import org.springframework.security.core.userdetails.UserDetails;
-
import reactor.core.publisher.Mono;
+/**
+ * An API for finding the {@link UserDetails} by username.
+ *
+ * @author Rob Winch
+ * @since 5.0
+ */
public interface ReactiveUserDetailsService {
+ /**
+ * Find the {@link UserDetails} by username.
+ * @param username the username to look up
+ * @return the {@link UserDetails}. Cannot be null
+ */
Mono findByUsername(String username);
}
diff --git a/web/src/main/java/org/springframework/security/web/server/DefaultServerRedirectStrategy.java b/web/src/main/java/org/springframework/security/web/server/DefaultServerRedirectStrategy.java
index 094b545780..af1e66d8bf 100644
--- a/web/src/main/java/org/springframework/security/web/server/DefaultServerRedirectStrategy.java
+++ b/web/src/main/java/org/springframework/security/web/server/DefaultServerRedirectStrategy.java
@@ -25,6 +25,8 @@ import reactor.core.publisher.Mono;
import java.net.URI;
/**
+ * The default {@link ServerRedirectStrategy} to use.
+ *
* @author Rob Winch
* @since 5.0
*/
@@ -55,6 +57,10 @@ public class DefaultServerRedirectStrategy implements ServerRedirectStrategy {
return location;
}
+ /**
+ * The {@link HttpStatus} to use for the redirect.
+ * @param httpStatus the status to use. Cannot be null
+ */
public void setHttpStatus(HttpStatus httpStatus) {
Assert.notNull(httpStatus, "httpStatus cannot be null");
this.httpStatus = httpStatus;
diff --git a/web/src/main/java/org/springframework/security/web/server/DelegatingServerAuthenticationEntryPoint.java b/web/src/main/java/org/springframework/security/web/server/DelegatingServerAuthenticationEntryPoint.java
index 91628bd7e1..5633e57ec6 100644
--- a/web/src/main/java/org/springframework/security/web/server/DelegatingServerAuthenticationEntryPoint.java
+++ b/web/src/main/java/org/springframework/security/web/server/DelegatingServerAuthenticationEntryPoint.java
@@ -29,6 +29,9 @@ import java.util.Arrays;
import java.util.List;
/**
+ * A {@link ServerAuthenticationEntryPoint} which delegates to multiple {@link ServerAuthenticationEntryPoint} based
+ * on a {@link ServerWebExchangeMatcher}
+ *
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/MatcherSecurityWebFilterChain.java b/web/src/main/java/org/springframework/security/web/server/MatcherSecurityWebFilterChain.java
index 99972e4bde..8f69333c6a 100644
--- a/web/src/main/java/org/springframework/security/web/server/MatcherSecurityWebFilterChain.java
+++ b/web/src/main/java/org/springframework/security/web/server/MatcherSecurityWebFilterChain.java
@@ -26,6 +26,9 @@ import reactor.core.publisher.Mono;
import java.util.List;
/**
+ * A {@link SecurityWebFilterChain} that leverages a {@link ServerWebExchangeMatcher} to determine which
+ * {@link WebFilter} to execute.
+ *
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/SecurityWebFilterChain.java b/web/src/main/java/org/springframework/security/web/server/SecurityWebFilterChain.java
index 3755dd2aaf..fff57d04d4 100644
--- a/web/src/main/java/org/springframework/security/web/server/SecurityWebFilterChain.java
+++ b/web/src/main/java/org/springframework/security/web/server/SecurityWebFilterChain.java
@@ -21,13 +21,25 @@ import org.springframework.web.server.WebFilter;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
-/**
+ /**
+ * Defines a filter chain which is capable of being matched against a {@link ServerWebExchange} in order to decide
+ * whether it applies to that request.
+ *
* @author Rob Winch
* @since 5.0
*/
public interface SecurityWebFilterChain {
+ /**
+ * Determines if this {@link SecurityWebFilterChain} matches the provided {@link ServerWebExchange}
+ * @param exchange the {@link ServerWebExchange}
+ * @return true if it matches, else false
+ */
Mono matches(ServerWebExchange exchange);
+ /**
+ * The {@link WebFilter} to use
+ * @return
+ */
Flux getWebFilters();
}
diff --git a/web/src/main/java/org/springframework/security/web/server/ServerAuthenticationEntryPoint.java b/web/src/main/java/org/springframework/security/web/server/ServerAuthenticationEntryPoint.java
index 4b658fa5c3..00272db067 100644
--- a/web/src/main/java/org/springframework/security/web/server/ServerAuthenticationEntryPoint.java
+++ b/web/src/main/java/org/springframework/security/web/server/ServerAuthenticationEntryPoint.java
@@ -21,11 +21,20 @@ import org.springframework.security.core.AuthenticationException;
import org.springframework.web.server.ServerWebExchange;
/**
+ * Used to request authentication
*
* @author Rob Winch
* @since 5.0
*/
+@FunctionalInterface
public interface ServerAuthenticationEntryPoint {
+ /**
+ * Initiates the authentication flow
+ *
+ * @param exchange
+ * @param e
+ * @return {@code Mono} to indicate when the request for authentication is complete
+ */
Mono commence(ServerWebExchange exchange, AuthenticationException e);
}
diff --git a/web/src/main/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverter.java b/web/src/main/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverter.java
index 7210828130..faaa19ed49 100644
--- a/web/src/main/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverter.java
+++ b/web/src/main/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverter.java
@@ -27,6 +27,7 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
+ * Converts from a {@link ServerWebExchange} to an {@link Authentication} that can be authenticated.
*
* @author Rob Winch
* @since 5.0
diff --git a/web/src/main/java/org/springframework/security/web/server/ServerRedirectStrategy.java b/web/src/main/java/org/springframework/security/web/server/ServerRedirectStrategy.java
index 912d9a95ad..c0ca8c5b5c 100644
--- a/web/src/main/java/org/springframework/security/web/server/ServerRedirectStrategy.java
+++ b/web/src/main/java/org/springframework/security/web/server/ServerRedirectStrategy.java
@@ -23,10 +23,19 @@ import reactor.core.publisher.Mono;
import org.springframework.web.server.ServerWebExchange;
/**
+ * A strategy for performing redirects.
+ *
* @author Rob Winch
* @since 5.0
*/
+@FunctionalInterface
public interface ServerRedirectStrategy {
+ /**
+ * Performs a redirect based upon the provided {@link ServerWebExchange} and {@link URI}
+ * @param exchange the {@link ServerWebExchange} to use
+ * @param location the location to redirect to
+ * @return {@code Mono} to indicate when redirect is complete
+ */
Mono sendRedirect(ServerWebExchange exchange, URI location);
}
diff --git a/web/src/main/java/org/springframework/security/web/server/WebFilterChainProxy.java b/web/src/main/java/org/springframework/security/web/server/WebFilterChainProxy.java
index 5bee97e2de..79edb47ee0 100644
--- a/web/src/main/java/org/springframework/security/web/server/WebFilterChainProxy.java
+++ b/web/src/main/java/org/springframework/security/web/server/WebFilterChainProxy.java
@@ -28,6 +28,8 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
+ * Used to delegate to a List of {@link SecurityWebFilterChain} instances.
+ *
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/WebFilterExchange.java b/web/src/main/java/org/springframework/security/web/server/WebFilterExchange.java
index 21ad4429b3..c7e6130327 100644
--- a/web/src/main/java/org/springframework/security/web/server/WebFilterExchange.java
+++ b/web/src/main/java/org/springframework/security/web/server/WebFilterExchange.java
@@ -21,6 +21,8 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
/**
+ * A composite of the {@link ServerWebExchange} and the {@link WebFilterChain}. This is typically used as a value object
+ * for handling success and failures.
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java b/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java
index 4445fefa43..f8c5d2c910 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java
@@ -36,6 +36,27 @@ import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
/**
+ * A {@link WebFilter} that performs authentication of a particular request. An outline of the logic:
+ *
+ *
+ * -
+ * A request comes in and if it does not match {@link #setRequiresAuthenticationMatcher(ServerWebExchangeMatcher)},
+ * then this filter does nothing and the {@link WebFilterChain} is continued. If it does match then...
+ *
+ * -
+ * An attempt to convert the {@link ServerWebExchange} into an {@link Authentication} is made. If the result is
+ * empty, then the filter does nothing more and the {@link WebFilterChain} is continued. If it does create an
+ * {@link Authentication}...
+ *
+ * -
+ * The {@link ReactiveAuthenticationManager} specified in
+ * {@link #AuthenticationWebFilter(ReactiveAuthenticationManager)} is used to perform authentication.
+ *
+ * -
+ * If authentication is successful, {@link ServerAuthenticationSuccessHandler} is invoked and the authentication
+ * is set on {@link ReactiveSecurityContextHolder}, else {@link ServerAuthenticationFailureHandler} is invoked
+ *
+ *
*
* @author Rob Winch
* @since 5.0
@@ -54,6 +75,10 @@ public class AuthenticationWebFilter implements WebFilter {
private ServerWebExchangeMatcher requiresAuthenticationMatcher = ServerWebExchangeMatchers.anyExchange();
+ /**
+ * Creates an instance
+ * @param authenticationManager the authentication manager to use
+ */
public AuthenticationWebFilter(ReactiveAuthenticationManager authenticationManager) {
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
this.authenticationManager = authenticationManager;
@@ -87,26 +112,53 @@ public class AuthenticationWebFilter implements WebFilter {
.subscriberContext(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(securityContext)));
}
+ /**
+ * Sets the repository for persisting the SecurityContext. Default is {@link NoOpServerSecurityContextRepository}
+ * @param securityContextRepository the repository to use
+ */
public void setSecurityContextRepository(
ServerSecurityContextRepository securityContextRepository) {
Assert.notNull(securityContextRepository, "securityContextRepository cannot be null");
this.securityContextRepository = securityContextRepository;
}
+ /**
+ * Sets the authentication success handler. Default is {@link WebFilterChainServerAuthenticationSuccessHandler}
+ * @param authenticationSuccessHandler the success handler to use
+ */
public void setAuthenticationSuccessHandler(ServerAuthenticationSuccessHandler authenticationSuccessHandler) {
+ Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null");
this.authenticationSuccessHandler = authenticationSuccessHandler;
}
+ /**
+ * Sets the strategy used for converting from a {@link ServerWebExchange} to an {@link Authentication} used for
+ * authenticating with the provided {@link ReactiveAuthenticationManager}. If the result is empty, then it signals
+ * that no authentication attempt should be made. The default converter is
+ * {@link ServerHttpBasicAuthenticationConverter}
+ * @param authenticationConverter the converter to use
+ */
public void setAuthenticationConverter(Function> authenticationConverter) {
+ Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
this.authenticationConverter = authenticationConverter;
}
+ /**
+ * Sets the failure handler used when authentication fails. The default is to prompt for basic authentication.
+ * @param authenticationFailureHandler the handler to use. Cannot be null.
+ */
public void setAuthenticationFailureHandler(
ServerAuthenticationFailureHandler authenticationFailureHandler) {
Assert.notNull(authenticationFailureHandler, "authenticationFailureHandler cannot be null");
this.authenticationFailureHandler = authenticationFailureHandler;
}
+ /**
+ * Sets the matcher used to determine when creating an {@link Authentication} from
+ * {@link #setAuthenticationConverter(Function)} to be authentication. If the converter returns an empty
+ * result, then no authentication is attempted. The default is any request
+ * @param requiresAuthenticationMatcher the matcher to use. Cannot be null.
+ */
public void setRequiresAuthenticationMatcher(
ServerWebExchangeMatcher requiresAuthenticationMatcher) {
Assert.notNull(requiresAuthenticationMatcher, "requiresAuthenticationMatcher cannot be null");
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/HttpBasicServerAuthenticationEntryPoint.java b/web/src/main/java/org/springframework/security/web/server/authentication/HttpBasicServerAuthenticationEntryPoint.java
index a32b8283b0..b71b11a4f9 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/HttpBasicServerAuthenticationEntryPoint.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/HttpBasicServerAuthenticationEntryPoint.java
@@ -25,6 +25,7 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
+ * Prompts a user for HTTP Basic authentication.
*
* @author Rob Winch
* @since 5.0
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationEntryPoint.java b/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationEntryPoint.java
index 516b8b30f2..5f6fc89632 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationEntryPoint.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationEntryPoint.java
@@ -43,11 +43,19 @@ public class RedirectServerAuthenticationEntryPoint
private ServerRequestCache requestCache = new WebSessionServerRequestCache();
+ /**
+ * Creates an instance
+ * @param location the location to redirect to (i.e. "/logout-success")
+ */
public RedirectServerAuthenticationEntryPoint(String location) {
Assert.notNull(location, "location cannot be null");
this.location = URI.create(location);
}
+ /**
+ * The request cache to use to save the request before sending a redirect.
+ * @param requestCache the cache to redirect to.
+ */
public void setRequestCache(ServerRequestCache requestCache) {
Assert.notNull(requestCache, "requestCache cannot be null");
this.requestCache = requestCache;
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationFailureHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationFailureHandler.java
index c1e7bbb3c4..198e3d50c9 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationFailureHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationFailureHandler.java
@@ -37,6 +37,10 @@ public class RedirectServerAuthenticationFailureHandler
private ServerRedirectStrategy redirectStrategy = new DefaultServerRedirectStrategy();
+ /**
+ * Creates an instance
+ * @param location the location to redirect to (i.e. "/login?failed")
+ */
public RedirectServerAuthenticationFailureHandler(String location) {
Assert.notNull(location, "location cannot be null");
this.location = URI.create(location);
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationSuccessHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationSuccessHandler.java
index 97de2eef79..5549dd94c3 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationSuccessHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/RedirectServerAuthenticationSuccessHandler.java
@@ -29,6 +29,8 @@ import reactor.core.publisher.Mono;
import java.net.URI;
/**
+ * Performs a redirect on authentication success. The default is to redirect to a saved request if present and
+ * otherwise "/".
* @author Rob Winch
* @since 5.0
*/
@@ -40,12 +42,24 @@ public class RedirectServerAuthenticationSuccessHandler
private ServerRequestCache requestCache = new WebSessionServerRequestCache();
+ /**
+ * Creates a new instance with location of "/"
+ */
public RedirectServerAuthenticationSuccessHandler() {}
+ /**
+ * Creates a new instance with the specified location
+ * @param location the location to redirect if the no request is cached in
+ * {@link #setRequestCache(ServerRequestCache)}
+ */
public RedirectServerAuthenticationSuccessHandler(String location) {
this.location = URI.create(location);
}
+ /**
+ * Sets the {@link ServerRequestCache} used to redirect to. Default is {@link WebSessionServerRequestCache}.
+ * @param requestCache the cache to use
+ */
public void setRequestCache(ServerRequestCache requestCache) {
Assert.notNull(requestCache, "requestCache cannot be null");
this.requestCache = requestCache;
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationEntryPointFailureHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationEntryPointFailureHandler.java
index 1779c38f9f..5524f76a96 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationEntryPointFailureHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationEntryPointFailureHandler.java
@@ -23,6 +23,7 @@ import org.springframework.util.Assert;
import reactor.core.publisher.Mono;
/**
+ * Adapts a {@link ServerAuthenticationEntryPoint} into a {@link ServerAuthenticationFailureHandler}
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationFailureHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationFailureHandler.java
index 390ce3b2d2..ea1d0f5197 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationFailureHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationFailureHandler.java
@@ -22,9 +22,17 @@ import reactor.core.publisher.Mono;
import org.springframework.security.web.server.WebFilterExchange;
/**
+ * Handles authentication failure
+ *
* @author Rob Winch
* @since 5.0
*/
public interface ServerAuthenticationFailureHandler {
+ /**
+ * Invoked when authentication attempt fails
+ * @param webFilterExchange the exchange
+ * @param exception the reason authentication failed
+ * @return a completion notification (success or error)
+ */
Mono onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException exception);
}
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationSuccessHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationSuccessHandler.java
index 4b34595ab3..7fdac73b56 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationSuccessHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationSuccessHandler.java
@@ -21,10 +21,17 @@ import org.springframework.security.web.server.WebFilterExchange;
import reactor.core.publisher.Mono;
/**
+ * Handles authentication success
* @author Rob Winch
* @since 5.0
*/
public interface ServerAuthenticationSuccessHandler {
+ /**
+ * Invoked when the application authenticates successfully
+ * @param webFilterExchange the exchange
+ * @param authentication the {@link Authentication}
+ * @return a completion notification (success or error)
+ */
Mono onAuthenticationSuccess(WebFilterExchange webFilterExchange,
Authentication authentication);
}
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/WebFilterChainServerAuthenticationSuccessHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/WebFilterChainServerAuthenticationSuccessHandler.java
index 4f3efcfe27..cd4685f243 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/WebFilterChainServerAuthenticationSuccessHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/WebFilterChainServerAuthenticationSuccessHandler.java
@@ -22,6 +22,8 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
+ * Success handler that continues the filter chain after authentication success.
+ *
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/logout/RedirectServerLogoutSuccessHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/logout/RedirectServerLogoutSuccessHandler.java
index d5f4afcde8..3bf87ae148 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/logout/RedirectServerLogoutSuccessHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/logout/RedirectServerLogoutSuccessHandler.java
@@ -26,6 +26,7 @@ import reactor.core.publisher.Mono;
import java.net.URI;
/**
+ * Performs a redirect on log out success.
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/logout/ServerLogoutHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/logout/ServerLogoutHandler.java
index 7e85ac1d99..a3f2e38bb3 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/logout/ServerLogoutHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/logout/ServerLogoutHandler.java
@@ -21,9 +21,17 @@ import org.springframework.security.web.server.WebFilterExchange;
import reactor.core.publisher.Mono;
/**
+ * Handles log out
* @author Rob Winch
* @since 5.0
+ * @see ServerLogoutSuccessHandler
*/
public interface ServerLogoutHandler {
+ /**
+ * Invoked when log out is requested
+ * @param exchange the exchange
+ * @param authentication the {@link Authentication}
+ * @return a completion notification (success or error)
+ */
Mono logout(WebFilterExchange exchange, Authentication authentication);
}
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/logout/ServerLogoutSuccessHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/logout/ServerLogoutSuccessHandler.java
index 66f96bb215..e1d16cfef6 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/logout/ServerLogoutSuccessHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/logout/ServerLogoutSuccessHandler.java
@@ -21,10 +21,18 @@ import org.springframework.security.web.server.WebFilterExchange;
import reactor.core.publisher.Mono;
/**
+ * Strategy for when log out was successfully performed (typically after {@link ServerLogoutHandler} is invoked).
* @author Rob Winch
* @since 5.0
+ * @see ServerLogoutHandler
*/
public interface ServerLogoutSuccessHandler {
+ /**
+ * Invoked after log out was successful
+ * @param exchange the exchange
+ * @param authentication the {@link Authentication}
+ * @return a completion notification (success or error)
+ */
Mono onLogoutSuccess(WebFilterExchange exchange, Authentication authentication);
}
diff --git a/web/src/main/java/org/springframework/security/web/server/context/NoOpServerSecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/server/context/NoOpServerSecurityContextRepository.java
index 2589eeb393..bcf9aa5c2a 100644
--- a/web/src/main/java/org/springframework/security/web/server/context/NoOpServerSecurityContextRepository.java
+++ b/web/src/main/java/org/springframework/security/web/server/context/NoOpServerSecurityContextRepository.java
@@ -22,6 +22,7 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
+ * A do nothing implementation of {@link ServerSecurityContextRepository}. Used in stateless applications.
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/context/ReactorContextWebFilter.java b/web/src/main/java/org/springframework/security/web/server/context/ReactorContextWebFilter.java
index e4e95078b7..45a6e53527 100644
--- a/web/src/main/java/org/springframework/security/web/server/context/ReactorContextWebFilter.java
+++ b/web/src/main/java/org/springframework/security/web/server/context/ReactorContextWebFilter.java
@@ -25,6 +25,9 @@ import reactor.core.publisher.Mono;
import reactor.util.context.Context;
/**
+ * Uses a {@link ServerSecurityContextRepository} to provide the {@link SecurityContext} to initialize the
+ * {@link ReactiveSecurityContextHolder}.
+ *
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/context/SecurityContextServerWebExchange.java b/web/src/main/java/org/springframework/security/web/server/context/SecurityContextServerWebExchange.java
index 3dcad60564..62290975b2 100644
--- a/web/src/main/java/org/springframework/security/web/server/context/SecurityContextServerWebExchange.java
+++ b/web/src/main/java/org/springframework/security/web/server/context/SecurityContextServerWebExchange.java
@@ -24,8 +24,10 @@ import org.springframework.web.server.ServerWebExchangeDecorator;
import reactor.core.publisher.Mono;
/**
+ * Overrides the {@link ServerWebExchange#getPrincipal()} with the provided SecurityContext
* @author Rob Winch
* @since 5.0
+ * @see SecurityContextServerWebExchangeWebFilter
*/
public class SecurityContextServerWebExchange extends ServerWebExchangeDecorator {
private final Mono context;
diff --git a/web/src/main/java/org/springframework/security/web/server/context/SecurityContextServerWebExchangeWebFilter.java b/web/src/main/java/org/springframework/security/web/server/context/SecurityContextServerWebExchangeWebFilter.java
index 46edccc7ff..888249b5a9 100644
--- a/web/src/main/java/org/springframework/security/web/server/context/SecurityContextServerWebExchangeWebFilter.java
+++ b/web/src/main/java/org/springframework/security/web/server/context/SecurityContextServerWebExchangeWebFilter.java
@@ -21,13 +21,9 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
-import reactor.util.context.Context;
-
-import java.security.Principal;
/**
- * Populate the {@link Principal} from {@link ServerWebExchange#getPrincipal()} into the
- * Reactor {@link Context}.
+ * Override the {@link ServerWebExchange#getPrincipal()} to be looked up using {@link ReactiveSecurityContextHolder}.
*
* @author Rob Winch
* @since 5.0
diff --git a/web/src/main/java/org/springframework/security/web/server/context/ServerSecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/server/context/ServerSecurityContextRepository.java
index cc6c9fdcc9..6c3b1dc985 100644
--- a/web/src/main/java/org/springframework/security/web/server/context/ServerSecurityContextRepository.java
+++ b/web/src/main/java/org/springframework/security/web/server/context/ServerSecurityContextRepository.java
@@ -20,9 +20,26 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
+/**
+ * Strategy used for persisting a {@link SecurityContext} between requests.
+ * @author Rob Winch
+ * @since 5.0
+ * @see ReactorContextWebFilter
+ */
public interface ServerSecurityContextRepository {
+ /**
+ * Saves the SecurityContext
+ * @param exchange the exchange to associate to the SecurityContext
+ * @param context the SecurityContext to save
+ * @return a completion notification (success or error)
+ */
Mono save(ServerWebExchange exchange, SecurityContext context);
+ /**
+ * Loads the SecurityContext associated with the {@link ServerWebExchange}
+ * @param exchange the exchange to look up the {@link SecurityContext}
+ * @return the {@link SecurityContext} to lookup or empty if not found. Never null
+ */
Mono load(ServerWebExchange exchange);
}
diff --git a/web/src/main/java/org/springframework/security/web/server/header/CacheControlServerHttpHeadersWriter.java b/web/src/main/java/org/springframework/security/web/server/header/CacheControlServerHttpHeadersWriter.java
index a4dc564ff8..ac6b094980 100644
--- a/web/src/main/java/org/springframework/security/web/server/header/CacheControlServerHttpHeadersWriter.java
+++ b/web/src/main/java/org/springframework/security/web/server/header/CacheControlServerHttpHeadersWriter.java
@@ -21,6 +21,13 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
+ * Writes cache control related headers.
+ *
+ *
+ * Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+ * Pragma: no-cache
+ * Expires: 0
+ *
*
* @author Rob Winch
* @since 5.0
diff --git a/web/src/main/java/org/springframework/security/web/server/header/CompositeServerHttpHeadersWriter.java b/web/src/main/java/org/springframework/security/web/server/header/CompositeServerHttpHeadersWriter.java
index 8120ee8cde..5df9572a59 100644
--- a/web/src/main/java/org/springframework/security/web/server/header/CompositeServerHttpHeadersWriter.java
+++ b/web/src/main/java/org/springframework/security/web/server/header/CompositeServerHttpHeadersWriter.java
@@ -25,6 +25,7 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
+ * Combines multiple {@link ServerHttpHeadersWriter} instances into a single instance.
*
* @author Rob Winch
* @since 5.0
diff --git a/web/src/main/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriter.java b/web/src/main/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriter.java
index af84bad896..eeadc70f26 100644
--- a/web/src/main/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriter.java
+++ b/web/src/main/java/org/springframework/security/web/server/header/StaticServerHttpHeadersWriter.java
@@ -24,6 +24,8 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
+ * Allows specifying {@link HttpHeaders} that should be written to the response.
+ *
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/header/StrictTransportSecurityServerHttpHeadersWriter.java b/web/src/main/java/org/springframework/security/web/server/header/StrictTransportSecurityServerHttpHeadersWriter.java
index b164c59d50..6313457966 100644
--- a/web/src/main/java/org/springframework/security/web/server/header/StrictTransportSecurityServerHttpHeadersWriter.java
+++ b/web/src/main/java/org/springframework/security/web/server/header/StrictTransportSecurityServerHttpHeadersWriter.java
@@ -22,6 +22,7 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
+ * Writes the Strict-Transport-Security if the request is secure.
* @author Rob Winch
* @since 5.0
*/
@@ -52,11 +53,19 @@ public final class StrictTransportSecurityServerHttpHeadersWriter
return isSecure(exchange) ? delegate.writeHttpHeaders(exchange) : Mono.empty();
}
+ /**
+ * Sets if subdomains should be included. Default is true
+ * @param includeSubDomains if subdomains should be included
+ */
public void setIncludeSubDomains(boolean includeSubDomains) {
subdomain = includeSubDomains ? " ; includeSubDomains" : "";
updateDelegate();
}
+ /**
+ * Sets the max age of the header. Default is a year.
+ * @param maxAge the max age of the header
+ */
public void setMaxAge(Duration maxAge) {
this.maxAge = "max-age=" + maxAge.getSeconds();
updateDelegate();
diff --git a/web/src/main/java/org/springframework/security/web/server/header/XFrameOptionsServerHttpHeadersWriter.java b/web/src/main/java/org/springframework/security/web/server/header/XFrameOptionsServerHttpHeadersWriter.java
index 9047a4a946..9b64764fcd 100644
--- a/web/src/main/java/org/springframework/security/web/server/header/XFrameOptionsServerHttpHeadersWriter.java
+++ b/web/src/main/java/org/springframework/security/web/server/header/XFrameOptionsServerHttpHeadersWriter.java
@@ -20,6 +20,7 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
+ * {@code ServerHttpHeadersWriter} implementation for the X-Frame-Options headers.
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriter.java b/web/src/main/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriter.java
index 69e7eb78a6..2e7cf31677 100644
--- a/web/src/main/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriter.java
+++ b/web/src/main/java/org/springframework/security/web/server/header/XXssProtectionServerHttpHeadersWriter.java
@@ -20,6 +20,8 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
+ * Add the x-xss-protection header.
+ *
* @author Rob Winch
* @since 5.0
*/
@@ -33,7 +35,7 @@ public class XXssProtectionServerHttpHeadersWriter implements ServerHttpHeadersW
private ServerHttpHeadersWriter delegate;
/**
- *
+ * Creates a new instance
*/
public XXssProtectionServerHttpHeadersWriter() {
this.enabled = true;
diff --git a/web/src/main/java/org/springframework/security/web/server/savedrequest/NoOpServerRequestCache.java b/web/src/main/java/org/springframework/security/web/server/savedrequest/NoOpServerRequestCache.java
index 934e1bde06..5fd16b453b 100644
--- a/web/src/main/java/org/springframework/security/web/server/savedrequest/NoOpServerRequestCache.java
+++ b/web/src/main/java/org/springframework/security/web/server/savedrequest/NoOpServerRequestCache.java
@@ -23,6 +23,7 @@ import reactor.core.publisher.Mono;
import java.net.URI;
/**
+ * An implementation of {@link ServerRequestCache} that does nothing. This is used in stateless applications
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/ui/LoginPageGeneratingWebFilter.java b/web/src/main/java/org/springframework/security/web/server/ui/LoginPageGeneratingWebFilter.java
index e077ebcb2a..6be4f8bbca 100644
--- a/web/src/main/java/org/springframework/security/web/server/ui/LoginPageGeneratingWebFilter.java
+++ b/web/src/main/java/org/springframework/security/web/server/ui/LoginPageGeneratingWebFilter.java
@@ -34,6 +34,8 @@ import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
/**
+ * Generates a default log in page used for authenticating users.
+ *
* @author Rob Winch
* @since 5.0
*/
@@ -54,7 +56,6 @@ public class LoginPageGeneratingWebFilter implements WebFilter {
result.setStatusCode(HttpStatus.OK);
result.getHeaders().setContentType(MediaType.TEXT_HTML);
return result.writeWith(createBuffer(exchange));
-// .doOnError( error -> DataBufferUtils.release(buffer));
}
private Mono createBuffer(ServerWebExchange exchange) {
diff --git a/web/src/main/java/org/springframework/security/web/server/ui/LogoutPageGeneratingWebFilter.java b/web/src/main/java/org/springframework/security/web/server/ui/LogoutPageGeneratingWebFilter.java
index 7100a7b99e..dede96e140 100644
--- a/web/src/main/java/org/springframework/security/web/server/ui/LogoutPageGeneratingWebFilter.java
+++ b/web/src/main/java/org/springframework/security/web/server/ui/LogoutPageGeneratingWebFilter.java
@@ -33,6 +33,8 @@ import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
/**
+ * Generates a default log out page.
+ *
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/util/matcher/AndServerWebExchangeMatcher.java b/web/src/main/java/org/springframework/security/web/server/util/matcher/AndServerWebExchangeMatcher.java
index 1f57d24203..7fdb25e93f 100644
--- a/web/src/main/java/org/springframework/security/web/server/util/matcher/AndServerWebExchangeMatcher.java
+++ b/web/src/main/java/org/springframework/security/web/server/util/matcher/AndServerWebExchangeMatcher.java
@@ -26,8 +26,10 @@ import java.util.List;
import java.util.Map;
/**
+ * Matches if all the provided {@link ServerWebExchangeMatcher} match
* @author Rob Winch
* @since 5.0
+ * @see OrServerWebExchangeMatcher
*/
public class AndServerWebExchangeMatcher implements ServerWebExchangeMatcher {
private final List matchers;
diff --git a/web/src/main/java/org/springframework/security/web/server/util/matcher/MediaTypeServerWebExchangeMatcher.java b/web/src/main/java/org/springframework/security/web/server/util/matcher/MediaTypeServerWebExchangeMatcher.java
index 58d14cea77..c14e50de12 100644
--- a/web/src/main/java/org/springframework/security/web/server/util/matcher/MediaTypeServerWebExchangeMatcher.java
+++ b/web/src/main/java/org/springframework/security/web/server/util/matcher/MediaTypeServerWebExchangeMatcher.java
@@ -34,6 +34,8 @@ import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
/**
+ * Matches based upon the accept headers.
+ *
* @author Rob Winch
* @since 5.0
*/
@@ -44,12 +46,20 @@ public class MediaTypeServerWebExchangeMatcher implements ServerWebExchangeMatch
private boolean useEquals;
private Set ignoredMediaTypes = Collections.emptySet();
+ /**
+ * Creates a new instance
+ * @param matchingMediaTypes the types to match on
+ */
public MediaTypeServerWebExchangeMatcher(MediaType... matchingMediaTypes) {
Assert.notEmpty(matchingMediaTypes, "matchingMediaTypes cannot be null");
Assert.noNullElements(matchingMediaTypes, "matchingMediaTypes cannot contain null");
this.matchingMediaTypes = Arrays.asList(matchingMediaTypes);
}
+ /**
+ * Creates a new instance
+ * @param matchingMediaTypes the types to match on
+ */
public MediaTypeServerWebExchangeMatcher(Collection matchingMediaTypes) {
Assert.notEmpty(matchingMediaTypes, "matchingMediaTypes cannot be null");
Assert.isTrue(!matchingMediaTypes.contains(null), () -> "matchingMediaTypes cannot contain null. Got " + matchingMediaTypes);
diff --git a/web/src/main/java/org/springframework/security/web/server/util/matcher/OrServerWebExchangeMatcher.java b/web/src/main/java/org/springframework/security/web/server/util/matcher/OrServerWebExchangeMatcher.java
index 03ce16990f..4a39c4b3ad 100644
--- a/web/src/main/java/org/springframework/security/web/server/util/matcher/OrServerWebExchangeMatcher.java
+++ b/web/src/main/java/org/springframework/security/web/server/util/matcher/OrServerWebExchangeMatcher.java
@@ -24,8 +24,10 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
+ * Matches if any of the provided {@link ServerWebExchangeMatcher} match
* @author Rob Winch
* @since 5.0
+ * @see AndServerWebExchangeMatcher
*/
public class OrServerWebExchangeMatcher implements ServerWebExchangeMatcher {
private final List matchers;
diff --git a/web/src/main/java/org/springframework/security/web/server/util/matcher/PathPatternParserServerWebExchangeMatcher.java b/web/src/main/java/org/springframework/security/web/server/util/matcher/PathPatternParserServerWebExchangeMatcher.java
index 381095cb5e..25ff4a7ba5 100644
--- a/web/src/main/java/org/springframework/security/web/server/util/matcher/PathPatternParserServerWebExchangeMatcher.java
+++ b/web/src/main/java/org/springframework/security/web/server/util/matcher/PathPatternParserServerWebExchangeMatcher.java
@@ -28,6 +28,7 @@ import java.util.HashMap;
import java.util.Map;
/**
+ * Matches if the {@link PathPattern} matches the path within the application.
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatcher.java b/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatcher.java
index a35743cac3..bf4640f3ef 100644
--- a/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatcher.java
+++ b/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatcher.java
@@ -22,14 +22,22 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
- *
+ * An interface for determining if a {@link ServerWebExchangeMatcher} matches.
* @author Rob Winch
* @since 5.0
*/
public interface ServerWebExchangeMatcher {
+ /**
+ * Determines if a request matches or not
+ * @param exchange
+ * @return
+ */
Mono matches(ServerWebExchange exchange);
+ /**
+ * The result of matching
+ */
class MatchResult {
private final boolean match;
private final Map variables;
@@ -43,18 +51,36 @@ public interface ServerWebExchangeMatcher {
return match;
}
+ /**
+ * Gets potential variables and their values
+ * @return
+ */
public Map getVariables() {
return variables;
}
+ /**
+ * Creates an instance of {@link MatchResult} that is a match with no variables
+ * @return
+ */
public static Mono match() {
return match(Collections.emptyMap());
}
+ /**
+ *
+ * Creates an instance of {@link MatchResult} that is a match with the specified variables
+ * @param variables
+ * @return
+ */
public static Mono match(Map variables) {
return Mono.just(new MatchResult(true, variables));
}
+ /**
+ * Creates an instance of {@link MatchResult} that is not a match.
+ * @return
+ */
public static Mono notMatch() {
return Mono.just(new MatchResult(false, Collections.emptyMap()));
}
diff --git a/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatcherEntry.java b/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatcherEntry.java
index 89326ebd68..8fe615dfd9 100644
--- a/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatcherEntry.java
+++ b/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatcherEntry.java
@@ -17,6 +17,7 @@
package org.springframework.security.web.server.util.matcher;
/**
+ * A rich object for associating a {@link ServerWebExchangeMatcher} to another object.
* @author Rob Winch
* @since 5.0
*/
diff --git a/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatchers.java b/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatchers.java
index 693a5934dd..344a84bfed 100644
--- a/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatchers.java
+++ b/web/src/main/java/org/springframework/security/web/server/util/matcher/ServerWebExchangeMatchers.java
@@ -23,11 +23,18 @@ import java.util.ArrayList;
import java.util.List;
/**
+ * Provides factory methods for creating common {@link ServerWebExchangeMatcher}
* @author Rob Winch
* @since 5.0
*/
public abstract class ServerWebExchangeMatchers {
+ /**
+ * Creates a matcher that matches on the specific method and any of the provided patterns.
+ * @param method the method to match on. If null, any method will be matched
+ * @param patterns the patterns to match on
+ * @return the matcher to use
+ */
public static ServerWebExchangeMatcher pathMatchers(HttpMethod method, String... patterns) {
List matchers = new ArrayList<>(patterns.length);
for (String pattern : patterns) {
@@ -36,15 +43,31 @@ public abstract class ServerWebExchangeMatchers {
return new OrServerWebExchangeMatcher(matchers);
}
+ /**
+ * Creates a matcher that matches on any of the provided patterns.
+ * @param patterns the patterns to match on
+ * @return the matcher to use
+ */
public static ServerWebExchangeMatcher pathMatchers(String... patterns) {
return pathMatchers(null, patterns);
}
+ /**
+ * Creates a matcher that will match on any of the provided matchers
+ * @param matchers the matchers to match on
+ * @return the matcher to use
+ */
public static ServerWebExchangeMatcher matchers(ServerWebExchangeMatcher... matchers) {
return new OrServerWebExchangeMatcher(matchers);
}
+ /**
+ * Matches any exchange
+ * @return the matcher to use
+ */
public static ServerWebExchangeMatcher anyExchange() {
+ // we don't use a lambda to ensure a unique equals and hashcode
+ // which otherwise can cause problems with adding multiple entries to an ordered LinkedHashMap
return new ServerWebExchangeMatcher() {
@Override
public Mono matches(ServerWebExchange exchange) {