From 151b545ed045a475444560ec5c85ad9edd39b8a2 Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Tue, 27 Mar 2018 21:05:29 -0500 Subject: [PATCH] Polish Javadoc Fixes: gh-5186 --- .../web/reactive/EnableWebFluxSecurity.java | 2 +- .../config/web/server/ServerHttpSecurity.java | 623 +++++++++++++++++- ...rePostAdviceReactiveMethodInterceptor.java | 9 + .../ReactiveAuthenticationManager.java | 1 + ...positoryReactiveAuthenticationManager.java | 8 + .../MapReactiveUserDetailsService.java | 13 + .../ReactiveUserDetailsService.java | 13 +- .../server/DefaultServerRedirectStrategy.java | 6 + ...egatingServerAuthenticationEntryPoint.java | 3 + .../server/MatcherSecurityWebFilterChain.java | 3 + .../web/server/SecurityWebFilterChain.java | 14 +- .../ServerAuthenticationEntryPoint.java | 9 + ...erverHttpBasicAuthenticationConverter.java | 1 + .../web/server/ServerRedirectStrategy.java | 9 + .../web/server/WebFilterChainProxy.java | 2 + .../web/server/WebFilterExchange.java | 2 + .../AuthenticationWebFilter.java | 52 ++ ...tpBasicServerAuthenticationEntryPoint.java | 1 + ...edirectServerAuthenticationEntryPoint.java | 8 + ...ectServerAuthenticationFailureHandler.java | 4 + ...ectServerAuthenticationSuccessHandler.java | 14 + ...uthenticationEntryPointFailureHandler.java | 1 + .../ServerAuthenticationFailureHandler.java | 8 + .../ServerAuthenticationSuccessHandler.java | 7 + ...ainServerAuthenticationSuccessHandler.java | 2 + .../RedirectServerLogoutSuccessHandler.java | 1 + .../logout/ServerLogoutHandler.java | 8 + .../logout/ServerLogoutSuccessHandler.java | 8 + .../NoOpServerSecurityContextRepository.java | 1 + .../context/ReactorContextWebFilter.java | 3 + .../SecurityContextServerWebExchange.java | 2 + ...rityContextServerWebExchangeWebFilter.java | 6 +- .../ServerSecurityContextRepository.java | 17 + .../CacheControlServerHttpHeadersWriter.java | 7 + .../CompositeServerHttpHeadersWriter.java | 1 + .../header/StaticServerHttpHeadersWriter.java | 2 + ...nsportSecurityServerHttpHeadersWriter.java | 9 + .../XFrameOptionsServerHttpHeadersWriter.java | 1 + ...XXssProtectionServerHttpHeadersWriter.java | 4 +- .../savedrequest/NoOpServerRequestCache.java | 1 + .../ui/LoginPageGeneratingWebFilter.java | 3 +- .../ui/LogoutPageGeneratingWebFilter.java | 2 + .../matcher/AndServerWebExchangeMatcher.java | 2 + .../MediaTypeServerWebExchangeMatcher.java | 10 + .../matcher/OrServerWebExchangeMatcher.java | 2 + ...PatternParserServerWebExchangeMatcher.java | 1 + .../matcher/ServerWebExchangeMatcher.java | 28 +- .../ServerWebExchangeMatcherEntry.java | 1 + .../matcher/ServerWebExchangeMatchers.java | 23 + 49 files changed, 931 insertions(+), 27 deletions(-) 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) {