diff --git a/config/src/main/java/org/springframework/security/config/web/server/AuthorizeExchangeBuilder.java b/config/src/main/java/org/springframework/security/config/web/server/AuthorizeExchangeBuilder.java deleted file mode 100644 index cea45f4302..0000000000 --- a/config/src/main/java/org/springframework/security/config/web/server/AuthorizeExchangeBuilder.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.security.config.web.server; - -import org.springframework.security.authorization.AuthenticatedAuthorizationManager; -import org.springframework.security.authorization.AuthorizationDecision; -import org.springframework.security.web.server.authorization.AuthorizationContext; -import org.springframework.security.authorization.ReactiveAuthorizationManager; -import org.springframework.security.authorization.AuthorityAuthorizationManager; -import org.springframework.security.web.server.authorization.AuthorizationWebFilter; -import org.springframework.security.web.server.authorization.DelegatingReactiveAuthorizationManager; -import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; -import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcherEntry; -import org.springframework.web.server.WebFilter; -import reactor.core.publisher.Mono; - -/** - * @author Rob Winch - * @since 5.0 - */ -public class AuthorizeExchangeBuilder extends AbstractServerWebExchangeMatcherRegistry { - private DelegatingReactiveAuthorizationManager.Builder managerBldr = DelegatingReactiveAuthorizationManager.builder(); - private ServerWebExchangeMatcher matcher; - private boolean anyExchangeRegistered; - - @Override - public Access anyExchange() { - Access result = super.anyExchange(); - anyExchangeRegistered = true; - return result; - } - - @Override - protected Access registerMatcher(ServerWebExchangeMatcher matcher) { - if(anyExchangeRegistered) { - throw new IllegalStateException("Cannot register " + matcher + " which would be unreachable because anyExchange() has already been registered."); - } - if(this.matcher != null) { - throw new IllegalStateException("The matcher " + matcher + " does not have an access rule defined"); - } - this.matcher = matcher; - return new Access(); - } - - public WebFilter build() { - if(this.matcher != null) { - throw new IllegalStateException("The matcher " + matcher + " does not have an access rule defined"); - } - return new AuthorizationWebFilter(managerBldr.build()); - } - - public final class Access { - - public AuthorizeExchangeBuilder permitAll() { - return access( (a,e) -> Mono.just(new AuthorizationDecision(true))); - } - - public AuthorizeExchangeBuilder denyAll() { - return access( (a,e) -> Mono.just(new AuthorizationDecision(false))); - } - - public AuthorizeExchangeBuilder hasRole(String role) { - return access(AuthorityAuthorizationManager.hasRole(role)); - } - - public AuthorizeExchangeBuilder hasAuthority(String authority) { - return access(AuthorityAuthorizationManager.hasAuthority(authority)); - } - - public AuthorizeExchangeBuilder authenticated() { - return access(AuthenticatedAuthorizationManager.authenticated()); - } - - public AuthorizeExchangeBuilder access(ReactiveAuthorizationManager manager) { - managerBldr.add(new ServerWebExchangeMatcherEntry<>(matcher, manager)); - matcher = null; - return AuthorizeExchangeBuilder.this; - } - } -} diff --git a/config/src/main/java/org/springframework/security/config/web/server/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/HttpSecurity.java index a03bea9fbc..5087afe14d 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/HttpSecurity.java @@ -20,15 +20,24 @@ import java.util.List; import java.util.Optional; import org.springframework.security.authentication.ReactiveAuthenticationManager; +import org.springframework.security.authorization.AuthenticatedAuthorizationManager; +import org.springframework.security.authorization.AuthorityAuthorizationManager; +import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.ReactiveAuthorizationManager; import org.springframework.security.web.server.MatcherSecurityWebFilterChain; import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.authorization.AuthorizationContext; +import org.springframework.security.web.server.authorization.AuthorizationWebFilter; +import org.springframework.security.web.server.authorization.DelegatingReactiveAuthorizationManager; import org.springframework.security.web.server.context.SecurityContextRepositoryWebFilter; import org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter; import org.springframework.security.web.server.context.SecurityContextRepository; import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; +import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcherEntry; import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers; import org.springframework.util.Assert; import org.springframework.web.server.WebFilter; +import reactor.core.publisher.Mono; /** * @author Rob Winch @@ -129,4 +138,73 @@ public class HttpSecurity { } private HttpSecurity() {} + + /** + * @author Rob Winch + * @since 5.0 + */ + public class AuthorizeExchangeBuilder extends AbstractServerWebExchangeMatcherRegistry { + private DelegatingReactiveAuthorizationManager.Builder managerBldr = DelegatingReactiveAuthorizationManager.builder(); + private ServerWebExchangeMatcher matcher; + private boolean anyExchangeRegistered; + + public HttpSecurity and() { + return HttpSecurity.this; + } + + @Override + public Access anyExchange() { + Access result = super.anyExchange(); + anyExchangeRegistered = true; + return result; + } + + @Override + protected Access registerMatcher(ServerWebExchangeMatcher matcher) { + if(anyExchangeRegistered) { + throw new IllegalStateException("Cannot register " + matcher + " which would be unreachable because anyExchange() has already been registered."); + } + if(this.matcher != null) { + throw new IllegalStateException("The matcher " + matcher + " does not have an access rule defined"); + } + this.matcher = matcher; + return new Access(); + } + + protected WebFilter build() { + if(this.matcher != null) { + throw new IllegalStateException("The matcher " + matcher + " does not have an access rule defined"); + } + return new AuthorizationWebFilter(managerBldr.build()); + } + + public final class Access { + + public AuthorizeExchangeBuilder permitAll() { + return access( (a,e) -> Mono.just(new AuthorizationDecision(true))); + } + + public AuthorizeExchangeBuilder denyAll() { + return access( (a,e) -> Mono.just(new AuthorizationDecision(false))); + } + + public AuthorizeExchangeBuilder hasRole(String role) { + return access(AuthorityAuthorizationManager.hasRole(role)); + } + + public AuthorizeExchangeBuilder hasAuthority(String authority) { + return access(AuthorityAuthorizationManager.hasAuthority(authority)); + } + + public AuthorizeExchangeBuilder authenticated() { + return access(AuthenticatedAuthorizationManager.authenticated()); + } + + public AuthorizeExchangeBuilder access(ReactiveAuthorizationManager manager) { + managerBldr.add(new ServerWebExchangeMatcherEntry<>(matcher, manager)); + matcher = null; + return AuthorizeExchangeBuilder.this; + } + } + } } diff --git a/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeBuilderTests.java b/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeBuilderTests.java index 25887c1b31..f3924b6fff 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeBuilderTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/AuthorizeExchangeBuilderTests.java @@ -29,7 +29,7 @@ import org.springframework.test.web.reactive.server.WebTestClient; * @since 5.0 */ public class AuthorizeExchangeBuilderTests { - AuthorizeExchangeBuilder authorization = new AuthorizeExchangeBuilder(); + HttpSecurity.AuthorizeExchangeBuilder authorization = HttpSecurity.http().new AuthorizeExchangeBuilder(); @Test public void antMatchersWhenMethodAndPatternsThenDiscriminatesByMethod() { diff --git a/config/src/test/java/org/springframework/security/config/web/server/HttpSecurityTests.java b/config/src/test/java/org/springframework/security/config/web/server/HttpSecurityTests.java index 4126c4daf0..54df31838c 100644 --- a/config/src/test/java/org/springframework/security/config/web/server/HttpSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/web/server/HttpSecurityTests.java @@ -83,7 +83,7 @@ public class HttpSecurityTests { http.securityContextRepository(new WebSessionSecurityContextRepository()); http.httpBasic(); http.authenticationManager(authenticationManager); - AuthorizeExchangeBuilder authorize = http.authorizeExchange(); + HttpSecurity.AuthorizeExchangeBuilder authorize = http.authorizeExchange(); authorize.anyExchange().authenticated(); WebTestClient client = buildClient(); diff --git a/samples/javaconfig/hellowebflux/src/main/java/sample/SecurityConfig.java b/samples/javaconfig/hellowebflux/src/main/java/sample/SecurityConfig.java index 1dca016f55..3166596d6b 100644 --- a/samples/javaconfig/hellowebflux/src/main/java/sample/SecurityConfig.java +++ b/samples/javaconfig/hellowebflux/src/main/java/sample/SecurityConfig.java @@ -39,12 +39,13 @@ public class SecurityConfig { @Bean SecurityWebFilterChain springWebFilterChain(HttpSecurity http) throws Exception { - http.authorizeExchange() - .pathMatchers("/admin/**").hasRole("ADMIN") - .pathMatchers("/users/{user}/**").access(this::currentUserMatchesPath) - .anyExchange().authenticated(); - - return http.build(); + return http + .authorizeExchange() + .pathMatchers("/admin/**").hasRole("ADMIN") + .pathMatchers("/users/{user}/**").access(this::currentUserMatchesPath) + .anyExchange().authenticated() + .and() + .build(); } private Mono currentUserMatchesPath(Mono authentication, AuthorizationContext context) { diff --git a/samples/javaconfig/hellowebfluxfn/src/main/java/sample/SecurityConfig.java b/samples/javaconfig/hellowebfluxfn/src/main/java/sample/SecurityConfig.java index e3bd584e11..86f856a01e 100644 --- a/samples/javaconfig/hellowebfluxfn/src/main/java/sample/SecurityConfig.java +++ b/samples/javaconfig/hellowebfluxfn/src/main/java/sample/SecurityConfig.java @@ -40,12 +40,13 @@ public class SecurityConfig { @Bean SecurityWebFilterChain httpSecurity(HttpSecurity http) throws Exception { - http.authorizeExchange() - .pathMatchers("/admin/**").hasRole("ADMIN") - .pathMatchers("/users/{user}/**").access(this::currentUserMatchesPath) - .anyExchange().authenticated(); - - return http.build(); + return http + .authorizeExchange() + .pathMatchers("/admin/**").hasRole("ADMIN") + .pathMatchers("/users/{user}/**").access(this::currentUserMatchesPath) + .anyExchange().authenticated() + .and() + .build(); } private Mono currentUserMatchesPath(Mono authentication, AuthorizationContext context) {