Support .and() in Reactive HttpBasic & HeaderBuilder

This commit is contained in:
Rob Winch 2017-08-29 20:08:39 -05:00
parent 539e76059a
commit 20befc3702
4 changed files with 160 additions and 187 deletions

View File

@ -1,128 +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.web.server.header.CacheControlHttpHeadersWriter;
import org.springframework.security.web.server.header.CompositeHttpHeadersWriter;
import org.springframework.security.web.server.header.ContentTypeOptionsHttpHeadersWriter;
import org.springframework.security.web.server.header.HttpHeaderWriterWebFilter;
import org.springframework.security.web.server.header.HttpHeadersWriter;
import org.springframework.security.web.server.header.StrictTransportSecurityHttpHeadersWriter;
import org.springframework.security.web.server.header.XFrameOptionsHttpHeadersWriter;
import org.springframework.security.web.server.header.XXssProtectionHttpHeadersWriter;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Rob Winch
* @since 5.0
*/
public class HeaderBuilder {
private final List<HttpHeadersWriter> writers;
private CacheControlHttpHeadersWriter cacheControl = new CacheControlHttpHeadersWriter();
private ContentTypeOptionsHttpHeadersWriter contentTypeOptions = new ContentTypeOptionsHttpHeadersWriter();
private StrictTransportSecurityHttpHeadersWriter hsts = new StrictTransportSecurityHttpHeadersWriter();
private XFrameOptionsHttpHeadersWriter frameOptions = new XFrameOptionsHttpHeadersWriter();
private XXssProtectionHttpHeadersWriter xss = new XXssProtectionHttpHeadersWriter();
public HeaderBuilder() {
this.writers = new ArrayList<>(Arrays.asList(cacheControl, contentTypeOptions, hsts, frameOptions, xss));
}
public CacheSpec cache() {
return new CacheSpec();
}
public ContentTypeOptionsSpec contentTypeOptions() {
return new ContentTypeOptionsSpec();
}
public FrameOptionsSpec frameOptions() {
return new FrameOptionsSpec();
}
public HstsSpec hsts() {
return new HstsSpec();
}
public HttpHeaderWriterWebFilter build() {
HttpHeadersWriter writer = new CompositeHttpHeadersWriter(writers);
return new HttpHeaderWriterWebFilter(writer);
}
public XssProtectionSpec xssProtection() {
return new XssProtectionSpec();
}
public class CacheSpec {
public void disable() {
writers.remove(cacheControl);
}
private CacheSpec() {}
}
public class ContentTypeOptionsSpec {
public void disable() {
writers.remove(contentTypeOptions);
}
private ContentTypeOptionsSpec() {}
}
public class FrameOptionsSpec {
public void mode(XFrameOptionsHttpHeadersWriter.Mode mode) {
frameOptions.setMode(mode);
}
public void disable() {
writers.remove(frameOptions);
}
private FrameOptionsSpec() {}
}
public class HstsSpec {
public void maxAge(Duration maxAge) {
hsts.setMaxAge(maxAge);
}
public void includeSubdomains(boolean includeSubDomains) {
hsts.setIncludeSubDomains(includeSubDomains);
}
public void disable() {
writers.remove(hsts);
}
private HstsSpec() {}
}
public class XssProtectionSpec {
public void disable() {
writers.remove(xss);
}
private XssProtectionSpec() {}
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright 2002-2016 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.authentication.ReactiveAuthenticationManager;
import org.springframework.security.web.server.AuthenticationEntryPoint;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.HttpBasicAuthenticationConverter;
import org.springframework.security.web.server.authentication.DefaultAuthenticationSuccessHandler;
import org.springframework.security.web.server.authentication.www.HttpBasicAuthenticationEntryPoint;
import org.springframework.security.web.server.context.SecurityContextRepository;
/**
* @author Rob Winch
* @since 5.0
*/
public class HttpBasicBuilder {
private ReactiveAuthenticationManager authenticationManager;
private SecurityContextRepository securityContextRepository;
private AuthenticationEntryPoint entryPoint = new HttpBasicAuthenticationEntryPoint();
public HttpBasicBuilder authenticationManager(ReactiveAuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
return this;
}
public HttpBasicBuilder securityContextRepository(SecurityContextRepository securityContextRepository) {
this.securityContextRepository = securityContextRepository;
return this;
}
public AuthenticationWebFilter build() {
AuthenticationWebFilter authenticationFilter = new AuthenticationWebFilter(authenticationManager);
authenticationFilter.setEntryPoint(entryPoint);
authenticationFilter.setAuthenticationConverter(new HttpBasicAuthenticationConverter());
if(securityContextRepository != null) {
DefaultAuthenticationSuccessHandler handler = new DefaultAuthenticationSuccessHandler();
handler.setSecurityContextRepository(securityContextRepository);
authenticationFilter.setAuthenticationSuccessHandler(handler);
}
return authenticationFilter;
}
}

View File

@ -15,7 +15,9 @@
*/
package org.springframework.security.config.web.server;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@ -24,8 +26,13 @@ import org.springframework.security.authorization.AuthenticatedAuthorizationMana
import org.springframework.security.authorization.AuthorityAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.web.server.AuthenticationEntryPoint;
import org.springframework.security.web.server.HttpBasicAuthenticationConverter;
import org.springframework.security.web.server.MatcherSecurityWebFilterChain;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.authentication.DefaultAuthenticationSuccessHandler;
import org.springframework.security.web.server.authentication.www.HttpBasicAuthenticationEntryPoint;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.security.web.server.authorization.AuthorizationWebFilter;
import org.springframework.security.web.server.authorization.DelegatingReactiveAuthorizationManager;
@ -33,6 +40,14 @@ import org.springframework.security.web.server.context.AuthenticationReactorCont
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.header.CacheControlHttpHeadersWriter;
import org.springframework.security.web.server.header.CompositeHttpHeadersWriter;
import org.springframework.security.web.server.header.ContentTypeOptionsHttpHeadersWriter;
import org.springframework.security.web.server.header.HttpHeaderWriterWebFilter;
import org.springframework.security.web.server.header.HttpHeadersWriter;
import org.springframework.security.web.server.header.StrictTransportSecurityHttpHeadersWriter;
import org.springframework.security.web.server.header.XFrameOptionsHttpHeadersWriter;
import org.springframework.security.web.server.header.XXssProtectionHttpHeadersWriter;
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;
@ -209,4 +224,147 @@ public class HttpSecurity {
}
}
}
/**
* @author Rob Winch
* @since 5.0
*/
public class HttpBasicBuilder {
private ReactiveAuthenticationManager authenticationManager;
private SecurityContextRepository securityContextRepository;
private AuthenticationEntryPoint entryPoint = new HttpBasicAuthenticationEntryPoint();
public HttpBasicBuilder authenticationManager(ReactiveAuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
return this;
}
public HttpBasicBuilder securityContextRepository(SecurityContextRepository securityContextRepository) {
this.securityContextRepository = securityContextRepository;
return this;
}
public HttpSecurity and() {
return HttpSecurity.this;
}
protected AuthenticationWebFilter build() {
AuthenticationWebFilter authenticationFilter = new AuthenticationWebFilter(authenticationManager);
authenticationFilter.setEntryPoint(entryPoint);
authenticationFilter.setAuthenticationConverter(new HttpBasicAuthenticationConverter());
if(securityContextRepository != null) {
DefaultAuthenticationSuccessHandler handler = new DefaultAuthenticationSuccessHandler();
handler.setSecurityContextRepository(securityContextRepository);
authenticationFilter.setAuthenticationSuccessHandler(handler);
}
return authenticationFilter;
}
private HttpBasicBuilder() {}
}
/**
* @author Rob Winch
* @since 5.0
*/
public class HeaderBuilder {
private final List<HttpHeadersWriter> writers;
private CacheControlHttpHeadersWriter cacheControl = new CacheControlHttpHeadersWriter();
private ContentTypeOptionsHttpHeadersWriter contentTypeOptions = new ContentTypeOptionsHttpHeadersWriter();
private StrictTransportSecurityHttpHeadersWriter hsts = new StrictTransportSecurityHttpHeadersWriter();
private XFrameOptionsHttpHeadersWriter frameOptions = new XFrameOptionsHttpHeadersWriter();
private XXssProtectionHttpHeadersWriter xss = new XXssProtectionHttpHeadersWriter();
public HttpSecurity and() {
return HttpSecurity.this;
}
public CacheSpec cache() {
return new CacheSpec();
}
public ContentTypeOptionsSpec contentTypeOptions() {
return new ContentTypeOptionsSpec();
}
public FrameOptionsSpec frameOptions() {
return new FrameOptionsSpec();
}
public HstsSpec hsts() {
return new HstsSpec();
}
public HttpHeaderWriterWebFilter build() {
HttpHeadersWriter writer = new CompositeHttpHeadersWriter(writers);
return new HttpHeaderWriterWebFilter(writer);
}
public XssProtectionSpec xssProtection() {
return new XssProtectionSpec();
}
public class CacheSpec {
public void disable() {
writers.remove(cacheControl);
}
private CacheSpec() {}
}
public class ContentTypeOptionsSpec {
public void disable() {
writers.remove(contentTypeOptions);
}
private ContentTypeOptionsSpec() {}
}
public class FrameOptionsSpec {
public void mode(XFrameOptionsHttpHeadersWriter.Mode mode) {
frameOptions.setMode(mode);
}
public void disable() {
writers.remove(frameOptions);
}
private FrameOptionsSpec() {}
}
public class HstsSpec {
public void maxAge(Duration maxAge) {
hsts.setMaxAge(maxAge);
}
public void includeSubdomains(boolean includeSubDomains) {
hsts.setIncludeSubDomains(includeSubDomains);
}
public void disable() {
writers.remove(hsts);
}
private HstsSpec() {}
}
public class XssProtectionSpec {
public void disable() {
writers.remove(xss);
}
private XssProtectionSpec() {}
}
private HeaderBuilder() {
this.writers = new ArrayList<>(
Arrays.asList(cacheControl, contentTypeOptions, hsts, frameOptions, xss));
}
}
}

View File

@ -42,7 +42,8 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
* @since 5.0
*/
public class HeaderBuilderTests {
HeaderBuilder headers = new HeaderBuilder();
HttpSecurity.HeaderBuilder headers = HttpSecurity.http().headers();
HttpHeaders expectedHeaders = new HttpHeaders();