From 5d05347e6156a967003cb2225585208a9dfb77c4 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 26 Sep 2017 12:40:39 -0700 Subject: [PATCH] Add auto-config and starter for reactive security Closes gh-9925 --- spring-boot-autoconfigure/pom.xml | 5 + ...iveAuthenticationManagerConfiguration.java | 64 ++++++++ .../ReactiveSecurityAutoConfiguration.java | 41 ++++++ .../WebfluxSecurityConfiguration.java | 38 +++++ .../main/resources/META-INF/spring.factories | 1 + ...eactiveSecurityAutoConfigurationTests.java | 139 ++++++++++++++++++ spring-boot-dependencies/pom.xml | 5 + spring-boot-samples/pom.xml | 1 + .../spring-boot-sample-secure-webflux/pom.xml | 64 ++++++++ .../sample/secure/webflux/EchoHandler.java | 32 ++++ .../SampleSecureWebFluxApplication.java | 50 +++++++ .../secure/webflux/WelcomeController.java | 32 ++++ .../src/main/resources/application.properties | 0 .../SampleSecureWebFluxApplicationTests.java | 77 ++++++++++ spring-boot-starters/pom.xml | 1 + .../pom.xml | 50 +++++++ .../main/resources/META-INF/spring.provides | 1 + 17 files changed, 601 insertions(+) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveAuthenticationManagerConfiguration.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/WebfluxSecurityConfiguration.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java create mode 100644 spring-boot-samples/spring-boot-sample-secure-webflux/pom.xml create mode 100644 spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/EchoHandler.java create mode 100644 spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/SampleSecureWebFluxApplication.java create mode 100644 spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/WelcomeController.java create mode 100644 spring-boot-samples/spring-boot-sample-secure-webflux/src/main/resources/application.properties create mode 100644 spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxApplicationTests.java create mode 100644 spring-boot-starters/spring-boot-starter-security-reactive/pom.xml create mode 100644 spring-boot-starters/spring-boot-starter-security-reactive/src/main/resources/META-INF/spring.provides diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml index 070a4ad44b..a8ce696c03 100755 --- a/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-autoconfigure/pom.xml @@ -527,6 +527,11 @@ spring-security-data true + + org.springframework.security + spring-security-webflux + true + org.springframework.session spring-session-core diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveAuthenticationManagerConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveAuthenticationManagerConfiguration.java new file mode 100644 index 0000000000..650b2f7f5a --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveAuthenticationManagerConfiguration.java @@ -0,0 +1,64 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.reactive; + +import java.util.UUID; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.ReactiveAuthenticationManager; +import org.springframework.security.core.userdetails.MapUserDetailsRepository; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsRepository; + +/** + * Default user {@link Configuration} for a reactive web application. + * Configures a {@link UserDetailsRepository} with a default user and generated password. + * This backs-off completely if there is a bean of type {@link UserDetailsRepository} + * or {@link ReactiveAuthenticationManager}. + * + * @author Madhura Bhave + * @since 2.0.0 + */ +@Configuration +@ConditionalOnClass({ReactiveAuthenticationManager.class}) +@ConditionalOnMissingBean({ReactiveAuthenticationManager.class, UserDetailsRepository.class }) +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) +public class ReactiveAuthenticationManagerConfiguration { + + private static final Log logger = LogFactory + .getLog(ReactiveAuthenticationManagerConfiguration.class); + + @Bean + public MapUserDetailsRepository userDetailsRepository() { + String password = UUID.randomUUID().toString(); + logger.info( + String.format("%n%nUsing default security password: %s%n", password)); + UserDetails user = User.withUsername("user") + .password(password) + .roles() + .build(); + return new MapUserDetailsRepository(user); + } +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java new file mode 100644 index 0000000000..f7cf2cc3f9 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.reactive; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.web.reactive.result.method.annotation.AuthenticationPrincipalArgumentResolver; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Security in a + * reactive application. This auto-configuration adds {@link EnableWebFluxSecurity} + * and delegates to Spring Security's content-negotiation mechanism for authentication. + * In a webapp this configuration also secures all web endpoints. + * + * @author Madhura Bhave + * @since 2.0.0 + */ +@Configuration +@ConditionalOnClass({EnableWebFluxSecurity.class, AuthenticationPrincipalArgumentResolver.class}) +@Import({ WebfluxSecurityConfiguration.class, + ReactiveAuthenticationManagerConfiguration.class }) +public class ReactiveSecurityAutoConfiguration { + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/WebfluxSecurityConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/WebfluxSecurityConfiguration.java new file mode 100644 index 0000000000..8e0f7b1afe --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/WebfluxSecurityConfiguration.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.reactive; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration; + +/** + * Switches on {@link EnableWebFluxSecurity} for a reactive web application + * if this annotation has not been added by the user. + * + * @author Madhura Bhave + * @since 2.0.0 + */ +@ConditionalOnClass(EnableWebFluxSecurity.class) +@ConditionalOnMissingBean(WebFluxSecurityConfiguration.class) +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) +@EnableWebFluxSecurity +public class WebfluxSecurityConfiguration { + +} diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index dc62226cd2..6d6a28959a 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -99,6 +99,7 @@ org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\ +org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\ diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java new file mode 100644 index 0000000000..b875e214b4 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java @@ -0,0 +1,139 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.reactive; + +import org.junit.Test; +import reactor.core.publisher.Mono; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.web.reactive.MockReactiveWebServerFactory; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext; +import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.server.reactive.HttpHandler; +import org.springframework.security.authentication.ReactiveAuthenticationManager; +import org.springframework.security.config.annotation.web.reactive.HttpSecurityConfiguration; +import org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.MapUserDetailsRepository; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsRepository; +import org.springframework.security.web.server.WebFilterChainFilter; +import org.springframework.web.reactive.config.EnableWebFlux; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ReactiveSecurityAutoConfiguration}. + * + * @author Madhura Bhave + */ +public class ReactiveSecurityAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner(ReactiveWebServerApplicationContext::new); + + @Test + public void enablesWebFluxSecurity() { + this.contextRunner.withUserConfiguration(TestConfig.class) + .withConfiguration(AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) + .run(context -> { + assertThat(context).getBean(HttpSecurityConfiguration.class).isNotNull(); + assertThat(context).getBean(WebFluxSecurityConfiguration.class).isNotNull(); + assertThat(context).getBean(WebFilterChainFilter.class).isNotNull(); + }); + } + + @Test + public void configuresADefaultUser() { + this.contextRunner.withUserConfiguration(TestConfig.class) + .withConfiguration(AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) + .run(context -> { + UserDetailsRepository userDetailsRepository = context.getBean(UserDetailsRepository.class); + assertThat(userDetailsRepository.findByUsername("user").block()).isNotNull(); + }); + } + + @Test + public void doesNotConfigureDefaultUserIfUserDetailsRepositoryAvailable() { + this.contextRunner.withUserConfiguration(UserConfig.class, TestConfig.class) + .withConfiguration(AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) + .run(context -> { + UserDetailsRepository userDetailsRepository = context.getBean(UserDetailsRepository.class); + assertThat(userDetailsRepository.findByUsername("user").block()).isNull(); + assertThat(userDetailsRepository.findByUsername("foo").block()).isNotNull(); + assertThat(userDetailsRepository.findByUsername("admin").block()).isNotNull(); + }); + } + + @Test + public void doesNotConfigureDefaultUserIfAuthenticationManagerAvailable() { + this.contextRunner.withUserConfiguration(AuthenticationManagerConfig.class, TestConfig.class) + .withConfiguration(AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) + .run(context -> { + assertThat(context).getBean(UserDetailsRepository.class).isNull(); + }); + } + + @Configuration + @EnableWebFlux + static class TestConfig { + + @Bean + public HttpHandler httpHandler(ApplicationContext applicationContext) { + return WebHttpHandlerBuilder.applicationContext(applicationContext).build(); + } + + @Bean + public ReactiveWebServerFactory reactiveWebServerFactory() { + return new MockReactiveWebServerFactory(); + } + + } + + @Configuration + static class UserConfig { + + @Bean + public MapUserDetailsRepository userDetailsRepository() { + UserDetails foo = User.withUsername("foo").password("foo").roles("USER").build(); + UserDetails admin = User.withUsername("admin").password("admin").roles("USER", "ADMIN").build(); + return new MapUserDetailsRepository(foo, admin); + } + + } + + @Configuration + static class AuthenticationManagerConfig { + + @Bean + public ReactiveAuthenticationManager reactiveAuthenticationManager() { + return new ReactiveAuthenticationManager() { + @Override + public Mono authenticate(Authentication authentication) { + return null; + } + }; + } + + } + +} diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 78d710678e..b510c7e6a0 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -506,6 +506,11 @@ spring-boot-starter-security 2.0.0.BUILD-SNAPSHOT + + org.springframework.boot + spring-boot-starter-security-reactive + 2.0.0.BUILD-SNAPSHOT + org.springframework.boot spring-boot-starter-social-facebook diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 4c652f926e..e29d7b0207 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -67,6 +67,7 @@ spring-boot-sample-property-validation spring-boot-sample-quartz spring-boot-sample-secure + spring-boot-sample-secure-webflux spring-boot-sample-servlet spring-boot-sample-session spring-boot-sample-simple diff --git a/spring-boot-samples/spring-boot-sample-secure-webflux/pom.xml b/spring-boot-samples/spring-boot-sample-secure-webflux/pom.xml new file mode 100644 index 0000000000..d1681faaeb --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-secure-webflux/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + 2.0.0.BUILD-SNAPSHOT + + spring-boot-sample-secure-webflux + Spring Boot Secure WebFlux Sample + Spring Boot Secure WebFlux Sample + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + / + + + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-security-reactive + + + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + generate build info + + build-info + + + + + + + diff --git a/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/EchoHandler.java b/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/EchoHandler.java new file mode 100644 index 0000000000..62f53e2e01 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/EchoHandler.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012-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 sample.secure.webflux; + +import reactor.core.publisher.Mono; + +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; + +@Component +public class EchoHandler { + + public Mono echo(ServerRequest request) { + return ServerResponse.ok().body(request.bodyToMono(String.class), String.class); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/SampleSecureWebFluxApplication.java b/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/SampleSecureWebFluxApplication.java new file mode 100644 index 0000000000..2da5698fe2 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/SampleSecureWebFluxApplication.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-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 sample.secure.webflux; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.security.core.userdetails.MapUserDetailsRepository; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsRepository; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerResponse; + +import static org.springframework.web.reactive.function.server.RequestPredicates.POST; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; + +@SpringBootApplication +public class SampleSecureWebFluxApplication { + + public static void main(String[] args) throws Exception { + SpringApplication.run(SampleSecureWebFluxApplication.class); + } + + @Bean + public RouterFunction monoRouterFunction(EchoHandler echoHandler) { + return route(POST("/echo"), echoHandler::echo); + } + + @Bean + public UserDetailsRepository userDetailsRepository() { + UserDetails user = User.withUsername("foo").password("password").roles("USER").build(); + return new MapUserDetailsRepository(user); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/WelcomeController.java b/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/WelcomeController.java new file mode 100644 index 0000000000..b5a14ad3b0 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/java/sample/secure/webflux/WelcomeController.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012-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 sample.secure.webflux; + +import java.security.Principal; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class WelcomeController { + + @GetMapping("/") + public String welcome(Principal principal) { + return "Hello " + principal.getName(); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-secure-webflux/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxApplicationTests.java b/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxApplicationTests.java new file mode 100644 index 0000000000..4ff0f3a442 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxApplicationTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2012-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 sample.secure.webflux; + +import java.util.Base64; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; + +/** + * Integration tests for a secure reactive application. + * + * @author Madhura Bhave + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@DirtiesContext +public class SampleSecureWebFluxApplicationTests { + + @Autowired + private WebTestClient webClient; + + @Test + public void userDefinedMappingsSecureByDefault() { + this.webClient.get().uri("/").accept(MediaType.APPLICATION_JSON).exchange() + .expectStatus().isEqualTo(HttpStatus.UNAUTHORIZED); + } + + @Test + public void actuatorsSecureByDefault() { + this.webClient.get().uri("/application/status").accept(MediaType.APPLICATION_JSON) + .exchange().expectStatus().isUnauthorized(); + } + + @Test + public void userDefinedMappingsAccessibleOnLogin() { + this.webClient.get().uri("/").accept(MediaType.APPLICATION_JSON) + .header("Authorization", "basic " + getBasicAuth()) + .exchange() + .expectBody(String.class).isEqualTo("Hello foo"); + } + + @Test + public void actuatorsAccessibleOnLogin() { + this.webClient.get().uri("/application/status").accept(MediaType.APPLICATION_JSON) + .header("Authorization", "basic " + getBasicAuth()) + .exchange() + .expectBody(String.class).isEqualTo("{\"status\":\"UP\"}"); + } + + private String getBasicAuth() { + return new String(Base64.getEncoder().encode(("foo:password").getBytes())); + } + +} \ No newline at end of file diff --git a/spring-boot-starters/pom.xml b/spring-boot-starters/pom.xml index 59821bbf52..c60fb8c16b 100644 --- a/spring-boot-starters/pom.xml +++ b/spring-boot-starters/pom.xml @@ -63,6 +63,7 @@ spring-boot-starter-quartz spring-boot-starter-reactor-netty spring-boot-starter-security + spring-boot-starter-security-reactive spring-boot-starter-social-facebook spring-boot-starter-social-twitter spring-boot-starter-social-linkedin diff --git a/spring-boot-starters/spring-boot-starter-security-reactive/pom.xml b/spring-boot-starters/spring-boot-starter-security-reactive/pom.xml new file mode 100644 index 0000000000..e6b797b7f0 --- /dev/null +++ b/spring-boot-starters/spring-boot-starter-security-reactive/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starters + 2.0.0.BUILD-SNAPSHOT + + spring-boot-starter-security-reactive + Spring Boot Security Reactive Starter + Starter for using reactive Spring Security + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.boot + spring-boot-starter + + + org.springframework + spring-aop + + + org.springframework.security + spring-security-config + + + aopalliance + aopalliance + + + + + org.springframework.security + spring-security-webflux + + + aopalliance + aopalliance + + + + + diff --git a/spring-boot-starters/spring-boot-starter-security-reactive/src/main/resources/META-INF/spring.provides b/spring-boot-starters/spring-boot-starter-security-reactive/src/main/resources/META-INF/spring.provides new file mode 100644 index 0000000000..5001b7f780 --- /dev/null +++ b/spring-boot-starters/spring-boot-starter-security-reactive/src/main/resources/META-INF/spring.provides @@ -0,0 +1 @@ +provides: spring-security-webflux,spring-security-config \ No newline at end of file