From 731b746917a02efe10c7a193fb7ea3f6c1632723 Mon Sep 17 00:00:00 2001 From: Illia Chtchoma Date: Tue, 17 Sep 2019 17:03:42 +0200 Subject: [PATCH 1/8] Spring Boot Admin with OAuth2 sample implementation --- spring-boot-admin-samples/pom.xml | 1 + .../docker-compose.yml | 35 +++++ .../spring-boot-admin-sample-oauth2/pom.xml | 55 ++++++++ .../Dockerfile | 11 ++ .../pom.xml | 80 +++++++++++ ...BootAdminOAuth2AdminServerApplication.java | 49 +++++++ ...swordGrantTypeContextAttributesMapper.java | 47 +++++++ .../config/WebSecurityConfiguration.java | 80 +++++++++++ .../src/main/resources/application.yml | 21 +++ .../SpringBootAdminServerIntegrationTest.java | 57 ++++++++ .../test/resources/__files/oauth_token.json | 7 + .../wait-for.sh | 79 +++++++++++ .../Dockerfile | 7 + .../pom.xml | 71 ++++++++++ ...nOAuth2AuthorizationServerApplication.java | 29 ++++ .../AuthorizationServerConfiguration.java | 133 ++++++++++++++++++ .../config/WebSecurityConfiguration.java | 37 +++++ .../oauth2/web/WellKnownController.java | 46 ++++++ .../src/main/resources/application.yml | 6 + .../AuthorizationServerIntegrationTest.java | 80 +++++++++++ .../Dockerfile | 11 ++ .../pom.xml | 88 ++++++++++++ ...tAdminOAuth2ResourceServerApplication.java | 29 ++++ .../config/WebSecurityConfiguration.java | 38 +++++ .../sample/oauth2/web/IndexController.java | 34 +++++ .../src/main/resources/application.yml | 15 ++ .../oauth2/ResourceServerIntegrationTest.java | 58 ++++++++ .../src/test/resources/application-test.yml | 4 + .../src/test/resources/jwks.json | 9 ++ .../wait-for.sh | 79 +++++++++++ .../config/AdminServerAutoConfiguration.java | 4 +- .../domain/entities/InstanceRepository.java | 4 +- .../eventstore/ConcurrentMapEventStore.java | 8 +- 33 files changed, 1304 insertions(+), 8 deletions(-) create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/pom.xml create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/PasswordGrantTypeContextAttributesMapper.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/oauth_token.json create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/wait-for.sh create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/pom.xml create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AuthorizationServerApplication.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthorizationServerConfiguration.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/WellKnownController.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/test/java/de/codecentric/boot/admin/sample/oauth2/AuthorizationServerIntegrationTest.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2ResourceServerApplication.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/IndexController.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/java/de/codecentric/boot/admin/sample/oauth2/ResourceServerIntegrationTest.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/application-test.yml create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/jwks.json create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/wait-for.sh diff --git a/spring-boot-admin-samples/pom.xml b/spring-boot-admin-samples/pom.xml index cf0fdda2aa7..3d5e6c6f7b6 100644 --- a/spring-boot-admin-samples/pom.xml +++ b/spring-boot-admin-samples/pom.xml @@ -34,6 +34,7 @@ spring-boot-admin-sample-war spring-boot-admin-sample-hazelcast spring-boot-admin-sample-custom-ui + spring-boot-admin-sample-oauth2 diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml new file mode 100644 index 00000000000..2e9e07c3b6e --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml @@ -0,0 +1,35 @@ +version: '3' + +services: + authorization-server: + build: + context: ./spring-boot-admin-sample-oauth2-authorization + container_name: sba-oauth2-auth + ports: + - 8081:8081 + + admin-server: + build: + context: ./spring-boot-admin-sample-oauth2-admin + container_name: sba-oauth2-admin + environment: + spring.security.oauth2.client.provider.my-provider.token-uri: http://authorization-server:8081/oauth/token + depends_on: + - authorization-server + command: ["./wait-for.sh authorization-server:8081 --timeout=120 -- java -jar app.jar"] + ports: + - 8080:8080 + + resource-server: + build: + context: ./spring-boot-admin-sample-oauth2-resource + container_name: sba-oauth2-resource + environment: + spring.boot.admin.client.url: http://admin-server:8080 + spring.security.oauth2.resourceserver.jwt.jwk-set-uri: http://authorization-server:8081/.well-known/jwks.json + depends_on: + - authorization-server + - admin-server + command: ["./wait-for.sh admin-server:8080 --timeout=120 -- java -jar app.jar"] + ports: + - 8082:8082 \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml new file mode 100644 index 00000000000..691a0af3644 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml @@ -0,0 +1,55 @@ + + + + + 4.0.0 + spring-boot-admin-sample-oauth2 + pom + Spring Boot Admin Sample OAuth2 + Spring Boot Admin Sample OAuth2 + + de.codecentric + spring-boot-admin-samples + ${revision} + .. + + + spring-boot-admin-sample-oauth2-admin + spring-boot-admin-sample-oauth2-authorization + spring-boot-admin-sample-oauth2-resource + + + 7.8 + 2.1.8.RELEASE + + + + + org.springframework.security.oauth.boot + spring-security-oauth2-autoconfigure + ${spring-security-oauth2-autoconfigure.version} + + + com.nimbusds + nimbus-jose-jwt + ${nimbus-jose-jwt.version} + + + + \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile new file mode 100644 index 00000000000..19a9fd1b14a --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile @@ -0,0 +1,11 @@ +FROM openjdk:8-jre-alpine + +COPY /target/spring-boot-admin-sample-oauth2-admin.jar app.jar + +EXPOSE 8080 + +# Add wait-for +COPY wait-for.sh wait-for.sh +RUN chmod +x wait-for.sh + +ENTRYPOINT ["/bin/sh", "-c"] \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/pom.xml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/pom.xml new file mode 100644 index 00000000000..05d1eba168b --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/pom.xml @@ -0,0 +1,80 @@ + + + + + 4.0.0 + spring-boot-admin-sample-oauth2-admin + Spring Boot Admin Sample OAuth2 - Spring Boot Admin + Spring Boot Admin Sample OAuth2 - Spring Boot Admin + + de.codecentric + spring-boot-admin-sample-oauth2 + ${revision} + .. + + + + org.springframework.boot + spring-boot-starter-web + + + de.codecentric + spring-boot-admin-starter-server + + + org.springframework.security + spring-security-config + + + org.springframework.security + spring-security-oauth2-client + + + org.springframework.boot + spring-boot-starter-test + test + + + com.github.tomakehurst + wiremock-jre8-standalone + test + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + de.codecentric.boot.admin.sample.oauth2.SpringBootAdminOAuth2AdminServerApplication + + + + + + \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java new file mode 100644 index 00000000000..822220e56fa --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2; + +import de.codecentric.boot.admin.server.config.EnableAdminServer; +import de.codecentric.boot.admin.server.web.client.HttpHeadersProvider; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpHeaders; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; +import org.springframework.security.oauth2.core.OAuth2AccessToken; + +@EnableAdminServer +@SpringBootApplication +public class SpringBootAdminOAuth2AdminServerApplication { + + private static final String AUTHORIZATION_HEADER = "Authorization"; + + public static void main(String[] args) { + SpringApplication.run(SpringBootAdminOAuth2AdminServerApplication.class, args); + } + + @Bean + public HttpHeadersProvider provider(@RegisteredOAuth2AuthorizedClient("my-client") OAuth2AuthorizedClient client) { + OAuth2AccessToken accessToken = client.getAccessToken(); + return instance -> { + HttpHeaders headers = new HttpHeaders(); + headers.set(AUTHORIZATION_HEADER, accessToken.getTokenType().getValue() + " " + accessToken.getTokenValue()); + return headers; + }; + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/PasswordGrantTypeContextAttributesMapper.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/PasswordGrantTypeContextAttributesMapper.java new file mode 100644 index 00000000000..462a9275d4b --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/PasswordGrantTypeContextAttributesMapper.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; + +import org.springframework.security.oauth2.client.OAuth2AuthorizationContext; +import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; +import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +public class PasswordGrantTypeContextAttributesMapper implements Function> { + + @Override + public Map apply(OAuth2AuthorizeRequest authorizeRequest) { + Map contextAttributes = new HashMap<>(); + String scope = authorizeRequest.getAttribute(OAuth2ParameterNames.SCOPE); + if (StringUtils.hasText(scope)) { + contextAttributes.put(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, + StringUtils.delimitedListToStringArray(scope, " ")); + } + contextAttributes.put( + OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, + authorizeRequest.getAttribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME)); + contextAttributes.put( + OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, + authorizeRequest.getAttribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME)); + return contextAttributes; + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java new file mode 100644 index 00000000000..bbca53b7a29 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; + +import static org.springframework.security.oauth2.client.OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME; +import static org.springframework.security.oauth2.client.OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME; + +@Configuration +@EnableWebSecurity +public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + // @formatter:off + httpSecurity + .csrf() + .disable() + .authorizeRequests() + .anyRequest().permitAll(); + // @formatter:on + } + + @Bean + public OAuth2AuthorizedClient authorizedClient(AuthorizedClientServiceOAuth2AuthorizedClientManager clientManager) { + OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("my-client") + .principal(new UsernamePasswordAuthenticationToken("subject", "password")) + .attribute(USERNAME_ATTRIBUTE_NAME, "subject") + .attribute(PASSWORD_ATTRIBUTE_NAME, "password") + .build(); + return clientManager.authorize(authorizeRequest); + } + + @Bean + public AuthorizedClientServiceOAuth2AuthorizedClientManager clientManager( + ClientRegistrationRepository clientRegistrationRepository, + OAuth2AuthorizedClientService authorizedClientService) { + + AuthorizedClientServiceOAuth2AuthorizedClientManager manager = + new AuthorizedClientServiceOAuth2AuthorizedClientManager( + clientRegistrationRepository, + authorizedClientService); + + manager.setAuthorizedClientProvider( + OAuth2AuthorizedClientProviderBuilder.builder() + .password() + .build()); + + manager.setContextAttributesMapper(new PasswordGrantTypeContextAttributesMapper()); + + return manager; + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml new file mode 100644 index 00000000000..579292c7c00 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml @@ -0,0 +1,21 @@ +server: + port: 8080 + +logging: + level: + org.springframework.web.client.RestTemplate: TRACE + +spring: + security: + oauth2: + client: + registration: + my-client: + client-id: reader + client-secret: secret + provider: my-provider + client-authentication-method: basic + authorization-grant-type: password + provider: + my-provider: + token-uri: http://localhost:8081/oauth/token \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java new file mode 100644 index 00000000000..f4ac7a5950e --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2; + +import com.github.tomakehurst.wiremock.WireMockServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; + +@SpringBootTest +class SpringBootAdminServerIntegrationTest { + + private static WireMockServer mockAuthorizationServer = new WireMockServer(options().port(8081)); + + @BeforeAll + static void beforeAll() { + mockAuthorizationServer.start(); + configureFor(mockAuthorizationServer.port()); + + stubFor(post("/oauth/token").willReturn( + aResponse() + .withHeader("Content-Type", "application/json") + .withBodyFile("oauth_token.json"))); + } + + @AfterAll + static void afterAll() { + mockAuthorizationServer.stop(); + } + + @Test + void should_load_context() { + + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/oauth_token.json b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/oauth_token.json new file mode 100644 index 00000000000..6f7d01b1a89 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/oauth_token.json @@ -0,0 +1,7 @@ +{ + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJtZXNzYWdlOndyaXRlIl0sImV4cCI6MTU2ODc1MzYyNSwianRpIjoiMmE5ZWUyMjMtYmEwMi00N2EwLWExMzUtMzk0MDcyNjMzMzVkIiwiY2xpZW50X2lkIjoid3JpdGVyIn0.BcghzN75YeXYBxLgkjHlH49kLErqZs2sL8CnT3p-S8fSwIObnmq0MioVdURj2-Q7nnV-gPlZsIScYOa2C5oG8UCqU9hJFqcjXoZ4FbMXrL0RgU5Kahok8nSkWCwx9ZKtjiPDFkZ6LXE-Rf0v3JbaaaYGfqjaFNmo8Rj-nVGerp0yi1ALwlJmTEJaaT2c6VqufOpecHj6xng3I99bSYsREp7FKQY-BW1gnkLQT1u8ooN8EYmXcpSnruUTFTwpmdwcNG9MMGOn2Zr3P_1eb-qI3LLPfh5rVcJric-yz8dG5mQVBPDMGjXGnw6vC5baKByK-RfiUcUEwZOthwqIJLo1Yw", + "token_type": "bearer", + "expires_in": 35999, + "scope": "message:write", + "jti": "2a9ee223-ba02-47a0-a135-39407263335d" +} \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/wait-for.sh b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/wait-for.sh new file mode 100644 index 00000000000..ddfc39ecd18 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/wait-for.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +TIMEOUT=15 +QUIET=0 + +echoerr() { + if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi +} + +usage() { + exitcode="$1" + cat << USAGE >&2 +Usage: + $cmdname host:port [-t timeout] [-- command args] + -q | --quiet Do not output any status messages + -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit "$exitcode" +} + +wait_for() { + for i in `seq $TIMEOUT` ; do + nc -z "$HOST" "$PORT" > /dev/null 2>&1 + + result=$? + if [ $result -eq 0 ] ; then + if [ $# -gt 0 ] ; then + exec "$@" + fi + exit 0 + fi + sleep 1 + done + echo "Operation timed out" >&2 + exit 1 +} + +while [ $# -gt 0 ] +do + case "$1" in + *:* ) + HOST=$(printf "%s\n" "$1"| cut -d : -f 1) + PORT=$(printf "%s\n" "$1"| cut -d : -f 2) + shift 1 + ;; + -q | --quiet) + QUIET=1 + shift 1 + ;; + -t) + TIMEOUT="$2" + if [ "$TIMEOUT" = "" ]; then break; fi + shift 2 + ;; + --timeout=*) + TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + break + ;; + --help) + usage 0 + ;; + *) + echoerr "Unknown argument: $1" + usage 1 + ;; + esac +done + +if [ "$HOST" = "" -o "$PORT" = "" ]; then + echoerr "Error: you need to provide a host and port to test." + usage 2 +fi + +wait_for "$@" diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile new file mode 100644 index 00000000000..9a3fc18c762 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile @@ -0,0 +1,7 @@ +FROM openjdk:8-jre-alpine + +COPY /target/spring-boot-admin-sample-oauth2-authorization.jar app.jar + +EXPOSE 8081 + +ENTRYPOINT ["java","-jar","app.jar"] \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/pom.xml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/pom.xml new file mode 100644 index 00000000000..d235cc443cc --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/pom.xml @@ -0,0 +1,71 @@ + + + + + 4.0.0 + spring-boot-admin-sample-oauth2-authorization + Spring Boot Admin Sample OAuth2 - Authorization Server + Spring Boot Admin Sample OAuth2 - Authorization Server + + de.codecentric + spring-boot-admin-sample-oauth2 + ${revision} + .. + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.security.oauth.boot + spring-security-oauth2-autoconfigure + + + com.nimbusds + nimbus-jose-jwt + + + org.springframework.boot + spring-boot-starter-test + test + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + de.codecentric.boot.admin.sample.oauth2.SpringBootAdminOAuth2AuthorizationServerApplication + + + + + + \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AuthorizationServerApplication.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AuthorizationServerApplication.java new file mode 100644 index 00000000000..ff39f0771c6 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AuthorizationServerApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootAdminOAuth2AuthorizationServerApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootAdminOAuth2AuthorizationServerApplication.class, args); + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthorizationServerConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthorizationServerConfiguration.java new file mode 100644 index 00000000000..c4cf23b89c1 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthorizationServerConfiguration.java @@ -0,0 +1,133 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; +import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; +import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.util.LinkedHashMap; +import java.util.Map; + +@Configuration +@EnableAuthorizationServer +public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { + + private static final String[] AUTHORIZED_GRANT_TYPES = {"password"}; + + private final AuthenticationConfiguration authenticationConfiguration; + + public AuthorizationServerConfiguration(AuthenticationConfiguration authenticationConfiguration) { + this.authenticationConfiguration = authenticationConfiguration; + } + + @Override + public void configure(ClientDetailsServiceConfigurer clients) throws Exception { + // @formatter:off + clients.inMemory() + .withClient("reader") + .authorizedGrantTypes(AUTHORIZED_GRANT_TYPES) + .secret("{noop}secret") + .scopes("message:read") + .accessTokenValiditySeconds(36_000) + .and() + .withClient("writer") + .authorizedGrantTypes(AUTHORIZED_GRANT_TYPES) + .secret("{noop}secret") + .scopes("message:write") + .accessTokenValiditySeconds(36_000); + // @formatter:on + } + + @Override + public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { + endpoints + .authenticationManager(this.authenticationConfiguration.getAuthenticationManager()) + .accessTokenConverter(accessTokenConverter()) + .tokenStore(tokenStore()); + } + + @Bean + public UserDetailsService userDetailsService() { + return new InMemoryUserDetailsManager(User + .withUsername("subject") + .password("{noop}password") + .roles("USER") + .build()); + } + + @Bean + public TokenStore tokenStore() { + return new JwtTokenStore(accessTokenConverter()); + } + + @Bean + public JwtAccessTokenConverter accessTokenConverter() { + JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); + converter.setKeyPair(keyPair()); + + DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); + accessTokenConverter.setUserTokenConverter(authenticationConverter()); + converter.setAccessTokenConverter(accessTokenConverter); + + return converter; + } + + @Bean + public KeyPair keyPair() { + try { + KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); + generator.initialize(2048); + return generator.generateKeyPair(); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException(e); + } + } + + private UserAuthenticationConverter authenticationConverter() { + return new DefaultUserAuthenticationConverter() { + @Override + public Map convertUserAuthentication(Authentication authentication) { + Map response = new LinkedHashMap<>(); + response.put("sub", authentication.getName()); + if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) { + response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities())); + } + return response; + } + }; + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java new file mode 100644 index 00000000000..950478df0f4 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + // @formatter:off + httpSecurity + .csrf() + .disable() + .authorizeRequests() + .antMatchers("/.well-known/jwks.json").permitAll(); + // @formatter:on + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/WellKnownController.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/WellKnownController.java new file mode 100644 index 00000000000..08f39963bcb --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/WellKnownController.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.web; + +import com.nimbusds.jose.jwk.JWKSet; +import com.nimbusds.jose.jwk.RSAKey; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.security.KeyPair; +import java.security.interfaces.RSAPublicKey; +import java.util.Map; + +@RestController +@RequestMapping("/.well-known") +public class WellKnownController { + + private final KeyPair keyPair; + + public WellKnownController(KeyPair keyPair) { + this.keyPair = keyPair; + } + + @GetMapping("/jwks.json") + public Map getJwkSet() { + RSAPublicKey publicKey = (RSAPublicKey) this.keyPair.getPublic(); + RSAKey key = new RSAKey.Builder(publicKey).build(); + return new JWKSet(key).toJSONObject(); + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml new file mode 100644 index 00000000000..6af3bf485b6 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml @@ -0,0 +1,6 @@ +server: + port: 8081 + +logging: + level: + org.springframework.security.web.authentication.www.BasicAuthenticationFilter: DEBUG \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/test/java/de/codecentric/boot/admin/sample/oauth2/AuthorizationServerIntegrationTest.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/test/java/de/codecentric/boot/admin/sample/oauth2/AuthorizationServerIntegrationTest.java new file mode 100644 index 00000000000..b2eeb95ae82 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/test/java/de/codecentric/boot/admin/sample/oauth2/AuthorizationServerIntegrationTest.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import static org.hamcrest.Matchers.both; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.lessThan; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +class AuthorizationServerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Test + void should_authenticate_and_return_token() throws Exception { + // given + String grantType = "password"; + String username = "subject"; + String password = "password"; + + // when + ResultActions resultActions = mockMvc.perform(post("/oauth/token") + .param("grant_type", grantType) + .param("username", username) + .param("password", password) + .header("Authorization", "Basic cmVhZGVyOnNlY3JldA==")); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.access_token").isNotEmpty()) + .andExpect(jsonPath("$.token_type").value("bearer")) + .andExpect(jsonPath("$.expires_in").value(both(lessThan(36000)).and(greaterThan(35990)))) + .andExpect(jsonPath("$.scope").value("message:read")) + .andExpect(jsonPath("$.jti").isNotEmpty()); + } + + @Test + void should_return_well_known_jwks() throws Exception { + // when + ResultActions resultActions = mockMvc.perform(get("/.well-known/jwks.json")); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.keys").value(hasSize(1))) + .andExpect(jsonPath("$.keys[0].kty").value("RSA")) + .andExpect(jsonPath("$.keys[0].e").value("AQAB")) + .andExpect(jsonPath("$.keys[0].n").isNotEmpty()); + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile new file mode 100644 index 00000000000..b949b1555e1 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile @@ -0,0 +1,11 @@ +FROM openjdk:8-jre-alpine + +COPY /target/spring-boot-admin-sample-oauth2-resource.jar app.jar + +EXPOSE 8082 + +# Add wait-for +COPY wait-for.sh wait-for.sh +RUN chmod +x wait-for.sh + +ENTRYPOINT ["/bin/sh", "-c"] \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml new file mode 100644 index 00000000000..3272ea122b4 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml @@ -0,0 +1,88 @@ + + + + + 4.0.0 + spring-boot-admin-sample-oauth2-resource + Spring Boot Admin Sample OAuth2 - Resource Server + Spring Boot Admin Sample OAuth2 - Resource Server + + de.codecentric + spring-boot-admin-sample-oauth2 + ${revision} + .. + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.security + spring-security-config + + + org.springframework.security + spring-security-oauth2-resource-server + + + org.springframework.security + spring-security-oauth2-jose + + + de.codecentric + spring-boot-admin-starter-client + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + de.codecentric.boot.admin.sample.oauth2.SpringBootAdminOAuth2ResourceServerApplication + + + + + + \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2ResourceServerApplication.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2ResourceServerApplication.java new file mode 100644 index 00000000000..cd6b562d390 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2ResourceServerApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootAdminOAuth2ResourceServerApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootAdminOAuth2ResourceServerApplication.class, args); + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java new file mode 100644 index 00000000000..2400ea19dcf --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; + +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + // @formatter:off + httpSecurity + .authorizeRequests() + .anyRequest().authenticated() + .and() + .oauth2ResourceServer() + .jwt(); + // @formatter:off + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/IndexController.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/IndexController.java new file mode 100644 index 00000000000..1d382188746 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/IndexController.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.web; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/") +public class IndexController { + + @GetMapping + public String index(@AuthenticationPrincipal Jwt jwt) { + return String.format("Hello, %s!", jwt.getSubject()); + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml new file mode 100644 index 00000000000..459a95b29c1 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml @@ -0,0 +1,15 @@ +server: + port: 8082 + +spring: + application: + name: resource-service + boot: + admin: + client: + url: http://localhost:8080 + security: + oauth2: + resourceserver: + jwt: + jwk-set-uri: http://localhost:8081/.well-known/jwks.json \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/java/de/codecentric/boot/admin/sample/oauth2/ResourceServerIntegrationTest.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/java/de/codecentric/boot/admin/sample/oauth2/ResourceServerIntegrationTest.java new file mode 100644 index 00000000000..7c36731985b --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/java/de/codecentric/boot/admin/sample/oauth2/ResourceServerIntegrationTest.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +class ResourceServerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Test + void should_not_be_able_access_actuator_endpoint_without_authentication() throws Exception { + // when + ResultActions resultActions = mockMvc.perform(get("/actuator/health")); + + // then + resultActions + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockUser + void should_be_able_access_actuator_endpoint_with_authentication() throws Exception { + // when + ResultActions resultActions = mockMvc.perform(get("/actuator/health")); + + // then + resultActions + .andExpect(status().isOk()); + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/application-test.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/application-test.yml new file mode 100644 index 00000000000..c97088775db --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/application-test.yml @@ -0,0 +1,4 @@ +spring: + autoconfigure: + exclude: + - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/jwks.json b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/jwks.json new file mode 100644 index 00000000000..e2b663eaccc --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/jwks.json @@ -0,0 +1,9 @@ +{ + "keys":[ + { + "kty":"RSA", + "e":"AQAB", + "n":"jvBtqsGCOmnYzwe_-HvgOqlKk6HPiLEzS6uCCcnVkFXrhnkPMZ-uQXTR0u-7ZklF0XC7-AMW8FQDOJS1T7IyJpCyeU4lS8RIf_Z8RX51gPGnQWkRvNw61RfiSuSA45LR5NrFTAAGoXUca_lZnbqnl0td-6hBDVeHYkkpAsSck1NPhlcsn-Pvc2Vleui_Iy1U2mzZCM1Vx6Dy7x9IeP_rTNtDhULDMFbB_JYs-Dg6Zd5Ounb3mP57tBGhLYN7zJkN1AAaBYkElsc4GUsGsUWKqgteQSXZorpf6HdSJsQMZBDd7xG8zDDJ28hGjJSgWBndRGSzQEYU09Xbtzk-8khPuw" + } + ] +} \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/wait-for.sh b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/wait-for.sh new file mode 100644 index 00000000000..ddfc39ecd18 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/wait-for.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +TIMEOUT=15 +QUIET=0 + +echoerr() { + if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi +} + +usage() { + exitcode="$1" + cat << USAGE >&2 +Usage: + $cmdname host:port [-t timeout] [-- command args] + -q | --quiet Do not output any status messages + -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit "$exitcode" +} + +wait_for() { + for i in `seq $TIMEOUT` ; do + nc -z "$HOST" "$PORT" > /dev/null 2>&1 + + result=$? + if [ $result -eq 0 ] ; then + if [ $# -gt 0 ] ; then + exec "$@" + fi + exit 0 + fi + sleep 1 + done + echo "Operation timed out" >&2 + exit 1 +} + +while [ $# -gt 0 ] +do + case "$1" in + *:* ) + HOST=$(printf "%s\n" "$1"| cut -d : -f 1) + PORT=$(printf "%s\n" "$1"| cut -d : -f 2) + shift 1 + ;; + -q | --quiet) + QUIET=1 + shift 1 + ;; + -t) + TIMEOUT="$2" + if [ "$TIMEOUT" = "" ]; then break; fi + shift 2 + ;; + --timeout=*) + TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + break + ;; + --help) + usage 0 + ;; + *) + echoerr "Unknown argument: $1" + usage 1 + ;; + esac +done + +if [ "$HOST" = "" -o "$PORT" = "" ]; then + echoerr "Error: you need to provide a host and port to test." + usage 2 +fi + +wait_for "$@" diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/config/AdminServerAutoConfiguration.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/config/AdminServerAutoConfiguration.java index f54f18cf5f1..a389716399e 100644 --- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/config/AdminServerAutoConfiguration.java +++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/config/AdminServerAutoConfiguration.java @@ -82,8 +82,8 @@ public InstanceIdGenerator instanceIdGenerator() { @Bean @ConditionalOnMissingBean public StatusUpdater statusUpdater(InstanceRepository instanceRepository, - InstanceWebClient.Builder instanceWebClientBulder) { - return new StatusUpdater(instanceRepository, instanceWebClientBulder.build()); + InstanceWebClient.Builder instanceWebClientBuilder) { + return new StatusUpdater(instanceRepository, instanceWebClientBuilder.build()); } @Bean(initMethod = "start", destroyMethod = "stop") diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/domain/entities/InstanceRepository.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/domain/entities/InstanceRepository.java index 02ec5977e02..38b09609e08 100644 --- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/domain/entities/InstanceRepository.java +++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/domain/entities/InstanceRepository.java @@ -61,7 +61,7 @@ public interface InstanceRepository { * * @param id Instance to update * @param remappingFunction function to apply - * @return the saved istance + * @return the saved instance */ Mono compute(InstanceId id, BiFunction> remappingFunction); @@ -71,7 +71,7 @@ public interface InstanceRepository { * * @param id Instance to update * @param remappingFunction function to apply - * @return the saved istance + * @return the saved instance */ Mono computeIfPresent(InstanceId id, BiFunction> remappingFunction); } diff --git a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/eventstore/ConcurrentMapEventStore.java b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/eventstore/ConcurrentMapEventStore.java index 5b4a0ed4bf8..231496809c3 100644 --- a/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/eventstore/ConcurrentMapEventStore.java +++ b/spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/eventstore/ConcurrentMapEventStore.java @@ -85,7 +85,7 @@ protected boolean doAppend(List events) { } List oldEvents = eventLog.computeIfAbsent(id, - (key) -> new ArrayList<>(maxLogSizePerAggregate + 1)); + key -> new ArrayList<>(maxLogSizePerAggregate + 1)); long lastVersion = getLastVersion(oldEvents); if (lastVersion >= events.get(0).getVersion()) { @@ -105,7 +105,7 @@ protected boolean doAppend(List events) { return true; } - log.debug("Unsuccessful attempot append the events {} ", events); + log.debug("Unsuccessful attempt append the events {} ", events); return false; } @@ -114,12 +114,12 @@ private void compact(List events) { Map, Optional> latestPerType = events.stream() .collect(groupingBy(InstanceEvent::getClass, reducing(latestEvent))); - events.removeIf((e) -> !Objects.equals(e, latestPerType.get(e.getClass()).orElse(null))); + events.removeIf(e -> !Objects.equals(e, latestPerType.get(e.getClass()).orElse(null))); } private OptimisticLockingException createOptimisticLockException(InstanceEvent event, long lastVersion) { return new OptimisticLockingException( - "Verison " + event.getVersion() + " was overtaken by " + lastVersion + " for " + event.getInstance()); + "Version " + event.getVersion() + " was overtaken by " + lastVersion + " for " + event.getInstance()); } protected static long getLastVersion(List events) { From 46e27674376299c62079fa29a8e2bd43c415938b Mon Sep 17 00:00:00 2001 From: Illia Chtchoma Date: Fri, 20 Sep 2019 14:51:02 +0200 Subject: [PATCH 2/8] Fixes after code review --- .../Dockerfile | 3 +- .../config/WebSecurityConfiguration.java | 43 ++++++++-- .../src/main/resources/application.yml | 3 + .../wait-for.sh | 79 ------------------- .../Dockerfile | 3 +- .../pom.xml | 12 +-- .../src/main/resources/application.yml | 10 ++- .../src/test/resources/application-test.yml | 4 - .../wait-for.sh | 79 ------------------- 9 files changed, 53 insertions(+), 183 deletions(-) delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/wait-for.sh delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/application-test.yml delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/wait-for.sh diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile index 19a9fd1b14a..1dc0dfc17a1 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile @@ -4,8 +4,7 @@ COPY /target/spring-boot-admin-sample-oauth2-admin.jar app.jar EXPOSE 8080 -# Add wait-for -COPY wait-for.sh wait-for.sh +RUN wget -O wait-for.sh "https://raw.githubusercontent.com/eficode/wait-for/master/wait-for" RUN chmod +x wait-for.sh ENTRYPOINT ["/bin/sh", "-c"] \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java index bbca53b7a29..7502d9ebb19 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java @@ -16,18 +16,19 @@ package de.codecentric.boot.admin.sample.oauth2.config; +import de.codecentric.boot.admin.server.config.AdminServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.oauth2.client.*; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; import static org.springframework.security.oauth2.client.OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME; import static org.springframework.security.oauth2.client.OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME; @@ -36,6 +37,15 @@ @EnableWebSecurity public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + private final Environment environment; + private final AdminServerProperties adminServerProperties; + + public WebSecurityConfiguration(Environment environment, + AdminServerProperties adminServerProperties) { + this.environment = environment; + this.adminServerProperties = adminServerProperties; + } + @Override protected void configure(HttpSecurity httpSecurity) throws Exception { // @formatter:off @@ -43,7 +53,18 @@ protected void configure(HttpSecurity httpSecurity) throws Exception { .csrf() .disable() .authorizeRequests() - .anyRequest().permitAll(); + .antMatchers(adminServerProperties.path("/assets/**")).permitAll() + .antMatchers(adminServerProperties.path("/login")).permitAll() + .antMatchers(adminServerProperties.path("/sw.js")).permitAll() + .anyRequest().authenticated() + .and() + .formLogin() + .loginPage(adminServerProperties.path("/login")) + .and() + .logout() + .logoutUrl(adminServerProperties.path("/logout")) + .and() + .httpBasic(); // @formatter:on } @@ -77,4 +98,14 @@ public AuthorizedClientServiceOAuth2AuthorizedClientManager clientManager( return manager; } + @Bean + @Override + public UserDetailsService userDetailsService() { + return new InMemoryUserDetailsManager(User + .withUsername(environment.getProperty("spring.security.user.name")) + .password("{noop}" + environment.getProperty("spring.security.user.password")) + .roles("USER") + .build()); + } + } diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml index 579292c7c00..8b876e2121c 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml @@ -7,6 +7,9 @@ logging: spring: security: + user: + name: sbadmin + password: pass oauth2: client: registration: diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/wait-for.sh b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/wait-for.sh deleted file mode 100644 index ddfc39ecd18..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/wait-for.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh - -TIMEOUT=15 -QUIET=0 - -echoerr() { - if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi -} - -usage() { - exitcode="$1" - cat << USAGE >&2 -Usage: - $cmdname host:port [-t timeout] [-- command args] - -q | --quiet Do not output any status messages - -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout - -- COMMAND ARGS Execute command with args after the test finishes -USAGE - exit "$exitcode" -} - -wait_for() { - for i in `seq $TIMEOUT` ; do - nc -z "$HOST" "$PORT" > /dev/null 2>&1 - - result=$? - if [ $result -eq 0 ] ; then - if [ $# -gt 0 ] ; then - exec "$@" - fi - exit 0 - fi - sleep 1 - done - echo "Operation timed out" >&2 - exit 1 -} - -while [ $# -gt 0 ] -do - case "$1" in - *:* ) - HOST=$(printf "%s\n" "$1"| cut -d : -f 1) - PORT=$(printf "%s\n" "$1"| cut -d : -f 2) - shift 1 - ;; - -q | --quiet) - QUIET=1 - shift 1 - ;; - -t) - TIMEOUT="$2" - if [ "$TIMEOUT" = "" ]; then break; fi - shift 2 - ;; - --timeout=*) - TIMEOUT="${1#*=}" - shift 1 - ;; - --) - shift - break - ;; - --help) - usage 0 - ;; - *) - echoerr "Unknown argument: $1" - usage 1 - ;; - esac -done - -if [ "$HOST" = "" -o "$PORT" = "" ]; then - echoerr "Error: you need to provide a host and port to test." - usage 2 -fi - -wait_for "$@" diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile index b949b1555e1..f4aac179d9e 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile @@ -4,8 +4,7 @@ COPY /target/spring-boot-admin-sample-oauth2-resource.jar app.jar EXPOSE 8082 -# Add wait-for -COPY wait-for.sh wait-for.sh +RUN wget -O wait-for.sh "https://raw.githubusercontent.com/eficode/wait-for/master/wait-for" RUN chmod +x wait-for.sh ENTRYPOINT ["/bin/sh", "-c"] \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml index 3272ea122b4..162c310e2f6 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml @@ -38,16 +38,8 @@ spring-boot-starter-actuator - org.springframework.security - spring-security-config - - - org.springframework.security - spring-security-oauth2-resource-server - - - org.springframework.security - spring-security-oauth2-jose + org.springframework.boot + spring-boot-starter-oauth2-resource-server de.codecentric diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml index 459a95b29c1..ca0177de314 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml @@ -8,8 +8,16 @@ spring: admin: client: url: http://localhost:8080 + username: sbadmin + password: pass security: oauth2: resourceserver: jwt: - jwk-set-uri: http://localhost:8081/.well-known/jwks.json \ No newline at end of file + jwk-set-uri: http://localhost:8081/.well-known/jwks.json + +management: + endpoints: + web: + exposure: + include: "*" \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/application-test.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/application-test.yml deleted file mode 100644 index c97088775db..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/application-test.yml +++ /dev/null @@ -1,4 +0,0 @@ -spring: - autoconfigure: - exclude: - - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/wait-for.sh b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/wait-for.sh deleted file mode 100644 index ddfc39ecd18..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/wait-for.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh - -TIMEOUT=15 -QUIET=0 - -echoerr() { - if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi -} - -usage() { - exitcode="$1" - cat << USAGE >&2 -Usage: - $cmdname host:port [-t timeout] [-- command args] - -q | --quiet Do not output any status messages - -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout - -- COMMAND ARGS Execute command with args after the test finishes -USAGE - exit "$exitcode" -} - -wait_for() { - for i in `seq $TIMEOUT` ; do - nc -z "$HOST" "$PORT" > /dev/null 2>&1 - - result=$? - if [ $result -eq 0 ] ; then - if [ $# -gt 0 ] ; then - exec "$@" - fi - exit 0 - fi - sleep 1 - done - echo "Operation timed out" >&2 - exit 1 -} - -while [ $# -gt 0 ] -do - case "$1" in - *:* ) - HOST=$(printf "%s\n" "$1"| cut -d : -f 1) - PORT=$(printf "%s\n" "$1"| cut -d : -f 2) - shift 1 - ;; - -q | --quiet) - QUIET=1 - shift 1 - ;; - -t) - TIMEOUT="$2" - if [ "$TIMEOUT" = "" ]; then break; fi - shift 2 - ;; - --timeout=*) - TIMEOUT="${1#*=}" - shift 1 - ;; - --) - shift - break - ;; - --help) - usage 0 - ;; - *) - echoerr "Unknown argument: $1" - usage 1 - ;; - esac -done - -if [ "$HOST" = "" -o "$PORT" = "" ]; then - echoerr "Error: you need to provide a host and port to test." - usage 2 -fi - -wait_for "$@" From 5ebfa45181dda3e3a8ee28179857240f31839123 Mon Sep 17 00:00:00 2001 From: Illia Chtchoma Date: Fri, 20 Sep 2019 22:59:44 +0200 Subject: [PATCH 3/8] Fixes after code review --- .../src/main/resources/application.yml | 4 ---- .../src/main/resources/application.yml | 6 +----- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml index 8b876e2121c..6ec2156db4b 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml @@ -1,10 +1,6 @@ server: port: 8080 -logging: - level: - org.springframework.web.client.RestTemplate: TRACE - spring: security: user: diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml index 6af3bf485b6..54b155fffd1 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml @@ -1,6 +1,2 @@ server: - port: 8081 - -logging: - level: - org.springframework.security.web.authentication.www.BasicAuthenticationFilter: DEBUG \ No newline at end of file + port: 8081 \ No newline at end of file From f5e95247b6d51e5e2e00ca8070144392cb1dc6f7 Mon Sep 17 00:00:00 2001 From: Illia Chtchoma Date: Fri, 20 Sep 2019 23:58:35 +0200 Subject: [PATCH 4/8] Authorization server re-implementation using Cloudfoundry UAA --- .../docker-compose.yml | 6 +- .../src/main/resources/application.yml | 9 +- .../SpringBootAdminServerIntegrationTest.java | 9 +- .../__files/access_token_response.json | 8 ++ .../test/resources/__files/oauth_token.json | 7 - .../Dockerfile | 15 +- .../config/uaa.yml | 108 ++++++++++++++ .../pom.xml | 41 +----- ...nOAuth2AuthorizationServerApplication.java | 29 ---- .../AuthorizationServerConfiguration.java | 133 ------------------ .../config/WebSecurityConfiguration.java | 37 ----- .../oauth2/web/WellKnownController.java | 46 ------ .../src/main/resources/application.yml | 2 - .../AuthorizationServerIntegrationTest.java | 80 ----------- .../src/main/resources/application.yml | 7 +- 15 files changed, 148 insertions(+), 389 deletions(-) create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/access_token_response.json delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/oauth_token.json create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/config/uaa.yml delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AuthorizationServerApplication.java delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthorizationServerConfiguration.java delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/WellKnownController.java delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/test/java/de/codecentric/boot/admin/sample/oauth2/AuthorizationServerIntegrationTest.java diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml index 2e9e07c3b6e..fd960035cfc 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml @@ -13,7 +13,8 @@ services: context: ./spring-boot-admin-sample-oauth2-admin container_name: sba-oauth2-admin environment: - spring.security.oauth2.client.provider.my-provider.token-uri: http://authorization-server:8081/oauth/token + cloudfoundry.uaa.host: authorization-server + cloudfoundry.uaa.port: 8081 depends_on: - authorization-server command: ["./wait-for.sh authorization-server:8081 --timeout=120 -- java -jar app.jar"] @@ -25,8 +26,9 @@ services: context: ./spring-boot-admin-sample-oauth2-resource container_name: sba-oauth2-resource environment: + cloudfoundry.uaa.host: authorization-server + cloudfoundry.uaa.port: 8081 spring.boot.admin.client.url: http://admin-server:8080 - spring.security.oauth2.resourceserver.jwt.jwk-set-uri: http://authorization-server:8081/.well-known/jwks.json depends_on: - authorization-server - admin-server diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml index 6ec2156db4b..c3fc169e66b 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml @@ -1,6 +1,11 @@ server: port: 8080 +cloudfoundry: + uaa: + host: localhost + port: 8081 + spring: security: user: @@ -10,11 +15,11 @@ spring: client: registration: my-client: - client-id: reader + client-id: admin client-secret: secret provider: my-provider client-authentication-method: basic authorization-grant-type: password provider: my-provider: - token-uri: http://localhost:8081/oauth/token \ No newline at end of file + token-uri: http://${cloudfoundry.uaa.host}:${cloudfoundry.uaa.port}/uaa/oauth/token \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java index f4ac7a5950e..c3eb36b3dc0 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java @@ -22,10 +22,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; -import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.*; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; @SpringBootTest @@ -38,10 +35,10 @@ static void beforeAll() { mockAuthorizationServer.start(); configureFor(mockAuthorizationServer.port()); - stubFor(post("/oauth/token").willReturn( + stubFor(post("/uaa/oauth/token").willReturn( aResponse() .withHeader("Content-Type", "application/json") - .withBodyFile("oauth_token.json"))); + .withBodyFile("access_token_response.json"))); } @AfterAll diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/access_token_response.json b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/access_token_response.json new file mode 100644 index 00000000000..5507a984d96 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/access_token_response.json @@ -0,0 +1,8 @@ +{ + "access_token": "eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0OjgwODAvdWFhL3Rva2VuX2tleXMiLCJraWQiOiJrZXktaWQtMSIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkMzg5NzBmNTc2MGU0NWRhOWExZTg5MjU0NDdlNzM5MSIsInN1YiI6IjJlOWQ5YzE1LTAyYmQtNGEyZi1iZmI2LWU5YTA3OTkwYzVjMSIsInNjb3BlIjpbIm9wZW5pZCJdLCJjbGllbnRfaWQiOiJhZG1pbiIsImNpZCI6ImFkbWluIiwiYXpwIjoiYWRtaW4iLCJncmFudF90eXBlIjoicGFzc3dvcmQiLCJ1c2VyX2lkIjoiMmU5ZDljMTUtMDJiZC00YTJmLWJmYjYtZTlhMDc5OTBjNWMxIiwib3JpZ2luIjoidWFhIiwidXNlcl9uYW1lIjoic3ViamVjdCIsImVtYWlsIjoic3ViamVjdEBsb2NhbGhvc3QiLCJhdXRoX3RpbWUiOjE1NjkwMTU2MjQsInJldl9zaWciOiJhNGExODY5IiwiaWF0IjoxNTY5MDE1NjI0LCJleHAiOjE1NjkwNTg4MjQsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MS91YWEvb2F1dGgvdG9rZW4iLCJ6aWQiOiJ1YWEiLCJhdWQiOlsib3BlbmlkIiwiYWRtaW4iXX0.VsYBQl8SF-TmST8NgqYUZviDS2K5LvD5vvofsMyV9Xql8ce5_Hv6Hvw7UDbjbv0K9sU9MRP_8URtZlaKMqdFnJut2WZW71Xx2paK8yegq8oUMbE5hUnRtsJ6LqDOlgV5M-Uucgwd-RyN3PZZ4ZWfGD3jne9F5fbqK4G_hBAwTleIjzZMflVBzSgFqWtiH5Uo_N3qfHfL2JTJCZG0Mb4xRmIRN0Ytn0sGCiDM3fJwFs-6dc0xhivQv4TzxmB_SVMW_DGnLSXyg-WJslQRV0sVvl6ywZxrDmnZdlNQzcLa7jQjDvLlROhi7E014-fqSLI3lV0vsbVOHnqNLJKI0YA8cw", + "token_type": "bearer", + "id_token": "eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0OjgwODAvdWFhL3Rva2VuX2tleXMiLCJraWQiOiJrZXktaWQtMSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyZTlkOWMxNS0wMmJkLTRhMmYtYmZiNi1lOWEwNzk5MGM1YzEiLCJhdWQiOlsiYWRtaW4iXSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgxL3VhYS9vYXV0aC90b2tlbiIsImV4cCI6MTU2OTA1ODgyNCwiaWF0IjoxNTY5MDE1NjI0LCJhbXIiOlsicHdkIl0sImF6cCI6ImFkbWluIiwic2NvcGUiOlsib3BlbmlkIl0sImVtYWlsIjoic3ViamVjdEBsb2NhbGhvc3QiLCJ6aWQiOiJ1YWEiLCJvcmlnaW4iOiJ1YWEiLCJqdGkiOiJkMzg5NzBmNTc2MGU0NWRhOWExZTg5MjU0NDdlNzM5MSIsInByZXZpb3VzX2xvZ29uX3RpbWUiOjE1NjkwMTUzOTQ5OTUsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJjbGllbnRfaWQiOiJhZG1pbiIsImNpZCI6ImFkbWluIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9uYW1lIjoic3ViamVjdCIsInJldl9zaWciOiJhNGExODY5IiwidXNlcl9pZCI6IjJlOWQ5YzE1LTAyYmQtNGEyZi1iZmI2LWU5YTA3OTkwYzVjMSIsImF1dGhfdGltZSI6MTU2OTAxNTYyNH0.YrXHDjUQDjP6L2TP7udDXV95xDGv1RpftILXN7WXP0SiHWC82-rJ-45ZoZEHl-Ma4ACgxivnAt4qWSwE9l_G-CnakeWmb47nqT9ZMHgebyMQDtPkn79JjAegkqorXTvEOjVIoRbdm-RsybHjQd_Wn8hGT-Pe6IyglwtsAHbCCHOviZG1cDO8hPWnwuUFKgcx1Z_4zrviEaIbTFQZdlfNE3NSN4MIkjhVr91Rq6eIQxhfyo4zfmNWa2tOHFR_05FZzzn8hBLnie5-XDkBVcRccPgLSe-pnZlPXFXSXpX03Lwj4NK6raF4v-XNir0xf_3MadYvanWqf7-9Ep4p1fslYw", + "expires_in": 43199, + "scope": "openid", + "jti": "d38970f5760e45da9a1e8925447e7391" +} \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/oauth_token.json b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/oauth_token.json deleted file mode 100644 index 6f7d01b1a89..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/oauth_token.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJtZXNzYWdlOndyaXRlIl0sImV4cCI6MTU2ODc1MzYyNSwianRpIjoiMmE5ZWUyMjMtYmEwMi00N2EwLWExMzUtMzk0MDcyNjMzMzVkIiwiY2xpZW50X2lkIjoid3JpdGVyIn0.BcghzN75YeXYBxLgkjHlH49kLErqZs2sL8CnT3p-S8fSwIObnmq0MioVdURj2-Q7nnV-gPlZsIScYOa2C5oG8UCqU9hJFqcjXoZ4FbMXrL0RgU5Kahok8nSkWCwx9ZKtjiPDFkZ6LXE-Rf0v3JbaaaYGfqjaFNmo8Rj-nVGerp0yi1ALwlJmTEJaaT2c6VqufOpecHj6xng3I99bSYsREp7FKQY-BW1gnkLQT1u8ooN8EYmXcpSnruUTFTwpmdwcNG9MMGOn2Zr3P_1eb-qI3LLPfh5rVcJric-yz8dG5mQVBPDMGjXGnw6vC5baKByK-RfiUcUEwZOthwqIJLo1Yw", - "token_type": "bearer", - "expires_in": 35999, - "scope": "message:write", - "jti": "2a9ee223-ba02-47a0-a135-39407263335d" -} \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile index 9a3fc18c762..601e235b82f 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile @@ -1,7 +1,14 @@ -FROM openjdk:8-jre-alpine +FROM tomcat:8.5 -COPY /target/spring-boot-admin-sample-oauth2-authorization.jar app.jar +ENV UAA_CONFIG_PATH=/usr/local/tomcat/webapps -EXPOSE 8081 +WORKDIR /usr/local/tomcat/conf +RUN sed -i -e 's/8080/8081/' server.xml -ENTRYPOINT ["java","-jar","app.jar"] \ No newline at end of file +WORKDIR /usr/local/tomcat/webapps +RUN wget -O uaa.war "https://repo1.maven.org/maven2/org/cloudfoundry/identity/cloudfoundry-identity-uaa/4.30.0/\ +cloudfoundry-identity-uaa-4.30.0.war" + +COPY config/uaa.yml $UAA_CONFIG_PATH/uaa.yml + +EXPOSE 8081 \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/config/uaa.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/config/uaa.yml new file mode 100644 index 00000000000..3ea2fb138c2 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/config/uaa.yml @@ -0,0 +1,108 @@ +issuer: + uri: http://localhost:8081/uaa + +encryption: + encryption_keys: + - label: encryption-key-1 + passphrase: XTMsZJZFQDyA2ds60c3MzmqDszP0AZ + active_key_label: encryption-key-1 + +oauth: + user: + authorities: + - openid + clients: + admin: + name: admin + secret: secret + authorized-grant-types: password + scope: openid + +scim: + users: + - subject|password|subject@localhost|Test|Subject|openid + +jwt: + token: + verification-key: | + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0m59l2u9iDnMbrXHfqkO + rn2dVQ3vfBJqcDuFUK03d+1PZGbVlNCqnkpIJ8syFppW8ljnWweP7+LiWpRoz0I7 + fYb3d8TjhV86Y997Fl4DBrxgM6KTJOuE/uxnoDhZQ14LgOU2ckXjOzOdTsnGMKQB + LCl0vpcXBtFLMaSbpv1ozi8h7DJyVZ6EnFQZUWGdgTMhDrmqevfx95U/16c5WBDO + kqwIn7Glry9n9Suxygbf8g5AzpWcusZgDLIIZ7JTUldBb8qU2a0Dl4mvLZOn4wPo + jfj9Cw2QICsc5+Pwf21fP+hzf+1WSRHbnYv8uanRO0gZ8ekGaghM/2H6gqJbo2nI + JwIDAQAB + -----END PUBLIC KEY----- + policy: + activeKeyId: key-id-1 + keys: + key-id-1: + signingKey: | + -----BEGIN RSA PRIVATE KEY----- + MIIEowIBAAKCAQEA0m59l2u9iDnMbrXHfqkOrn2dVQ3vfBJqcDuFUK03d+1PZGbV + lNCqnkpIJ8syFppW8ljnWweP7+LiWpRoz0I7fYb3d8TjhV86Y997Fl4DBrxgM6KT + JOuE/uxnoDhZQ14LgOU2ckXjOzOdTsnGMKQBLCl0vpcXBtFLMaSbpv1ozi8h7DJy + VZ6EnFQZUWGdgTMhDrmqevfx95U/16c5WBDOkqwIn7Glry9n9Suxygbf8g5AzpWc + usZgDLIIZ7JTUldBb8qU2a0Dl4mvLZOn4wPojfj9Cw2QICsc5+Pwf21fP+hzf+1W + SRHbnYv8uanRO0gZ8ekGaghM/2H6gqJbo2nIJwIDAQABAoIBAHPV9rSfzllq16op + zoNetIJBC5aCcU4vJQBbA2wBrgMKUyXFpdSheQphgY7GP/BJTYtifRiS9RzsHAYY + pAlTQEQ9Q4RekZAdd5r6rlsFrUzL7Xj/CVjNfQyHPhPocNqwrkxp4KrO5eL06qcw + UzT7UtnoiCdSLI7IL0hIgJZP8J1uPNdXH+kkDEHE9xzU1q0vsi8nBLlim+ioYfEa + Q/Q/ovMNviLKVs+ZUz+wayglDbCzsevuU+dh3Gmfc98DJw6n6iClpd4fDPqvhxUO + BDeQT1mFeHxexDse/kH9nygxT6E4wlU1sw0TQANcT6sHReyHT1TlwnWlCQzoR3l2 + RmkzUsECgYEA8W/VIkfyYdUd5ri+yJ3iLdYF2tDvkiuzVmJeA5AK2KO1fNc7cSPK + /sShHruc0WWZKWiR8Tp3d1XwA2rHMFHwC78RsTds+NpROs3Ya5sWd5mvmpEBbL+z + cl3AU9NLHVvsZjogmgI9HIMTTl4ld7GDsFMt0qlCDztqG6W/iguQCx8CgYEA3x/j + UkP45/PaFWd5c1DkWvmfmi9UxrIM7KeyBtDExGIkffwBMWFMCWm9DODw14bpnqAA + jH5AhQCzVYaXIdp12b+1+eOOckYHwzjWOFpJ3nLgNK3wi067jVp0N0UfgV5nfYw/ + +YoHfYRCGsM91fowh7wLcyPPwmSAbQAKwbOZKfkCgYEAnccDdZ+m2iA3pitdIiVr + RaDzuoeHx/IfBHjMD2/2ZpS1aZwOEGXfppZA5KCeXokSimj31rjqkWXrr4/8E6u4 + PzTiDvm1kPq60r7qi4eSKx6YD15rm/G7ByYVJbKTB+CmoDekToDgBt3xo+kKeyna + cUQqUdyieunM8bxja4ca3ukCgYAfrDAhomJ30qa3eRvFYcs4msysH2HiXq30/g0I + aKQ12FSjyZ0FvHEFuQvMAzZM8erByKarStSvzJyoXFWhyZgHE+6qDUJQOF6ruKq4 + DyEDQb1P3Q0TSVbYRunOWrKRM6xvJvSB4LUVfSvBDsv9TumKqwfZDVFVn9yXHHVq + b6sjSQKBgDkcyYkAjpOHoG3XKMw06OE4OKpP9N6qU8uZOuA8ZF9ZyR7vFf4bCsKv + QH+xY/4h8tgL+eASz5QWhj8DItm8wYGI5lKJr8f36jk0JLPUXODyDAeN6ekXY9LI + fudkijw0dnh28LJqbkFF5wLNtATzyCfzjp+czrPMn9uqLNKt/iVD + -----END RSA PRIVATE KEY----- + +login: + serviceProviderKey: | + -----BEGIN RSA PRIVATE KEY----- + MIICXQIBAAKBgQDHtC5gUXxBKpEqZTLkNvFwNGnNIkggNOwOQVNbpO0WVHIivig5 + L39WqS9u0hnA+O7MCA/KlrAR4bXaeVVhwfUPYBKIpaaTWFQR5cTR1UFZJL/OF9vA + fpOwznoD66DDCnQVpbCjtDYWX+x6imxn8HCYxhMol6ZnTbSsFW6VZjFMjQIDAQAB + AoGAVOj2Yvuigi6wJD99AO2fgF64sYCm/BKkX3dFEw0vxTPIh58kiRP554Xt5ges + 7ZCqL9QpqrChUikO4kJ+nB8Uq2AvaZHbpCEUmbip06IlgdA440o0r0CPo1mgNxGu + lhiWRN43Lruzfh9qKPhleg2dvyFGQxy5Gk6KW/t8IS4x4r0CQQD/dceBA+Ndj3Xp + ubHfxqNz4GTOxndc/AXAowPGpge2zpgIc7f50t8OHhG6XhsfJ0wyQEEvodDhZPYX + kKBnXNHzAkEAyCA76vAwuxqAd3MObhiebniAU3SnPf2u4fdL1EOm92dyFs1JxyyL + gu/DsjPjx6tRtn4YAalxCzmAMXFSb1qHfwJBAM3qx3z0gGKbUEWtPHcP7BNsrnWK + vw6By7VC8bk/ffpaP2yYspS66Le9fzbFwoDzMVVUO/dELVZyBnhqSRHoXQcCQQCe + A2WL8S5o7Vn19rC0GVgu3ZJlUrwiZEVLQdlrticFPXaFrn3Md82ICww3jmURaKHS + N+l4lnMda79eSp3OMmq9AkA0p79BvYsLshUJJnvbk76pCjR28PK4dV1gSDUEqQMB + qy45ptdwJLqLJCeNoR0JUcDNIRhOCuOPND7pcMtX6hI/ + -----END RSA PRIVATE KEY----- + serviceProviderKeyPassword: password + serviceProviderCertificate: | + -----BEGIN CERTIFICATE----- + MIIDSTCCArKgAwIBAgIBADANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJhdzEO + MAwGA1UECBMFYXJ1YmExDjAMBgNVBAoTBWFydWJhMQ4wDAYDVQQHEwVhcnViYTEO + MAwGA1UECxMFYXJ1YmExDjAMBgNVBAMTBWFydWJhMR0wGwYJKoZIhvcNAQkBFg5h + cnViYUBhcnViYS5hcjAeFw0xNTExMjAyMjI2MjdaFw0xNjExMTkyMjI2MjdaMHwx + CzAJBgNVBAYTAmF3MQ4wDAYDVQQIEwVhcnViYTEOMAwGA1UEChMFYXJ1YmExDjAM + BgNVBAcTBWFydWJhMQ4wDAYDVQQLEwVhcnViYTEOMAwGA1UEAxMFYXJ1YmExHTAb + BgkqhkiG9w0BCQEWDmFydWJhQGFydWJhLmFyMIGfMA0GCSqGSIb3DQEBAQUAA4GN + ADCBiQKBgQDHtC5gUXxBKpEqZTLkNvFwNGnNIkggNOwOQVNbpO0WVHIivig5L39W + qS9u0hnA+O7MCA/KlrAR4bXaeVVhwfUPYBKIpaaTWFQR5cTR1UFZJL/OF9vAfpOw + znoD66DDCnQVpbCjtDYWX+x6imxn8HCYxhMol6ZnTbSsFW6VZjFMjQIDAQABo4Ha + MIHXMB0GA1UdDgQWBBTx0lDzjH/iOBnOSQaSEWQLx1syGDCBpwYDVR0jBIGfMIGc + gBTx0lDzjH/iOBnOSQaSEWQLx1syGKGBgKR+MHwxCzAJBgNVBAYTAmF3MQ4wDAYD + VQQIEwVhcnViYTEOMAwGA1UEChMFYXJ1YmExDjAMBgNVBAcTBWFydWJhMQ4wDAYD + VQQLEwVhcnViYTEOMAwGA1UEAxMFYXJ1YmExHTAbBgkqhkiG9w0BCQEWDmFydWJh + QGFydWJhLmFyggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAYvBJ + 0HOZbbHClXmGUjGs+GS+xC1FO/am2suCSYqNB9dyMXfOWiJ1+TLJk+o/YZt8vuxC + KdcZYgl4l/L6PxJ982SRhc83ZW2dkAZI4M0/Ud3oePe84k8jm3A7EvH5wi5hvCkK + RpuRBwn3Ei+jCRouxTbzKPsuCVB+1sNyxMTXzf0= + -----END CERTIFICATE----- \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/pom.xml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/pom.xml index d235cc443cc..bd2e1582dc3 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/pom.xml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/pom.xml @@ -20,6 +20,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-boot-admin-sample-oauth2-authorization + pom Spring Boot Admin Sample OAuth2 - Authorization Server Spring Boot Admin Sample OAuth2 - Authorization Server @@ -28,44 +29,4 @@ ${revision} .. - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.security.oauth.boot - spring-security-oauth2-autoconfigure - - - com.nimbusds - nimbus-jose-jwt - - - org.springframework.boot - spring-boot-starter-test - test - - - - ${project.artifactId} - - - org.springframework.boot - spring-boot-maven-plugin - - - - repackage - - - - - - de.codecentric.boot.admin.sample.oauth2.SpringBootAdminOAuth2AuthorizationServerApplication - - - - - \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AuthorizationServerApplication.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AuthorizationServerApplication.java deleted file mode 100644 index ff39f0771c6..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AuthorizationServerApplication.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class SpringBootAdminOAuth2AuthorizationServerApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringBootAdminOAuth2AuthorizationServerApplication.class, args); - } - -} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthorizationServerConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthorizationServerConfiguration.java deleted file mode 100644 index c4cf23b89c1..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthorizationServerConfiguration.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; -import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; -import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter; -import org.springframework.security.oauth2.provider.token.TokenStore; -import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter; -import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; -import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; - -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.util.LinkedHashMap; -import java.util.Map; - -@Configuration -@EnableAuthorizationServer -public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { - - private static final String[] AUTHORIZED_GRANT_TYPES = {"password"}; - - private final AuthenticationConfiguration authenticationConfiguration; - - public AuthorizationServerConfiguration(AuthenticationConfiguration authenticationConfiguration) { - this.authenticationConfiguration = authenticationConfiguration; - } - - @Override - public void configure(ClientDetailsServiceConfigurer clients) throws Exception { - // @formatter:off - clients.inMemory() - .withClient("reader") - .authorizedGrantTypes(AUTHORIZED_GRANT_TYPES) - .secret("{noop}secret") - .scopes("message:read") - .accessTokenValiditySeconds(36_000) - .and() - .withClient("writer") - .authorizedGrantTypes(AUTHORIZED_GRANT_TYPES) - .secret("{noop}secret") - .scopes("message:write") - .accessTokenValiditySeconds(36_000); - // @formatter:on - } - - @Override - public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { - endpoints - .authenticationManager(this.authenticationConfiguration.getAuthenticationManager()) - .accessTokenConverter(accessTokenConverter()) - .tokenStore(tokenStore()); - } - - @Bean - public UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(User - .withUsername("subject") - .password("{noop}password") - .roles("USER") - .build()); - } - - @Bean - public TokenStore tokenStore() { - return new JwtTokenStore(accessTokenConverter()); - } - - @Bean - public JwtAccessTokenConverter accessTokenConverter() { - JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); - converter.setKeyPair(keyPair()); - - DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); - accessTokenConverter.setUserTokenConverter(authenticationConverter()); - converter.setAccessTokenConverter(accessTokenConverter); - - return converter; - } - - @Bean - public KeyPair keyPair() { - try { - KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); - generator.initialize(2048); - return generator.generateKeyPair(); - } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException(e); - } - } - - private UserAuthenticationConverter authenticationConverter() { - return new DefaultUserAuthenticationConverter() { - @Override - public Map convertUserAuthentication(Authentication authentication) { - Map response = new LinkedHashMap<>(); - response.put("sub", authentication.getName()); - if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) { - response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities())); - } - return response; - } - }; - } - -} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java deleted file mode 100644 index 950478df0f4..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -@Configuration -public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(HttpSecurity httpSecurity) throws Exception { - // @formatter:off - httpSecurity - .csrf() - .disable() - .authorizeRequests() - .antMatchers("/.well-known/jwks.json").permitAll(); - // @formatter:on - } - -} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/WellKnownController.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/WellKnownController.java deleted file mode 100644 index 08f39963bcb..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/WellKnownController.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.web; - -import com.nimbusds.jose.jwk.JWKSet; -import com.nimbusds.jose.jwk.RSAKey; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.security.KeyPair; -import java.security.interfaces.RSAPublicKey; -import java.util.Map; - -@RestController -@RequestMapping("/.well-known") -public class WellKnownController { - - private final KeyPair keyPair; - - public WellKnownController(KeyPair keyPair) { - this.keyPair = keyPair; - } - - @GetMapping("/jwks.json") - public Map getJwkSet() { - RSAPublicKey publicKey = (RSAPublicKey) this.keyPair.getPublic(); - RSAKey key = new RSAKey.Builder(publicKey).build(); - return new JWKSet(key).toJSONObject(); - } - -} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml deleted file mode 100644 index 54b155fffd1..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/main/resources/application.yml +++ /dev/null @@ -1,2 +0,0 @@ -server: - port: 8081 \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/test/java/de/codecentric/boot/admin/sample/oauth2/AuthorizationServerIntegrationTest.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/test/java/de/codecentric/boot/admin/sample/oauth2/AuthorizationServerIntegrationTest.java deleted file mode 100644 index b2eeb95ae82..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/src/test/java/de/codecentric/boot/admin/sample/oauth2/AuthorizationServerIntegrationTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.ResultActions; - -import static org.hamcrest.Matchers.both; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.lessThan; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@SpringBootTest -@AutoConfigureMockMvc -class AuthorizationServerIntegrationTest { - - @Autowired - private MockMvc mockMvc; - - @Test - void should_authenticate_and_return_token() throws Exception { - // given - String grantType = "password"; - String username = "subject"; - String password = "password"; - - // when - ResultActions resultActions = mockMvc.perform(post("/oauth/token") - .param("grant_type", grantType) - .param("username", username) - .param("password", password) - .header("Authorization", "Basic cmVhZGVyOnNlY3JldA==")); - - // then - resultActions - .andExpect(status().isOk()) - .andExpect(jsonPath("$.access_token").isNotEmpty()) - .andExpect(jsonPath("$.token_type").value("bearer")) - .andExpect(jsonPath("$.expires_in").value(both(lessThan(36000)).and(greaterThan(35990)))) - .andExpect(jsonPath("$.scope").value("message:read")) - .andExpect(jsonPath("$.jti").isNotEmpty()); - } - - @Test - void should_return_well_known_jwks() throws Exception { - // when - ResultActions resultActions = mockMvc.perform(get("/.well-known/jwks.json")); - - // then - resultActions - .andExpect(status().isOk()) - .andExpect(jsonPath("$.keys").value(hasSize(1))) - .andExpect(jsonPath("$.keys[0].kty").value("RSA")) - .andExpect(jsonPath("$.keys[0].e").value("AQAB")) - .andExpect(jsonPath("$.keys[0].n").isNotEmpty()); - } - -} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml index ca0177de314..07ab3cdbe8b 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml @@ -1,6 +1,11 @@ server: port: 8082 +cloudfoundry: + uaa: + host: localhost + port: 8081 + spring: application: name: resource-service @@ -14,7 +19,7 @@ spring: oauth2: resourceserver: jwt: - jwk-set-uri: http://localhost:8081/.well-known/jwks.json + jwk-set-uri: http://${cloudfoundry.uaa.host}:${cloudfoundry.uaa.port}/uaa/token_keys management: endpoints: From 8cd160e32a5cf844b00be08af211053c40204eb2 Mon Sep 17 00:00:00 2001 From: Illia Chtchoma Date: Sat, 21 Sep 2019 00:26:06 +0200 Subject: [PATCH 5/8] More precise CSRF configuration for admin server --- .../config/WebSecurityConfiguration.java | 21 +++++++++++++++++-- .../SpringBootAdminServerIntegrationTest.java | 5 ++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java index 7502d9ebb19..491908efce7 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java @@ -20,15 +20,22 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; +import org.springframework.http.HttpMethod; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.oauth2.client.*; +import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import static org.springframework.security.oauth2.client.OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME; import static org.springframework.security.oauth2.client.OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME; @@ -51,7 +58,17 @@ protected void configure(HttpSecurity httpSecurity) throws Exception { // @formatter:off httpSecurity .csrf() - .disable() + .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) + .ignoringRequestMatchers( + new AntPathRequestMatcher( + this.adminServerProperties.path("/instances"), + HttpMethod.POST.toString()), + new AntPathRequestMatcher( + this.adminServerProperties.path("/instances/*"), + HttpMethod.DELETE.toString()), + new AntPathRequestMatcher( + this.adminServerProperties.path("/actuator/**")) + ).and() .authorizeRequests() .antMatchers(adminServerProperties.path("/assets/**")).permitAll() .antMatchers(adminServerProperties.path("/login")).permitAll() diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java index c3eb36b3dc0..c2ee61ed43d 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java @@ -22,7 +22,10 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; -import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; @SpringBootTest From 12fe1c056af4109e408a225441d547b71a6f89f8 Mon Sep 17 00:00:00 2001 From: Illia Chtchoma Date: Thu, 26 Sep 2019 15:52:29 +0200 Subject: [PATCH 6/8] Migration to authorization_code grant type --- .../docker-compose.yml | 10 +- .../spring-boot-admin-sample-oauth2/pom.xml | 18 ---- .../Dockerfile | 10 +- .../pom.xml | 8 +- ...BootAdminOAuth2AdminServerApplication.java | 30 +++++- .../CustomOAuth2AuthorizedClientService.java | 94 +++++++++++++++++++ ...swordGrantTypeContextAttributesMapper.java | 47 ---------- .../config/WebSecurityConfiguration.java | 77 +++++---------- .../oauth2/web/LoginRedirectController.java | 45 +++++++++ .../src/main/resources/application.yml | 34 +++++-- .../SpringBootAdminServerIntegrationTest.java | 2 +- ...sponse.json => access-token-response.json} | 0 .../Dockerfile | 5 +- .../config/uaa.yml | 3 +- .../Dockerfile | 10 +- .../pom.xml | 5 + .../config/WebSecurityConfiguration.java | 32 ++++++- .../src/main/resources/application.yml | 11 ++- .../oauth2/ResourceServerIntegrationTest.java | 38 ++++++-- .../test/resources/__files/token-keys.json | 13 +++ .../src/test/resources/jwks.json | 9 -- 21 files changed, 331 insertions(+), 170 deletions(-) create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/CustomOAuth2AuthorizedClientService.java delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/PasswordGrantTypeContextAttributesMapper.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/LoginRedirectController.java rename spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/{access_token_response.json => access-token-response.json} (100%) create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/__files/token-keys.json delete mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/jwks.json diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml index fd960035cfc..2f339c6c086 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/docker-compose.yml @@ -4,6 +4,8 @@ services: authorization-server: build: context: ./spring-boot-admin-sample-oauth2-authorization + environment: + REDIRECT_URI: http://localhost:8080,http://localhost:8080/login/oauth2/code/admin container_name: sba-oauth2-auth ports: - 8081:8081 @@ -15,9 +17,13 @@ services: environment: cloudfoundry.uaa.host: authorization-server cloudfoundry.uaa.port: 8081 + spring.security.oauth2.client.provider.cloudfoundry-uaa.authorization-uri: >- + http://localhost:8081/uaa/oauth/authorize + security.logout.redirect-url: >- + http://localhost:8081/uaa/logout.do?client_id=admin&redirect=http://localhost:8080/login depends_on: - authorization-server - command: ["./wait-for.sh authorization-server:8081 --timeout=120 -- java -jar app.jar"] + command: ["./wait-for-command.sh -t 120 -c 'curl authorization-server:8081/uaa' && java -jar app.jar"] ports: - 8080:8080 @@ -32,6 +38,6 @@ services: depends_on: - authorization-server - admin-server - command: ["./wait-for.sh admin-server:8080 --timeout=120 -- java -jar app.jar"] + command: ["./wait-for-command.sh -t 120 -c 'curl admin-server:8080' && java -jar app.jar"] ports: - 8082:8082 \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml index 691a0af3644..29fe6a685a7 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml @@ -34,22 +34,4 @@ spring-boot-admin-sample-oauth2-authorization spring-boot-admin-sample-oauth2-resource - - 7.8 - 2.1.8.RELEASE - - - - - org.springframework.security.oauth.boot - spring-security-oauth2-autoconfigure - ${spring-security-oauth2-autoconfigure.version} - - - com.nimbusds - nimbus-jose-jwt - ${nimbus-jose-jwt.version} - - - \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile index 1dc0dfc17a1..8e5b70540ea 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/Dockerfile @@ -1,10 +1,12 @@ FROM openjdk:8-jre-alpine +RUN apk --no-cache add curl + COPY /target/spring-boot-admin-sample-oauth2-admin.jar app.jar -EXPOSE 8080 +RUN wget -O wait-for-command.sh "https://raw.githubusercontent.com/ettore26/wait-for-command/master/wait-for-command.sh" +RUN chmod +x wait-for-command.sh -RUN wget -O wait-for.sh "https://raw.githubusercontent.com/eficode/wait-for/master/wait-for" -RUN chmod +x wait-for.sh +ENTRYPOINT ["/bin/sh", "-c"] -ENTRYPOINT ["/bin/sh", "-c"] \ No newline at end of file +EXPOSE 8080 \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/pom.xml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/pom.xml index 05d1eba168b..7d1da4391d2 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/pom.xml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/pom.xml @@ -38,12 +38,8 @@ spring-boot-admin-starter-server - org.springframework.security - spring-security-config - - - org.springframework.security - spring-security-oauth2-client + org.springframework.boot + spring-boot-starter-oauth2-client org.springframework.boot diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java index 822220e56fa..8cdab305d92 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java @@ -16,16 +16,22 @@ package de.codecentric.boot.admin.sample.oauth2; +import com.nimbusds.jose.util.Base64; +import de.codecentric.boot.admin.sample.oauth2.config.CustomOAuth2AuthorizedClientService; import de.codecentric.boot.admin.server.config.EnableAdminServer; import de.codecentric.boot.admin.server.web.client.HttpHeadersProvider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; import org.springframework.http.HttpHeaders; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.core.OAuth2AccessToken; +import java.util.Optional; + @EnableAdminServer @SpringBootApplication public class SpringBootAdminOAuth2AdminServerApplication { @@ -37,13 +43,29 @@ public static void main(String[] args) { } @Bean - public HttpHeadersProvider provider(@RegisteredOAuth2AuthorizedClient("my-client") OAuth2AuthorizedClient client) { - OAuth2AccessToken accessToken = client.getAccessToken(); + public HttpHeadersProvider provider(CustomOAuth2AuthorizedClientService clientService, Environment environment) { return instance -> { HttpHeaders headers = new HttpHeaders(); - headers.set(AUTHORIZATION_HEADER, accessToken.getTokenType().getValue() + " " + accessToken.getTokenValue()); + + Optional clientOptional = clientService.loadAuthorizedClientByScope("openid"); + + if (clientOptional.isPresent()) { + OAuth2AccessToken accessToken = clientOptional.get().getAccessToken(); + headers.set(AUTHORIZATION_HEADER, + String.join(" ", accessToken.getTokenType().getValue(), accessToken.getTokenValue())); + } else { + String username = environment.getRequiredProperty("security.client.healthcheck.username"); + String password = environment.getRequiredProperty("security.client.healthcheck.password"); + headers.set(AUTHORIZATION_HEADER, "Basic " + Base64.encode(username + ":" + password)); + } + return headers; }; } + @Bean + public OAuth2AuthorizedClientService clientService(ClientRegistrationRepository clientRegistrationRepository) { + return new CustomOAuth2AuthorizedClientService(clientRegistrationRepository); + } + } diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/CustomOAuth2AuthorizedClientService.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/CustomOAuth2AuthorizedClientService.java new file mode 100644 index 00000000000..40ef7f98305 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/CustomOAuth2AuthorizedClientService.java @@ -0,0 +1,94 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; + +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientId; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.util.Assert; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Mostly clones {@link org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService}, but + * provides an ability to load authorized client without concrete principal. + */ +public class CustomOAuth2AuthorizedClientService implements OAuth2AuthorizedClientService { + + private final Map authorizedClients; + private final ClientRegistrationRepository clientRegistrationRepository; + + public CustomOAuth2AuthorizedClientService(ClientRegistrationRepository clientRegistrationRepository) { + Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); + this.clientRegistrationRepository = clientRegistrationRepository; + this.authorizedClients = new ConcurrentHashMap<>(); + } + + public CustomOAuth2AuthorizedClientService(ClientRegistrationRepository clientRegistrationRepository, + Map authorizedClients) { + Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); + Assert.notEmpty(authorizedClients, "authorizedClients cannot be empty"); + this.clientRegistrationRepository = clientRegistrationRepository; + this.authorizedClients = new ConcurrentHashMap<>(authorizedClients); + } + + @Override + @SuppressWarnings("unchecked") + public T loadAuthorizedClient(String clientRegistrationId, String principalName) { + Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty"); + Assert.hasText(principalName, "principalName cannot be empty"); + ClientRegistration registration = this.clientRegistrationRepository.findByRegistrationId(clientRegistrationId); + if (registration == null) { + return null; + } + return (T) this.authorizedClients.get(new OAuth2AuthorizedClientId(clientRegistrationId, principalName)); + } + + @SuppressWarnings("unchecked") + public Optional loadAuthorizedClientByScope(String scope) { + return (Optional) authorizedClients.values().stream() + .filter(client -> client.getClientRegistration().getScopes().contains(scope)) + .findAny(); + } + + @Override + public void saveAuthorizedClient(OAuth2AuthorizedClient authorizedClient, Authentication principal) { + Assert.notNull(authorizedClient, "authorizedClient cannot be null"); + Assert.notNull(principal, "principal cannot be null"); + this.authorizedClients.put( + new OAuth2AuthorizedClientId( + authorizedClient.getClientRegistration().getRegistrationId(), + principal.getName()), + authorizedClient); + } + + @Override + public void removeAuthorizedClient(String clientRegistrationId, String principalName) { + Assert.hasText(clientRegistrationId, "clientRegistrationId cannot be empty"); + Assert.hasText(principalName, "principalName cannot be empty"); + ClientRegistration registration = this.clientRegistrationRepository.findByRegistrationId(clientRegistrationId); + if (registration != null) { + this.authorizedClients.remove(new OAuth2AuthorizedClientId(clientRegistrationId, principalName)); + } + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/PasswordGrantTypeContextAttributesMapper.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/PasswordGrantTypeContextAttributesMapper.java deleted file mode 100644 index 462a9275d4b..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/PasswordGrantTypeContextAttributesMapper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; - -import org.springframework.security.oauth2.client.OAuth2AuthorizationContext; -import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; -import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; -import org.springframework.util.StringUtils; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -public class PasswordGrantTypeContextAttributesMapper implements Function> { - - @Override - public Map apply(OAuth2AuthorizeRequest authorizeRequest) { - Map contextAttributes = new HashMap<>(); - String scope = authorizeRequest.getAttribute(OAuth2ParameterNames.SCOPE); - if (StringUtils.hasText(scope)) { - contextAttributes.put(OAuth2AuthorizationContext.REQUEST_SCOPE_ATTRIBUTE_NAME, - StringUtils.delimitedListToStringArray(scope, " ")); - } - contextAttributes.put( - OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, - authorizeRequest.getAttribute(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME)); - contextAttributes.put( - OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, - authorizeRequest.getAttribute(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME)); - return contextAttributes; - } - -} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java index 491908efce7..d11cdb6a4ac 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java @@ -18,29 +18,17 @@ import de.codecentric.boot.admin.server.config.AdminServerProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import static org.springframework.security.oauth2.client.OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME; -import static org.springframework.security.oauth2.client.OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME; - -@Configuration @EnableWebSecurity public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @@ -67,62 +55,43 @@ protected void configure(HttpSecurity httpSecurity) throws Exception { this.adminServerProperties.path("/instances/*"), HttpMethod.DELETE.toString()), new AntPathRequestMatcher( - this.adminServerProperties.path("/actuator/**")) - ).and() + this.adminServerProperties.path("/actuator/**"))) + .and() .authorizeRequests() .antMatchers(adminServerProperties.path("/assets/**")).permitAll() - .antMatchers(adminServerProperties.path("/login")).permitAll() - .antMatchers(adminServerProperties.path("/sw.js")).permitAll() - .anyRequest().authenticated() + .antMatchers(adminServerProperties.path("/sw.js")).permitAll() + .antMatchers(adminServerProperties.path("/instances")) + .hasAnyAuthority("ROLE_client", "SCOPE_openid") + .anyRequest().hasAuthority("SCOPE_openid") .and() - .formLogin() - .loginPage(adminServerProperties.path("/login")) + .oauth2Login() + .loginPage(adminServerProperties.path("/oauth2/authorization/" + getClientId())) + .and() + .logout() + .logoutSuccessUrl(getLogoutSuccessUrl()) .and() - .logout() - .logoutUrl(adminServerProperties.path("/logout")) + .oauth2Client() .and() .httpBasic(); // @formatter:on } @Bean - public OAuth2AuthorizedClient authorizedClient(AuthorizedClientServiceOAuth2AuthorizedClientManager clientManager) { - OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("my-client") - .principal(new UsernamePasswordAuthenticationToken("subject", "password")) - .attribute(USERNAME_ATTRIBUTE_NAME, "subject") - .attribute(PASSWORD_ATTRIBUTE_NAME, "password") - .build(); - return clientManager.authorize(authorizeRequest); - } - - @Bean - public AuthorizedClientServiceOAuth2AuthorizedClientManager clientManager( - ClientRegistrationRepository clientRegistrationRepository, - OAuth2AuthorizedClientService authorizedClientService) { - - AuthorizedClientServiceOAuth2AuthorizedClientManager manager = - new AuthorizedClientServiceOAuth2AuthorizedClientManager( - clientRegistrationRepository, - authorizedClientService); - - manager.setAuthorizedClientProvider( - OAuth2AuthorizedClientProviderBuilder.builder() - .password() + @Override + public UserDetailsService userDetailsService() { + return new InMemoryUserDetailsManager( + User.withUsername(environment.getRequiredProperty("security.client.registration.username")) + .password(environment.getRequiredProperty("security.client.registration.password")) + .roles("client") .build()); + } - manager.setContextAttributesMapper(new PasswordGrantTypeContextAttributesMapper()); - - return manager; + private String getClientId() { + return environment.getRequiredProperty("spring.security.oauth2.client.registration.admin.client-id"); } - @Bean - @Override - public UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(User - .withUsername(environment.getProperty("spring.security.user.name")) - .password("{noop}" + environment.getProperty("spring.security.user.password")) - .roles("USER") - .build()); + private String getLogoutSuccessUrl() { + return environment.getRequiredProperty("security.logout.redirect-url"); } } diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/LoginRedirectController.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/LoginRedirectController.java new file mode 100644 index 00000000000..c089dfe10ab --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/web/LoginRedirectController.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.web; + +import de.codecentric.boot.admin.server.ui.web.UiController; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Hook to shadow {@link UiController#login()}, as login page is provided by external provider. + */ +@Controller +@RequestMapping("/login") +public class LoginRedirectController { + + @GetMapping + public void redirectToIndex(HttpServletResponse response) throws IOException { + response.sendRedirect("/"); + } + + @GetMapping(params = "redirectTo") + public void redirectTo(@RequestParam String redirectTo, HttpServletResponse response) throws IOException { + response.sendRedirect(redirectTo); + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml index c3fc169e66b..f0d0cca2c37 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/resources/application.yml @@ -8,18 +8,34 @@ cloudfoundry: spring: security: - user: - name: sbadmin - password: pass oauth2: client: registration: - my-client: + admin: client-id: admin client-secret: secret - provider: my-provider - client-authentication-method: basic - authorization-grant-type: password + provider: cloudfoundry-uaa + authorization-grant-type: authorization_code + redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}" + scope: openid provider: - my-provider: - token-uri: http://${cloudfoundry.uaa.host}:${cloudfoundry.uaa.port}/uaa/oauth/token \ No newline at end of file + cloudfoundry-uaa: + authorization-uri: http://${cloudfoundry.uaa.host}:${cloudfoundry.uaa.port}/uaa/oauth/authorize + token-uri: http://${cloudfoundry.uaa.host}:${cloudfoundry.uaa.port}/uaa/oauth/token + user-info-uri: http://${cloudfoundry.uaa.host}:${cloudfoundry.uaa.port}/uaa/userinfo + user-name-attribute: sub + jwk-set-uri: http://${cloudfoundry.uaa.host}:${cloudfoundry.uaa.port}/uaa/token_keys + +security: + client: + registration: + username: client + password: "{noop}password" + healthcheck: + username: sba + password: password + logout: + redirect-url: >- + http://${cloudfoundry.uaa.host}:${cloudfoundry.uaa.port}/uaa/logout.do? + client_id=${spring.security.oauth2.client.registration.admin.client-id}& + redirect=http://localhost:${server.port}/login \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java index c2ee61ed43d..b86a3affd07 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminServerIntegrationTest.java @@ -41,7 +41,7 @@ static void beforeAll() { stubFor(post("/uaa/oauth/token").willReturn( aResponse() .withHeader("Content-Type", "application/json") - .withBodyFile("access_token_response.json"))); + .withBodyFile("access-token-response.json"))); } @AfterAll diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/access_token_response.json b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/access-token-response.json similarity index 100% rename from spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/access_token_response.json rename to spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/test/resources/__files/access-token-response.json diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile index 601e235b82f..bdb1ff17a0c 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/Dockerfile @@ -9,6 +9,9 @@ WORKDIR /usr/local/tomcat/webapps RUN wget -O uaa.war "https://repo1.maven.org/maven2/org/cloudfoundry/identity/cloudfoundry-identity-uaa/4.30.0/\ cloudfoundry-identity-uaa-4.30.0.war" -COPY config/uaa.yml $UAA_CONFIG_PATH/uaa.yml +COPY config/uaa.yml ${UAA_CONFIG_PATH}/uaa.yml + +CMD sed -i "s|#{REDIRECT_URI}|${REDIRECT_URI}|g" ${UAA_CONFIG_PATH}/uaa.yml && \ +/usr/local/tomcat/bin/catalina.sh run EXPOSE 8081 \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/config/uaa.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/config/uaa.yml index 3ea2fb138c2..9c6b344cc33 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/config/uaa.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-authorization/config/uaa.yml @@ -15,7 +15,8 @@ oauth: admin: name: admin secret: secret - authorized-grant-types: password + authorized-grant-types: authorization_code + redirect-uri: #{REDIRECT_URI} scope: openid scim: diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile index f4aac179d9e..cfacc50fcf1 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/Dockerfile @@ -1,10 +1,12 @@ FROM openjdk:8-jre-alpine +RUN apk --no-cache add curl + COPY /target/spring-boot-admin-sample-oauth2-resource.jar app.jar -EXPOSE 8082 +RUN wget -O wait-for-command.sh "https://raw.githubusercontent.com/ettore26/wait-for-command/master/wait-for-command.sh" +RUN chmod +x wait-for-command.sh -RUN wget -O wait-for.sh "https://raw.githubusercontent.com/eficode/wait-for/master/wait-for" -RUN chmod +x wait-for.sh +ENTRYPOINT ["/bin/sh", "-c"] -ENTRYPOINT ["/bin/sh", "-c"] \ No newline at end of file +EXPOSE 8082 \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml index 162c310e2f6..a22a97363cd 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/pom.xml @@ -55,6 +55,11 @@ spring-security-test test + + com.github.tomakehurst + wiremock-jre8-standalone + test + ${project.artifactId} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java index 2400ea19dcf..52193ce663d 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java @@ -16,23 +16,53 @@ package de.codecentric.boot.admin.sample.oauth2.config; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; @EnableWebSecurity public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + private final Environment environment; + + public WebSecurityConfiguration(Environment environment) { + this.environment = environment; + } + @Override protected void configure(HttpSecurity httpSecurity) throws Exception { // @formatter:off httpSecurity .authorizeRequests() - .anyRequest().authenticated() + .antMatchers("/actuator/health", "/actuator/info") + .hasAnyAuthority("ROLE_sba_server", "SCOPE_openid") + .antMatchers("/actuator/**").hasAuthority("SCOPE_openid") + .anyRequest().hasAuthority("ROLE_user") + .and() + .httpBasic() .and() .oauth2ResourceServer() .jwt(); // @formatter:off } + @Bean + @Override + protected UserDetailsService userDetailsService() { + return new InMemoryUserDetailsManager( + User.withUsername(environment.getRequiredProperty("security.healthcheck.username")) + .password(environment.getRequiredProperty("security.healthcheck.password")) + .roles("sba_server") + .build(), + User.withUsername("admin") + .password("{noop}password") + .roles("user") + .build()); + } + } diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml index 07ab3cdbe8b..f3beda9b5a5 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/main/resources/application.yml @@ -13,8 +13,8 @@ spring: admin: client: url: http://localhost:8080 - username: sbadmin - password: pass + username: client + password: password security: oauth2: resourceserver: @@ -25,4 +25,9 @@ management: endpoints: web: exposure: - include: "*" \ No newline at end of file + include: "*" + +security: + healthcheck: + username: sba + password: "{noop}password" \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/java/de/codecentric/boot/admin/sample/oauth2/ResourceServerIntegrationTest.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/java/de/codecentric/boot/admin/sample/oauth2/ResourceServerIntegrationTest.java index 7c36731985b..b1d052661e3 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/java/de/codecentric/boot/admin/sample/oauth2/ResourceServerIntegrationTest.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/java/de/codecentric/boot/admin/sample/oauth2/ResourceServerIntegrationTest.java @@ -16,6 +16,9 @@ package de.codecentric.boot.admin.sample.oauth2; +import com.github.tomakehurst.wiremock.WireMockServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -23,21 +26,44 @@ import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @AutoConfigureMockMvc class ResourceServerIntegrationTest { + private static WireMockServer mockAuthorizationServer = new WireMockServer(options().port(8081)); + + @BeforeAll + static void beforeAll() { + mockAuthorizationServer.start(); + configureFor(mockAuthorizationServer.port()); + + stubFor(post("/uaa/oauth/token_keys").willReturn( + aResponse() + .withHeader("Content-Type", "application/json") + .withBodyFile("token-keys.json"))); + } + + @AfterAll + static void afterAll() { + mockAuthorizationServer.stop(); + } + @Autowired private MockMvc mockMvc; @Test - void should_not_be_able_access_actuator_endpoint_without_authentication() throws Exception { + void should_not_be_able_to_access_actuator_endpoint_without_authentication() throws Exception { // when - ResultActions resultActions = mockMvc.perform(get("/actuator/health")); + ResultActions resultActions = mockMvc.perform(MockMvcRequestBuilders.get("/actuator/health")); // then resultActions @@ -45,10 +71,10 @@ void should_not_be_able_access_actuator_endpoint_without_authentication() throws } @Test - @WithMockUser - void should_be_able_access_actuator_endpoint_with_authentication() throws Exception { + @WithMockUser(roles = "sba_server") + void should_be_able_to_access_actuator_endpoint_with_authentication() throws Exception { // when - ResultActions resultActions = mockMvc.perform(get("/actuator/health")); + ResultActions resultActions = mockMvc.perform(MockMvcRequestBuilders.get("/actuator/health")); // then resultActions diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/__files/token-keys.json b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/__files/token-keys.json new file mode 100644 index 00000000000..60a129ef768 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/__files/token-keys.json @@ -0,0 +1,13 @@ +{ + "keys": [ + { + "kty": "RSA", + "e": "AQAB", + "use": "sig", + "kid": "key-id-1", + "alg": "RS256", + "value": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0m59l2u9iDnMbrXHfqkO\nrn2dVQ3vfBJqcDuFUK03d+1PZGbVlNCqnkpIJ8syFppW8ljnWweP7+LiWpRoz0I7\nfYb3d8TjhV86Y997Fl4DBrxgM6KTJOuE/uxnoDhZQ14LgOU2ckXjOzOdTsnGMKQB\nLCl0vpcXBtFLMaSbpv1ozi8h7DJyVZ6EnFQZUWGdgTMhDrmqevfx95U/16c5WBDO\nkqwIn7Glry9n9Suxygbf8g5AzpWcusZgDLIIZ7JTUldBb8qU2a0Dl4mvLZOn4wPo\njfj9Cw2QICsc5+Pwf21fP+hzf+1WSRHbnYv8uanRO0gZ8ekGaghM/2H6gqJbo2nI\nJwIDAQAB\n-----END PUBLIC KEY-----", + "n": "ANJufZdrvYg5zG61x36pDq59nVUN73wSanA7hVCtN3ftT2Rm1ZTQqp5KSCfLMhaaVvJY51sHj-_i4lqUaM9CO32G93fE44VfOmPfexZeAwa8YDOikyTrhP7sZ6A4WUNeC4DlNnJF4zsznU7JxjCkASwpdL6XFwbRSzGkm6b9aM4vIewyclWehJxUGVFhnYEzIQ65qnr38feVP9enOVgQzpKsCJ-xpa8vZ_UrscoG3_IOQM6VnLrGYAyyCGeyU1JXQW_KlNmtA5eJry2Tp-MD6I34_QsNkCArHOfj8H9tXz_oc3_tVkkR252L_Lmp0TtIGfHpBmoITP9h-oKiW6NpyCc" + } + ] +} \ No newline at end of file diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/jwks.json b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/jwks.json deleted file mode 100644 index e2b663eaccc..00000000000 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-resource/src/test/resources/jwks.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "keys":[ - { - "kty":"RSA", - "e":"AQAB", - "n":"jvBtqsGCOmnYzwe_-HvgOqlKk6HPiLEzS6uCCcnVkFXrhnkPMZ-uQXTR0u-7ZklF0XC7-AMW8FQDOJS1T7IyJpCyeU4lS8RIf_Z8RX51gPGnQWkRvNw61RfiSuSA45LR5NrFTAAGoXUca_lZnbqnl0td-6hBDVeHYkkpAsSck1NPhlcsn-Pvc2Vleui_Iy1U2mzZCM1Vx6Dy7x9IeP_rTNtDhULDMFbB_JYs-Dg6Zd5Ounb3mP57tBGhLYN7zJkN1AAaBYkElsc4GUsGsUWKqgteQSXZorpf6HdSJsQMZBDd7xG8zDDJ28hGjJSgWBndRGSzQEYU09Xbtzk-8khPuw" - } - ] -} \ No newline at end of file From 3bcd7bd1e696438ecbe56c673ca530498013e1b9 Mon Sep 17 00:00:00 2001 From: Illia Chtchoma Date: Sun, 29 Sep 2019 22:54:46 +0200 Subject: [PATCH 7/8] Fixed endpoint detection triggering on successful authentication --- .../spring-boot-admin-sample-oauth2/pom.xml | 2 +- ...BootAdminOAuth2AdminServerApplication.java | 40 ------------ .../config/AuthenticationHeaderProvider.java | 64 +++++++++++++++++++ .../OAuth2AuthenticationSuccessHandler.java | 58 +++++++++++++++++ ...=> OAuth2AuthorizedClientServiceImpl.java} | 13 +--- .../config/WebSecurityConfiguration.java | 6 +- 6 files changed, 131 insertions(+), 52 deletions(-) create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthenticationHeaderProvider.java create mode 100644 spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthenticationSuccessHandler.java rename spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/{CustomOAuth2AuthorizedClientService.java => OAuth2AuthorizedClientServiceImpl.java} (83%) diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml index 29fe6a685a7..886ebca4d81 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/pom.xml @@ -34,4 +34,4 @@ spring-boot-admin-sample-oauth2-authorization spring-boot-admin-sample-oauth2-resource - \ No newline at end of file + diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java index 8cdab305d92..3429dd20b1d 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/SpringBootAdminOAuth2AdminServerApplication.java @@ -16,56 +16,16 @@ package de.codecentric.boot.admin.sample.oauth2; -import com.nimbusds.jose.util.Base64; -import de.codecentric.boot.admin.sample.oauth2.config.CustomOAuth2AuthorizedClientService; import de.codecentric.boot.admin.server.config.EnableAdminServer; -import de.codecentric.boot.admin.server.web.client.HttpHeadersProvider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; -import org.springframework.core.env.Environment; -import org.springframework.http.HttpHeaders; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.core.OAuth2AccessToken; - -import java.util.Optional; @EnableAdminServer @SpringBootApplication public class SpringBootAdminOAuth2AdminServerApplication { - private static final String AUTHORIZATION_HEADER = "Authorization"; - public static void main(String[] args) { SpringApplication.run(SpringBootAdminOAuth2AdminServerApplication.class, args); } - @Bean - public HttpHeadersProvider provider(CustomOAuth2AuthorizedClientService clientService, Environment environment) { - return instance -> { - HttpHeaders headers = new HttpHeaders(); - - Optional clientOptional = clientService.loadAuthorizedClientByScope("openid"); - - if (clientOptional.isPresent()) { - OAuth2AccessToken accessToken = clientOptional.get().getAccessToken(); - headers.set(AUTHORIZATION_HEADER, - String.join(" ", accessToken.getTokenType().getValue(), accessToken.getTokenValue())); - } else { - String username = environment.getRequiredProperty("security.client.healthcheck.username"); - String password = environment.getRequiredProperty("security.client.healthcheck.password"); - headers.set(AUTHORIZATION_HEADER, "Basic " + Base64.encode(username + ":" + password)); - } - - return headers; - }; - } - - @Bean - public OAuth2AuthorizedClientService clientService(ClientRegistrationRepository clientRegistrationRepository) { - return new CustomOAuth2AuthorizedClientService(clientRegistrationRepository); - } - } diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthenticationHeaderProvider.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthenticationHeaderProvider.java new file mode 100644 index 00000000000..c2d77f5c51c --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/AuthenticationHeaderProvider.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; + +import com.nimbusds.jose.util.Base64; +import de.codecentric.boot.admin.server.domain.entities.Instance; +import de.codecentric.boot.admin.server.web.client.HttpHeadersProvider; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpHeaders; +import org.springframework.lang.NonNull; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class AuthenticationHeaderProvider implements HttpHeadersProvider { + + private static final String AUTHORIZATION_HEADER = "Authorization"; + + private final OAuth2AuthorizedClientServiceImpl clientService; + private final Environment environment; + + public AuthenticationHeaderProvider(OAuth2AuthorizedClientServiceImpl clientService, Environment environment) { + this.clientService = clientService; + this.environment = environment; + } + + @NonNull + @Override + public HttpHeaders getHeaders(@NonNull Instance instance) { + HttpHeaders headers = new HttpHeaders(); + + Optional clientOptional = clientService.loadAuthorizedClientByScope("openid"); + + if (clientOptional.isPresent()) { + OAuth2AccessToken accessToken = clientOptional.get().getAccessToken(); + headers.set(AUTHORIZATION_HEADER, + String.join(" ", accessToken.getTokenType().getValue(), accessToken.getTokenValue())); + } else { + String username = environment.getRequiredProperty("security.client.healthcheck.username"); + String password = environment.getRequiredProperty("security.client.healthcheck.password"); + headers.set(AUTHORIZATION_HEADER, "Basic " + Base64.encode(username + ":" + password)); + } + + return headers; + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthenticationSuccessHandler.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthenticationSuccessHandler.java new file mode 100644 index 00000000000..bcad1bd7393 --- /dev/null +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthenticationSuccessHandler.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014-2019 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 de.codecentric.boot.admin.sample.oauth2.config; + +import de.codecentric.boot.admin.server.domain.entities.Instance; +import de.codecentric.boot.admin.server.domain.entities.InstanceRepository; +import de.codecentric.boot.admin.server.services.EndpointDetector; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Component +public class OAuth2AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { + + private final InstanceRepository instanceRepository; + private final EndpointDetector endpointDetector; + + public OAuth2AuthenticationSuccessHandler(InstanceRepository instanceRepository, + EndpointDetector endpointDetector) { + this.instanceRepository = instanceRepository; + this.endpointDetector = endpointDetector; + } + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, + HttpServletResponse response, + Authentication authentication) throws ServletException, IOException { + super.onAuthenticationSuccess(request, response, authentication); + detectEndpoints(); + } + + private void detectEndpoints() { + instanceRepository.findAll() + .map(Instance::getId) + .flatMap(endpointDetector::detectEndpoints) + .subscribe(); + } + +} diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/CustomOAuth2AuthorizedClientService.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthorizedClientServiceImpl.java similarity index 83% rename from spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/CustomOAuth2AuthorizedClientService.java rename to spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthorizedClientServiceImpl.java index 40ef7f98305..08369fb94f8 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/CustomOAuth2AuthorizedClientService.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthorizedClientServiceImpl.java @@ -32,25 +32,18 @@ * Mostly clones {@link org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService}, but * provides an ability to load authorized client without concrete principal. */ -public class CustomOAuth2AuthorizedClientService implements OAuth2AuthorizedClientService { +// @Service +public class OAuth2AuthorizedClientServiceImpl implements OAuth2AuthorizedClientService { private final Map authorizedClients; private final ClientRegistrationRepository clientRegistrationRepository; - public CustomOAuth2AuthorizedClientService(ClientRegistrationRepository clientRegistrationRepository) { + public OAuth2AuthorizedClientServiceImpl(ClientRegistrationRepository clientRegistrationRepository) { Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); this.clientRegistrationRepository = clientRegistrationRepository; this.authorizedClients = new ConcurrentHashMap<>(); } - public CustomOAuth2AuthorizedClientService(ClientRegistrationRepository clientRegistrationRepository, - Map authorizedClients) { - Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); - Assert.notEmpty(authorizedClients, "authorizedClients cannot be empty"); - this.clientRegistrationRepository = clientRegistrationRepository; - this.authorizedClients = new ConcurrentHashMap<>(authorizedClients); - } - @Override @SuppressWarnings("unchecked") public T loadAuthorizedClient(String clientRegistrationId, String principalName) { diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java index d11cdb6a4ac..1084fd9877c 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/WebSecurityConfiguration.java @@ -34,11 +34,14 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { private final Environment environment; private final AdminServerProperties adminServerProperties; + private final OAuth2AuthenticationSuccessHandler authenticationSuccessHandler; public WebSecurityConfiguration(Environment environment, - AdminServerProperties adminServerProperties) { + AdminServerProperties adminServerProperties, + OAuth2AuthenticationSuccessHandler authenticationSuccessHandler) { this.environment = environment; this.adminServerProperties = adminServerProperties; + this.authenticationSuccessHandler = authenticationSuccessHandler; } @Override @@ -65,6 +68,7 @@ protected void configure(HttpSecurity httpSecurity) throws Exception { .anyRequest().hasAuthority("SCOPE_openid") .and() .oauth2Login() + .successHandler(authenticationSuccessHandler) .loginPage(adminServerProperties.path("/oauth2/authorization/" + getClientId())) .and() .logout() From eb4db577a1941bef836bab11cf6bf8cca83dfe44 Mon Sep 17 00:00:00 2001 From: Illia Chtchoma Date: Wed, 2 Oct 2019 23:56:33 +0200 Subject: [PATCH 8/8] Fixed bean declaration --- .../oauth2/config/OAuth2AuthorizedClientServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthorizedClientServiceImpl.java b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthorizedClientServiceImpl.java index 08369fb94f8..338d02d4d86 100644 --- a/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthorizedClientServiceImpl.java +++ b/spring-boot-admin-samples/spring-boot-admin-sample-oauth2/spring-boot-admin-sample-oauth2-admin/src/main/java/de/codecentric/boot/admin/sample/oauth2/config/OAuth2AuthorizedClientServiceImpl.java @@ -22,6 +22,7 @@ import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.stereotype.Service; import org.springframework.util.Assert; import java.util.Map; @@ -32,7 +33,7 @@ * Mostly clones {@link org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService}, but * provides an ability to load authorized client without concrete principal. */ -// @Service +@Service public class OAuth2AuthorizedClientServiceImpl implements OAuth2AuthorizedClientService { private final Map authorizedClients;