Merge remote-tracking branch 'upstream/0.4.x' into main
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.security.oauth2.server.authorization.authentication;
|
package org.springframework.security.oauth2.server.authorization.authentication;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ public final class OAuth2ClientCredentialsAuthenticationProvider implements Auth
|
|||||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
|
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> authorizedScopes = registeredClient.getScopes(); // Default to configured scopes
|
Set<String> authorizedScopes = Collections.emptySet();
|
||||||
if (!CollectionUtils.isEmpty(clientCredentialsAuthentication.getScopes())) {
|
if (!CollectionUtils.isEmpty(clientCredentialsAuthentication.getScopes())) {
|
||||||
for (String requestedScope : clientCredentialsAuthentication.getScopes()) {
|
for (String requestedScope : clientCredentialsAuthentication.getScopes()) {
|
||||||
if (!registeredClient.getScopes().contains(requestedScope)) {
|
if (!registeredClient.getScopes().contains(requestedScope)) {
|
||||||
|
|||||||
@@ -211,6 +211,22 @@ public class OAuth2ClientCredentialsAuthenticationProviderTests {
|
|||||||
assertThat(accessTokenAuthentication.getAccessToken().getScopes()).isEqualTo(requestedScope);
|
assertThat(accessTokenAuthentication.getAccessToken().getScopes()).isEqualTo(requestedScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void authenticateWhenNoScopeRequestedThenAccessTokenDoesNotContainScope() {
|
||||||
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
|
||||||
|
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||||
|
registeredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, registeredClient.getClientSecret());
|
||||||
|
OAuth2ClientCredentialsAuthenticationToken authentication =
|
||||||
|
new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal, null, null);
|
||||||
|
|
||||||
|
when(this.jwtEncoder.encode(any()))
|
||||||
|
.thenReturn(createJwt(Collections.singleton("mapped-scoped")));
|
||||||
|
|
||||||
|
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
|
||||||
|
(OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||||
|
assertThat(accessTokenAuthentication.getAccessToken().getScopes()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void authenticateWhenAccessTokenNotGeneratedThenThrowOAuth2AuthenticationException() {
|
public void authenticateWhenAccessTokenNotGeneratedThenThrowOAuth2AuthenticationException() {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
|
||||||
|
|||||||
@@ -28,14 +28,17 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
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.oauth2.core.AuthorizationGrantType;
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService;
|
import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
||||||
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
|
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
|
||||||
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
|
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
|
||||||
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
|
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
|
||||||
import org.springframework.security.oauth2.server.authorization.settings.ProviderSettings;
|
import org.springframework.security.oauth2.server.authorization.settings.ProviderSettings;
|
||||||
@@ -72,6 +75,7 @@ public class AuthorizationServerConfig {
|
|||||||
.exceptionHandling(exceptions ->
|
.exceptionHandling(exceptions ->
|
||||||
exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
|
exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
|
||||||
)
|
)
|
||||||
|
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
|
||||||
.apply(authorizationServerConfigurer);
|
.apply(authorizationServerConfigurer);
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
@@ -89,6 +93,7 @@ public class AuthorizationServerConfig {
|
|||||||
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
|
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
|
||||||
.redirectUri("http://127.0.0.1:8080/authorized")
|
.redirectUri("http://127.0.0.1:8080/authorized")
|
||||||
.scope(OidcScopes.OPENID)
|
.scope(OidcScopes.OPENID)
|
||||||
|
.scope(OidcScopes.PROFILE)
|
||||||
.scope("message.read")
|
.scope("message.read")
|
||||||
.scope("message.write")
|
.scope("message.write")
|
||||||
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
|
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
|
||||||
@@ -104,6 +109,11 @@ public class AuthorizationServerConfig {
|
|||||||
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
|
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
|
||||||
|
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ProviderSettings providerSettings() {
|
public ProviderSettings providerSettings() {
|
||||||
return ProviderSettings.builder().issuer("http://localhost:9000").build();
|
return ProviderSettings.builder().issuer("http://localhost:9000").build();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2020-2021 the original author or authors.
|
* Copyright 2020-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -23,6 +23,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||||
@@ -66,6 +67,9 @@ public class AuthorizationConsentController {
|
|||||||
authorizedScopes = Collections.emptySet();
|
authorizedScopes = Collections.emptySet();
|
||||||
}
|
}
|
||||||
for (String requestedScope : StringUtils.delimitedListToStringArray(scope, " ")) {
|
for (String requestedScope : StringUtils.delimitedListToStringArray(scope, " ")) {
|
||||||
|
if (OidcScopes.OPENID.equals(requestedScope)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (authorizedScopes.contains(requestedScope)) {
|
if (authorizedScopes.contains(requestedScope)) {
|
||||||
previouslyApprovedScopes.add(requestedScope);
|
previouslyApprovedScopes.add(requestedScope);
|
||||||
} else {
|
} else {
|
||||||
@@ -95,6 +99,10 @@ public class AuthorizationConsentController {
|
|||||||
private static final String DEFAULT_DESCRIPTION = "UNKNOWN SCOPE - We cannot provide information about this permission, use caution when granting this.";
|
private static final String DEFAULT_DESCRIPTION = "UNKNOWN SCOPE - We cannot provide information about this permission, use caution when granting this.";
|
||||||
private static final Map<String, String> scopeDescriptions = new HashMap<>();
|
private static final Map<String, String> scopeDescriptions = new HashMap<>();
|
||||||
static {
|
static {
|
||||||
|
scopeDescriptions.put(
|
||||||
|
OidcScopes.PROFILE,
|
||||||
|
"This application will be able to read your profile information."
|
||||||
|
);
|
||||||
scopeDescriptions.put(
|
scopeDescriptions.put(
|
||||||
"message.read",
|
"message.read",
|
||||||
"This application will be able to read your message."
|
"This application will be able to read your message."
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2020-2021 the original author or authors.
|
* Copyright 2020-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -95,7 +95,7 @@ public class CustomConsentAuthorizationServerTests {
|
|||||||
assertThat(scope.isChecked()).isTrue();
|
assertThat(scope.isChecked()).isTrue();
|
||||||
scopeIds.add(scope.getId());
|
scopeIds.add(scope.getId());
|
||||||
});
|
});
|
||||||
assertThat(scopeIds).containsExactlyInAnyOrder("openid", "message.read", "message.write");
|
assertThat(scopeIds).containsExactlyInAnyOrder("message.read", "message.write");
|
||||||
|
|
||||||
DomElement submitConsentButton = consentPage.querySelector("button[id='submit-consent']");
|
DomElement submitConsentButton = consentPage.querySelector("button[id='submit-consent']");
|
||||||
this.webClient.getOptions().setRedirectEnabled(false);
|
this.webClient.getOptions().setRedirectEnabled(false);
|
||||||
|
|||||||
@@ -32,9 +32,11 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
|
|||||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
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.oauth2.core.AuthorizationGrantType;
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;
|
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;
|
||||||
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
|
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
||||||
@@ -63,7 +65,8 @@ public class AuthorizationServerConfig {
|
|||||||
http
|
http
|
||||||
.exceptionHandling(exceptions ->
|
.exceptionHandling(exceptions ->
|
||||||
exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
|
exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
|
||||||
);
|
)
|
||||||
|
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
@@ -81,6 +84,7 @@ public class AuthorizationServerConfig {
|
|||||||
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
|
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
|
||||||
.redirectUri("http://127.0.0.1:8080/authorized")
|
.redirectUri("http://127.0.0.1:8080/authorized")
|
||||||
.scope(OidcScopes.OPENID)
|
.scope(OidcScopes.OPENID)
|
||||||
|
.scope(OidcScopes.PROFILE)
|
||||||
.scope("message.read")
|
.scope("message.read")
|
||||||
.scope("message.write")
|
.scope("message.write")
|
||||||
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
|
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
|
||||||
@@ -111,6 +115,11 @@ public class AuthorizationServerConfig {
|
|||||||
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
|
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
|
||||||
|
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ProviderSettings providerSettings() {
|
public ProviderSettings providerSettings() {
|
||||||
return ProviderSettings.builder().issuer("http://localhost:9000").build();
|
return ProviderSettings.builder().issuer("http://localhost:9000").build();
|
||||||
|
|||||||
@@ -34,9 +34,11 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
|
|||||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
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.oauth2.core.AuthorizationGrantType;
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;
|
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;
|
||||||
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
|
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
||||||
@@ -62,6 +64,7 @@ public class AuthorizationServerConfig {
|
|||||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||||
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
|
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
|
||||||
|
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
|
||||||
http.apply(new FederatedIdentityConfigurer());
|
http.apply(new FederatedIdentityConfigurer());
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
@@ -84,6 +87,7 @@ public class AuthorizationServerConfig {
|
|||||||
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
|
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
|
||||||
.redirectUri("http://127.0.0.1:8080/authorized")
|
.redirectUri("http://127.0.0.1:8080/authorized")
|
||||||
.scope(OidcScopes.OPENID)
|
.scope(OidcScopes.OPENID)
|
||||||
|
.scope(OidcScopes.PROFILE)
|
||||||
.scope("message.read")
|
.scope("message.read")
|
||||||
.scope("message.write")
|
.scope("message.write")
|
||||||
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
|
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
|
||||||
@@ -114,6 +118,11 @@ public class AuthorizationServerConfig {
|
|||||||
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
|
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
|
||||||
|
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ProviderSettings providerSettings() {
|
public ProviderSettings providerSettings() {
|
||||||
return ProviderSettings.builder().issuer("http://localhost:9000").build();
|
return ProviderSettings.builder().issuer("http://localhost:9000").build();
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ spring:
|
|||||||
client-secret: secret
|
client-secret: secret
|
||||||
authorization-grant-type: authorization_code
|
authorization-grant-type: authorization_code
|
||||||
redirect-uri: "http://127.0.0.1:8080/login/oauth2/code/{registrationId}"
|
redirect-uri: "http://127.0.0.1:8080/login/oauth2/code/{registrationId}"
|
||||||
scope: openid
|
scope: openid, profile
|
||||||
client-name: messaging-client-oidc
|
client-name: messaging-client-oidc
|
||||||
messaging-client-authorization-code:
|
messaging-client-authorization-code:
|
||||||
provider: spring
|
provider: spring
|
||||||
|
|||||||
Reference in New Issue
Block a user