Refresh Getting Started example
Closes gh-1186
This commit is contained in:
@@ -32,7 +32,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
@@ -52,6 +52,7 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean // <1>
|
||||
@@ -70,7 +71,7 @@ public class SecurityConfig {
|
||||
new LoginUrlAuthenticationEntryPoint("/login"))
|
||||
)
|
||||
// Accept access tokens for User Info and/or Client Registration
|
||||
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
|
||||
.oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));
|
||||
// @formatter:on
|
||||
|
||||
return http.build();
|
||||
@@ -109,26 +110,21 @@ public class SecurityConfig {
|
||||
@Bean // <4>
|
||||
public RegisteredClientRepository registeredClientRepository() {
|
||||
// @formatter:off
|
||||
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
|
||||
.clientId("messaging-client")
|
||||
RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString())
|
||||
.clientId("oidc-client")
|
||||
.clientSecret("{noop}secret")
|
||||
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
|
||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||
.authorizationGrantType(AuthorizationGrantType.DEVICE_CODE)
|
||||
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
|
||||
.redirectUri("http://127.0.0.1:8080/authorized")
|
||||
.postLogoutRedirectUri("http://127.0.0.1:8080/index")
|
||||
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/oidc-client")
|
||||
.postLogoutRedirectUri("http://127.0.0.1:8080/")
|
||||
.scope(OidcScopes.OPENID)
|
||||
.scope(OidcScopes.PROFILE)
|
||||
.scope("message.read")
|
||||
.scope("message.write")
|
||||
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
return new InMemoryRegisteredClientRepository(registeredClient);
|
||||
return new InMemoryRegisteredClientRepository(oidcClient);
|
||||
}
|
||||
|
||||
@Bean // <5>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
server:
|
||||
port: 9000
|
||||
|
||||
logging:
|
||||
level:
|
||||
org.springframework.security: trace
|
||||
|
||||
spring:
|
||||
security:
|
||||
oauth2:
|
||||
authorizationserver:
|
||||
client:
|
||||
oidc-client:
|
||||
registration:
|
||||
client-id: "oidc-client"
|
||||
client-secret: "{noop}secret"
|
||||
client-authentication-methods:
|
||||
- "client_secret_basic"
|
||||
authorization-grant-types:
|
||||
- "authorization_code"
|
||||
- "refresh_token"
|
||||
redirect-uris:
|
||||
- "http://127.0.0.1:8080/login/oauth2/code/oidc-client"
|
||||
post-logout-redirect-uris:
|
||||
- "http://127.0.0.1:8080/"
|
||||
scopes:
|
||||
- "openid"
|
||||
- "profile"
|
||||
require-authorization-consent: true
|
||||
@@ -127,7 +127,7 @@ public class AuthorizationCodeGrantFlow {
|
||||
.andReturn();
|
||||
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
|
||||
assertThat(redirectedUrl).isNotNull();
|
||||
assertThat(redirectedUrl).matches("http://127.0.0.1:8080/authorized\\?code=.{15,}&state=state");
|
||||
assertThat(redirectedUrl).matches("http://127.0.0.1:8080/\\S+\\?code=.{15,}&state=state");
|
||||
|
||||
String locationHeader = URLDecoder.decode(redirectedUrl, StandardCharsets.UTF_8.name());
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromUriString(locationHeader).build();
|
||||
|
||||
@@ -21,7 +21,6 @@ import org.assertj.core.api.ObjectAssert;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import sample.AuthorizationCodeGrantFlow;
|
||||
import sample.DeviceAuthorizationGrantFlow;
|
||||
import sample.test.SpringTestContext;
|
||||
import sample.test.SpringTestContextExtension;
|
||||
|
||||
@@ -32,6 +31,7 @@ import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService;
|
||||
import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService;
|
||||
@@ -77,13 +77,13 @@ public class SecurityConfigTests {
|
||||
assertThat(this.authorizationService).isInstanceOf(InMemoryOAuth2AuthorizationService.class);
|
||||
assertThat(this.authorizationConsentService).isInstanceOf(InMemoryOAuth2AuthorizationConsentService.class);
|
||||
|
||||
RegisteredClient registeredClient = this.registeredClientRepository.findByClientId("messaging-client");
|
||||
RegisteredClient registeredClient = this.registeredClientRepository.findByClientId("oidc-client");
|
||||
assertThat(registeredClient).isNotNull();
|
||||
|
||||
AuthorizationCodeGrantFlow authorizationCodeGrantFlow = new AuthorizationCodeGrantFlow(this.mockMvc);
|
||||
authorizationCodeGrantFlow.setUsername("user");
|
||||
authorizationCodeGrantFlow.addScope("message.read");
|
||||
authorizationCodeGrantFlow.addScope("message.write");
|
||||
authorizationCodeGrantFlow.addScope(OidcScopes.OPENID);
|
||||
authorizationCodeGrantFlow.addScope(OidcScopes.PROFILE);
|
||||
|
||||
String state = authorizationCodeGrantFlow.authorize(registeredClient);
|
||||
assertThatAuthorization(state, OAuth2ParameterNames.STATE).isNotNull();
|
||||
@@ -117,53 +117,6 @@ public class SecurityConfigTests {
|
||||
StringUtils.delimitedListToStringArray(scopes, " "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deviceAuthorizationWhenGettingStartedConfigUsedThenSuccess() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfig.class).autowire();
|
||||
assertThat(this.registeredClientRepository).isInstanceOf(InMemoryRegisteredClientRepository.class);
|
||||
assertThat(this.authorizationService).isInstanceOf(InMemoryOAuth2AuthorizationService.class);
|
||||
assertThat(this.authorizationConsentService).isInstanceOf(InMemoryOAuth2AuthorizationConsentService.class);
|
||||
|
||||
RegisteredClient registeredClient = this.registeredClientRepository.findByClientId("messaging-client");
|
||||
assertThat(registeredClient).isNotNull();
|
||||
|
||||
DeviceAuthorizationGrantFlow deviceAuthorizationGrantFlow = new DeviceAuthorizationGrantFlow(this.mockMvc);
|
||||
deviceAuthorizationGrantFlow.setUsername("user");
|
||||
deviceAuthorizationGrantFlow.addScope("message.read");
|
||||
deviceAuthorizationGrantFlow.addScope("message.write");
|
||||
|
||||
Map<String, Object> deviceAuthorizationResponse = deviceAuthorizationGrantFlow.authorize(registeredClient);
|
||||
String userCode = (String) deviceAuthorizationResponse.get(OAuth2ParameterNames.USER_CODE);
|
||||
assertThatAuthorization(userCode, OAuth2ParameterNames.USER_CODE).isNotNull();
|
||||
assertThatAuthorization(userCode, null).isNotNull();
|
||||
|
||||
String deviceCode = (String) deviceAuthorizationResponse.get(OAuth2ParameterNames.DEVICE_CODE);
|
||||
assertThatAuthorization(deviceCode, OAuth2ParameterNames.DEVICE_CODE).isNotNull();
|
||||
assertThatAuthorization(deviceCode, null).isNotNull();
|
||||
|
||||
String state = deviceAuthorizationGrantFlow.submitCode(userCode);
|
||||
assertThatAuthorization(state, OAuth2ParameterNames.STATE).isNotNull();
|
||||
assertThatAuthorization(state, null).isNotNull();
|
||||
|
||||
deviceAuthorizationGrantFlow.submitConsent(registeredClient, state, userCode);
|
||||
|
||||
Map<String, Object> tokenResponse = deviceAuthorizationGrantFlow.getTokenResponse(registeredClient, deviceCode);
|
||||
String accessToken = (String) tokenResponse.get(OAuth2ParameterNames.ACCESS_TOKEN);
|
||||
assertThatAuthorization(accessToken, OAuth2ParameterNames.ACCESS_TOKEN).isNotNull();
|
||||
assertThatAuthorization(accessToken, null).isNotNull();
|
||||
|
||||
String refreshToken = (String) tokenResponse.get(OAuth2ParameterNames.REFRESH_TOKEN);
|
||||
assertThatAuthorization(refreshToken, OAuth2ParameterNames.REFRESH_TOKEN).isNotNull();
|
||||
assertThatAuthorization(refreshToken, null).isNotNull();
|
||||
|
||||
String scopes = (String) tokenResponse.get(OAuth2ParameterNames.SCOPE);
|
||||
OAuth2AuthorizationConsent authorizationConsent = this.authorizationConsentService.findById(
|
||||
registeredClient.getId(), "user");
|
||||
assertThat(authorizationConsent).isNotNull();
|
||||
assertThat(authorizationConsent.getScopes()).containsExactlyInAnyOrder(
|
||||
StringUtils.delimitedListToStringArray(scopes, " "));
|
||||
}
|
||||
|
||||
private ObjectAssert<OAuth2Authorization> assertThatAuthorization(String token, String tokenType) {
|
||||
return assertThat(findAuthorization(token, tokenType));
|
||||
}
|
||||
|
||||
@@ -15,7 +15,28 @@ Spring Authorization Server can be used anywhere you already use https://docs.sp
|
||||
|
||||
The easiest way to begin using Spring Authorization Server is by creating a https://spring.io/projects/spring-boot[Spring Boot]-based application.
|
||||
You can use https://start.spring.io[start.spring.io] to generate a basic project or use the https://github.com/spring-projects/spring-authorization-server/tree/main/samples/default-authorizationserver[default authorization server sample] as a guide.
|
||||
Then add Spring Authorization Server as a dependency, as in the following example:
|
||||
Then add Spring Boot's starter for Spring Authorization Server as a dependency:
|
||||
|
||||
[[spring-boot-maven-dependency]]
|
||||
.Maven
|
||||
[source,xml,role="primary",subs="attributes,verbatim"]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
[[spring-boot-gradle-dependency]]
|
||||
.Gradle
|
||||
[source,gradle,role="secondary",subs="attributes,verbatim"]
|
||||
----
|
||||
implementation "org.springframework.boot:spring-boot-starter-oauth2-authorization-server"
|
||||
----
|
||||
|
||||
TIP: See https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html#getting-started.installing[Installing Spring Boot] for more information on using Spring Boot with Maven or Gradle.
|
||||
|
||||
Alternatively, you can add Spring Authorization Server without Spring Boot using the following example:
|
||||
|
||||
[[maven-dependency]]
|
||||
.Maven
|
||||
@@ -35,15 +56,29 @@ Then add Spring Authorization Server as a dependency, as in the following exampl
|
||||
implementation "org.springframework.security:spring-security-oauth2-authorization-server:{spring-authorization-server-version}"
|
||||
----
|
||||
|
||||
TIP: See https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html#getting-started.installing[Installing Spring Boot] for more information on using Spring Boot with Maven or Gradle.
|
||||
|
||||
[[developing-your-first-application]]
|
||||
== Developing Your First Application
|
||||
|
||||
To get started, you need the minimum required components defined as a `@Bean` in a Spring `@Configuration`. These components can be defined as follows:
|
||||
To get started, you need the minimum required components defined as a `@Bean`. When using the `spring-boot-starter-oauth2-authorization-server` dependency, define the following properties and Spring Boot will provide the necessary `@Bean` definitions for you:
|
||||
|
||||
[[application-yml]]
|
||||
.application.yml
|
||||
[source,yaml]
|
||||
----
|
||||
include::{docs-java}/sample/gettingStarted/application.yml[]
|
||||
----
|
||||
|
||||
TIP: Beyond the Getting Started experience, most users will want to customize the default configuration. The <<defining-required-components,next section>> demonstrates providing all of the necessary beans yourself.
|
||||
|
||||
[[defining-required-components]]
|
||||
== Defining Required Components
|
||||
|
||||
If you want to customize the default configuration (regardless of whether you're using Spring Boot), you can define the minimum required components as a `@Bean` in a Spring `@Configuration`.
|
||||
|
||||
TIP: To skip the setup and run a working example, see the https://github.com/spring-projects/spring-authorization-server/tree/main/samples/default-authorizationserver[default authorization server sample].
|
||||
|
||||
These components can be defined as follows:
|
||||
|
||||
[[sample.gettingStarted]]
|
||||
include::code:SecurityConfig[]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user