mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-16 23:33:31 +00:00
Rename ClientRegistration.clientAlias -> registrationId
Fixes gh-4575
This commit is contained in:
parent
38be35677d
commit
814742fef6
@ -44,7 +44,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.springframework.security.oauth2.client.web.AuthorizationCodeRequestRedirectFilter.CLIENT_ALIAS_URI_VARIABLE_NAME;
|
import static org.springframework.security.oauth2.client.web.AuthorizationCodeRequestRedirectFilter.REGISTRATION_ID_URI_VARIABLE_NAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
@ -244,10 +244,10 @@ public final class OAuth2LoginConfigurer<H extends HttpSecurityBuilder<H>> exten
|
|||||||
RequestMatcher authorizationRequestMatcher = OAuth2LoginConfigurer.this.authorizationCodeRequestRedirectFilterConfigurer.getAuthorizationRequestMatcher();
|
RequestMatcher authorizationRequestMatcher = OAuth2LoginConfigurer.this.authorizationCodeRequestRedirectFilterConfigurer.getAuthorizationRequestMatcher();
|
||||||
if (authorizationRequestMatcher != null && AntPathRequestMatcher.class.isAssignableFrom(authorizationRequestMatcher.getClass())) {
|
if (authorizationRequestMatcher != null && AntPathRequestMatcher.class.isAssignableFrom(authorizationRequestMatcher.getClass())) {
|
||||||
String authorizationRequestPattern = ((AntPathRequestMatcher)authorizationRequestMatcher).getPattern();
|
String authorizationRequestPattern = ((AntPathRequestMatcher)authorizationRequestMatcher).getPattern();
|
||||||
String clientAliasTemplateVariable = "{" + CLIENT_ALIAS_URI_VARIABLE_NAME + "}";
|
String registrationIdTemplateVariable = "{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}";
|
||||||
if (authorizationRequestPattern.endsWith(clientAliasTemplateVariable)) {
|
if (authorizationRequestPattern.endsWith(registrationIdTemplateVariable)) {
|
||||||
authorizationRequestBaseUri = authorizationRequestPattern.substring(
|
authorizationRequestBaseUri = authorizationRequestPattern.substring(
|
||||||
0, authorizationRequestPattern.length() - clientAliasTemplateVariable.length() - 1);
|
0, authorizationRequestPattern.length() - registrationIdTemplateVariable.length() - 1);
|
||||||
} else {
|
} else {
|
||||||
authorizationRequestBaseUri = authorizationRequestPattern;
|
authorizationRequestBaseUri = authorizationRequestPattern;
|
||||||
}
|
}
|
||||||
@ -257,7 +257,7 @@ public final class OAuth2LoginConfigurer<H extends HttpSecurityBuilder<H>> exten
|
|||||||
|
|
||||||
Map<String, String> oauth2AuthenticationUrlToClientName = clientRegistrationRepository.getRegistrations().stream()
|
Map<String, String> oauth2AuthenticationUrlToClientName = clientRegistrationRepository.getRegistrations().stream()
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
e -> authorizationRequestBaseUri + "/" + e.getClientAlias(),
|
e -> authorizationRequestBaseUri + "/" + e.getRegistrationId(),
|
||||||
e -> e.getClientName()));
|
e -> e.getClientName()));
|
||||||
loginPageGeneratingFilter.setOauth2LoginEnabled(true);
|
loginPageGeneratingFilter.setOauth2LoginEnabled(true);
|
||||||
loginPageGeneratingFilter.setOauth2AuthenticationUrlToClientName(oauth2AuthenticationUrlToClientName);
|
loginPageGeneratingFilter.setOauth2AuthenticationUrlToClientName(oauth2AuthenticationUrlToClientName);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Google
|
# Google
|
||||||
spring.security.oauth2.client.templates.google.client-authentication-method=basic
|
spring.security.oauth2.client.templates.google.client-authentication-method=basic
|
||||||
spring.security.oauth2.client.templates.google.authorization-grant-type=authorization_code
|
spring.security.oauth2.client.templates.google.authorization-grant-type=authorization_code
|
||||||
spring.security.oauth2.client.templates.google.redirect-uri={scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}
|
spring.security.oauth2.client.templates.google.redirect-uri={scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{registrationId}
|
||||||
spring.security.oauth2.client.templates.google.scope=openid, profile, email, address, phone
|
spring.security.oauth2.client.templates.google.scope=openid, profile, email, address, phone
|
||||||
spring.security.oauth2.client.templates.google.authorization-uri=https://accounts.google.com/o/oauth2/v2/auth
|
spring.security.oauth2.client.templates.google.authorization-uri=https://accounts.google.com/o/oauth2/v2/auth
|
||||||
spring.security.oauth2.client.templates.google.token-uri=https://www.googleapis.com/oauth2/v4/token
|
spring.security.oauth2.client.templates.google.token-uri=https://www.googleapis.com/oauth2/v4/token
|
||||||
@ -13,7 +13,7 @@ spring.security.oauth2.client.templates.google.client-alias=google
|
|||||||
# GitHub
|
# GitHub
|
||||||
spring.security.oauth2.client.templates.github.client-authentication-method=basic
|
spring.security.oauth2.client.templates.github.client-authentication-method=basic
|
||||||
spring.security.oauth2.client.templates.github.authorization-grant-type=authorization_code
|
spring.security.oauth2.client.templates.github.authorization-grant-type=authorization_code
|
||||||
spring.security.oauth2.client.templates.github.redirect-uri={scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}
|
spring.security.oauth2.client.templates.github.redirect-uri={scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{registrationId}
|
||||||
spring.security.oauth2.client.templates.github.scope=user
|
spring.security.oauth2.client.templates.github.scope=user
|
||||||
spring.security.oauth2.client.templates.github.authorization-uri=https://github.com/login/oauth/authorize
|
spring.security.oauth2.client.templates.github.authorization-uri=https://github.com/login/oauth/authorize
|
||||||
spring.security.oauth2.client.templates.github.token-uri=https://github.com/login/oauth/access_token
|
spring.security.oauth2.client.templates.github.token-uri=https://github.com/login/oauth/access_token
|
||||||
@ -25,7 +25,7 @@ spring.security.oauth2.client.templates.github.client-alias=github
|
|||||||
# Facebook
|
# Facebook
|
||||||
spring.security.oauth2.client.templates.facebook.client-authentication-method=post
|
spring.security.oauth2.client.templates.facebook.client-authentication-method=post
|
||||||
spring.security.oauth2.client.templates.facebook.authorization-grant-type=authorization_code
|
spring.security.oauth2.client.templates.facebook.authorization-grant-type=authorization_code
|
||||||
spring.security.oauth2.client.templates.facebook.redirect-uri={scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}
|
spring.security.oauth2.client.templates.facebook.redirect-uri={scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{registrationId}
|
||||||
spring.security.oauth2.client.templates.facebook.scope=public_profile, email
|
spring.security.oauth2.client.templates.facebook.scope=public_profile, email
|
||||||
spring.security.oauth2.client.templates.facebook.authorization-uri=https://www.facebook.com/v2.8/dialog/oauth
|
spring.security.oauth2.client.templates.facebook.authorization-uri=https://www.facebook.com/v2.8/dialog/oauth
|
||||||
spring.security.oauth2.client.templates.facebook.token-uri=https://graph.facebook.com/v2.8/oauth/access_token
|
spring.security.oauth2.client.templates.facebook.token-uri=https://graph.facebook.com/v2.8/oauth/access_token
|
||||||
@ -37,7 +37,7 @@ spring.security.oauth2.client.templates.facebook.client-alias=facebook
|
|||||||
# Okta
|
# Okta
|
||||||
spring.security.oauth2.client.templates.okta.client-authentication-method=basic
|
spring.security.oauth2.client.templates.okta.client-authentication-method=basic
|
||||||
spring.security.oauth2.client.templates.okta.authorization-grant-type=authorization_code
|
spring.security.oauth2.client.templates.okta.authorization-grant-type=authorization_code
|
||||||
spring.security.oauth2.client.templates.okta.redirect-uri={scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}
|
spring.security.oauth2.client.templates.okta.redirect-uri={scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{registrationId}
|
||||||
spring.security.oauth2.client.templates.okta.scope=openid, profile, email, address, phone
|
spring.security.oauth2.client.templates.okta.scope=openid, profile, email, address, phone
|
||||||
spring.security.oauth2.client.templates.okta.client-name=Okta
|
spring.security.oauth2.client.templates.okta.client-name=Okta
|
||||||
spring.security.oauth2.client.templates.okta.client-alias=okta
|
spring.security.oauth2.client.templates.okta.client-alias=okta
|
||||||
|
@ -33,6 +33,7 @@ import java.util.Set;
|
|||||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-2">Section 2 Client Registration</a>
|
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-2">Section 2 Client Registration</a>
|
||||||
*/
|
*/
|
||||||
public class ClientRegistration {
|
public class ClientRegistration {
|
||||||
|
private String registrationId;
|
||||||
private String clientId;
|
private String clientId;
|
||||||
private String clientSecret;
|
private String clientSecret;
|
||||||
private ClientAuthenticationMethod clientAuthenticationMethod = ClientAuthenticationMethod.BASIC;
|
private ClientAuthenticationMethod clientAuthenticationMethod = ClientAuthenticationMethod.BASIC;
|
||||||
@ -41,11 +42,18 @@ public class ClientRegistration {
|
|||||||
private Set<String> scope = Collections.emptySet();
|
private Set<String> scope = Collections.emptySet();
|
||||||
private ProviderDetails providerDetails = new ProviderDetails();
|
private ProviderDetails providerDetails = new ProviderDetails();
|
||||||
private String clientName;
|
private String clientName;
|
||||||
private String clientAlias;
|
|
||||||
|
|
||||||
protected ClientRegistration() {
|
protected ClientRegistration() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRegistrationId() {
|
||||||
|
return this.registrationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setRegistrationId(String registrationId) {
|
||||||
|
this.registrationId = registrationId;
|
||||||
|
}
|
||||||
|
|
||||||
public String getClientId() {
|
public String getClientId() {
|
||||||
return this.clientId;
|
return this.clientId;
|
||||||
}
|
}
|
||||||
@ -110,14 +118,6 @@ public class ClientRegistration {
|
|||||||
this.clientName = clientName;
|
this.clientName = clientName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getClientAlias() {
|
|
||||||
return this.clientAlias;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setClientAlias(String clientAlias) {
|
|
||||||
this.clientAlias = clientAlias;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ProviderDetails {
|
public class ProviderDetails {
|
||||||
private String authorizationUri;
|
private String authorizationUri;
|
||||||
private String tokenUri;
|
private String tokenUri;
|
||||||
@ -185,6 +185,7 @@ public class ClientRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
protected String registrationId;
|
||||||
protected String clientId;
|
protected String clientId;
|
||||||
protected String clientSecret;
|
protected String clientSecret;
|
||||||
protected ClientAuthenticationMethod clientAuthenticationMethod = ClientAuthenticationMethod.BASIC;
|
protected ClientAuthenticationMethod clientAuthenticationMethod = ClientAuthenticationMethod.BASIC;
|
||||||
@ -197,14 +198,14 @@ public class ClientRegistration {
|
|||||||
protected String userNameAttributeName;
|
protected String userNameAttributeName;
|
||||||
protected String jwkSetUri;
|
protected String jwkSetUri;
|
||||||
protected String clientName;
|
protected String clientName;
|
||||||
protected String clientAlias;
|
|
||||||
|
|
||||||
public Builder(String clientId) {
|
public Builder(String registrationId) {
|
||||||
this.clientId = clientId;
|
this.registrationId = registrationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder(ClientRegistrationProperties clientRegistrationProperties) {
|
public Builder(ClientRegistrationProperties clientRegistrationProperties) {
|
||||||
this(clientRegistrationProperties.getClientId());
|
this(clientRegistrationProperties.getRegistrationId());
|
||||||
|
this.clientId(clientRegistrationProperties.getClientId());
|
||||||
this.clientSecret(clientRegistrationProperties.getClientSecret());
|
this.clientSecret(clientRegistrationProperties.getClientSecret());
|
||||||
this.clientAuthenticationMethod(clientRegistrationProperties.getClientAuthenticationMethod());
|
this.clientAuthenticationMethod(clientRegistrationProperties.getClientAuthenticationMethod());
|
||||||
this.authorizationGrantType(clientRegistrationProperties.getAuthorizationGrantType());
|
this.authorizationGrantType(clientRegistrationProperties.getAuthorizationGrantType());
|
||||||
@ -218,11 +219,11 @@ public class ClientRegistration {
|
|||||||
this.userNameAttributeName(clientRegistrationProperties.getUserNameAttributeName());
|
this.userNameAttributeName(clientRegistrationProperties.getUserNameAttributeName());
|
||||||
this.jwkSetUri(clientRegistrationProperties.getJwkSetUri());
|
this.jwkSetUri(clientRegistrationProperties.getJwkSetUri());
|
||||||
this.clientName(clientRegistrationProperties.getClientName());
|
this.clientName(clientRegistrationProperties.getClientName());
|
||||||
this.clientAlias(clientRegistrationProperties.getClientAlias());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder(ClientRegistration clientRegistration) {
|
public Builder(ClientRegistration clientRegistration) {
|
||||||
this(clientRegistration.getClientId());
|
this(clientRegistration.getRegistrationId());
|
||||||
|
this.clientId(clientRegistration.getClientId());
|
||||||
this.clientSecret(clientRegistration.getClientSecret());
|
this.clientSecret(clientRegistration.getClientSecret());
|
||||||
this.clientAuthenticationMethod(clientRegistration.getClientAuthenticationMethod());
|
this.clientAuthenticationMethod(clientRegistration.getClientAuthenticationMethod());
|
||||||
this.authorizationGrantType(clientRegistration.getAuthorizationGrantType());
|
this.authorizationGrantType(clientRegistration.getAuthorizationGrantType());
|
||||||
@ -236,7 +237,11 @@ public class ClientRegistration {
|
|||||||
this.userNameAttributeName(clientRegistration.getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName());
|
this.userNameAttributeName(clientRegistration.getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName());
|
||||||
this.jwkSetUri(clientRegistration.getProviderDetails().getJwkSetUri());
|
this.jwkSetUri(clientRegistration.getProviderDetails().getJwkSetUri());
|
||||||
this.clientName(clientRegistration.getClientName());
|
this.clientName(clientRegistration.getClientName());
|
||||||
this.clientAlias(clientRegistration.getClientAlias());
|
}
|
||||||
|
|
||||||
|
public Builder clientId(String clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder clientSecret(String clientSecret) {
|
public Builder clientSecret(String clientSecret) {
|
||||||
@ -297,11 +302,6 @@ public class ClientRegistration {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder clientAlias(String clientAlias) {
|
|
||||||
this.clientAlias = clientAlias;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientRegistration build() {
|
public ClientRegistration build() {
|
||||||
this.validateClientWithAuthorizationCodeGrantType();
|
this.validateClientWithAuthorizationCodeGrantType();
|
||||||
ClientRegistration clientRegistration = new ClientRegistration();
|
ClientRegistration clientRegistration = new ClientRegistration();
|
||||||
@ -310,6 +310,7 @@ public class ClientRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void setProperties(ClientRegistration clientRegistration) {
|
protected void setProperties(ClientRegistration clientRegistration) {
|
||||||
|
clientRegistration.setRegistrationId(this.registrationId);
|
||||||
clientRegistration.setClientId(this.clientId);
|
clientRegistration.setClientId(this.clientId);
|
||||||
clientRegistration.setClientSecret(this.clientSecret);
|
clientRegistration.setClientSecret(this.clientSecret);
|
||||||
clientRegistration.setClientAuthenticationMethod(this.clientAuthenticationMethod);
|
clientRegistration.setClientAuthenticationMethod(this.clientAuthenticationMethod);
|
||||||
@ -326,12 +327,12 @@ public class ClientRegistration {
|
|||||||
clientRegistration.setProviderDetails(providerDetails);
|
clientRegistration.setProviderDetails(providerDetails);
|
||||||
|
|
||||||
clientRegistration.setClientName(this.clientName);
|
clientRegistration.setClientName(this.clientName);
|
||||||
clientRegistration.setClientAlias(this.clientAlias);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void validateClientWithAuthorizationCodeGrantType() {
|
protected void validateClientWithAuthorizationCodeGrantType() {
|
||||||
Assert.isTrue(AuthorizationGrantType.AUTHORIZATION_CODE.equals(this.authorizationGrantType),
|
Assert.isTrue(AuthorizationGrantType.AUTHORIZATION_CODE.equals(this.authorizationGrantType),
|
||||||
"authorizationGrantType must be " + AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
"authorizationGrantType must be " + AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
||||||
|
Assert.hasText(this.registrationId, "registrationId cannot be empty");
|
||||||
Assert.hasText(this.clientId, "clientId cannot be empty");
|
Assert.hasText(this.clientId, "clientId cannot be empty");
|
||||||
Assert.hasText(this.clientSecret, "clientSecret cannot be empty");
|
Assert.hasText(this.clientSecret, "clientSecret cannot be empty");
|
||||||
Assert.notNull(this.clientAuthenticationMethod, "clientAuthenticationMethod cannot be null");
|
Assert.notNull(this.clientAuthenticationMethod, "clientAuthenticationMethod cannot be null");
|
||||||
@ -341,7 +342,7 @@ public class ClientRegistration {
|
|||||||
Assert.hasText(this.tokenUri, "tokenUri cannot be empty");
|
Assert.hasText(this.tokenUri, "tokenUri cannot be empty");
|
||||||
Assert.hasText(this.userInfoUri, "userInfoUri cannot be empty");
|
Assert.hasText(this.userInfoUri, "userInfoUri cannot be empty");
|
||||||
Assert.hasText(this.clientName, "clientName cannot be empty");
|
Assert.hasText(this.clientName, "clientName cannot be empty");
|
||||||
Assert.hasText(this.clientAlias, "clientAlias cannot be empty");
|
Assert.hasText(this.registrationId, "registrationId cannot be empty");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import java.util.Set;
|
|||||||
* @see ClientRegistration
|
* @see ClientRegistration
|
||||||
*/
|
*/
|
||||||
public class ClientRegistrationProperties {
|
public class ClientRegistrationProperties {
|
||||||
|
private String registrationId;
|
||||||
private String clientId;
|
private String clientId;
|
||||||
private String clientSecret;
|
private String clientSecret;
|
||||||
private ClientAuthenticationMethod clientAuthenticationMethod = ClientAuthenticationMethod.BASIC;
|
private ClientAuthenticationMethod clientAuthenticationMethod = ClientAuthenticationMethod.BASIC;
|
||||||
@ -45,8 +46,14 @@ public class ClientRegistrationProperties {
|
|||||||
private String userNameAttributeName;
|
private String userNameAttributeName;
|
||||||
private String jwkSetUri;
|
private String jwkSetUri;
|
||||||
private String clientName;
|
private String clientName;
|
||||||
private String clientAlias;
|
|
||||||
|
|
||||||
|
public String getRegistrationId() {
|
||||||
|
return this.registrationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegistrationId(String registrationId) {
|
||||||
|
this.registrationId = registrationId;
|
||||||
|
}
|
||||||
|
|
||||||
public String getClientId() {
|
public String getClientId() {
|
||||||
return this.clientId;
|
return this.clientId;
|
||||||
@ -143,12 +150,4 @@ public class ClientRegistrationProperties {
|
|||||||
public void setClientName(String clientName) {
|
public void setClientName(String clientName) {
|
||||||
this.clientName = clientName;
|
this.clientName = clientName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getClientAlias() {
|
|
||||||
return this.clientAlias;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClientAlias(String clientAlias) {
|
|
||||||
this.clientAlias = clientAlias;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,9 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface ClientRegistrationRepository {
|
public interface ClientRegistrationRepository {
|
||||||
|
|
||||||
List<ClientRegistration> getRegistrationsByClientId(String clientId);
|
List<ClientRegistration> findByClientId(String clientId);
|
||||||
|
|
||||||
ClientRegistration getRegistrationByClientAlias(String clientAlias);
|
ClientRegistration findByRegistrationId(String registrationId);
|
||||||
|
|
||||||
List<ClientRegistration> getRegistrations();
|
List<ClientRegistration> getRegistrations();
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ import java.util.stream.Collectors;
|
|||||||
* @see ClientRegistration
|
* @see ClientRegistration
|
||||||
*/
|
*/
|
||||||
public final class InMemoryClientRegistrationRepository implements ClientRegistrationRepository {
|
public final class InMemoryClientRegistrationRepository implements ClientRegistrationRepository {
|
||||||
private final ClientRegistrationIdentifierStrategy<String> identifierStrategy = new ClientAliasIdentifierStrategy();
|
private final ClientRegistrationIdentifierStrategy<String> identifierStrategy = new RegistrationIdIdentifierStrategy();
|
||||||
private final Map<String, ClientRegistration> registrations;
|
private final Map<String, ClientRegistration> registrations;
|
||||||
|
|
||||||
public InMemoryClientRegistrationRepository(List<ClientRegistration> registrations) {
|
public InMemoryClientRegistrationRepository(List<ClientRegistration> registrations) {
|
||||||
@ -49,7 +49,7 @@ public final class InMemoryClientRegistrationRepository implements ClientRegistr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ClientRegistration> getRegistrationsByClientId(String clientId) {
|
public List<ClientRegistration> findByClientId(String clientId) {
|
||||||
Assert.hasText(clientId, "clientId cannot be empty");
|
Assert.hasText(clientId, "clientId cannot be empty");
|
||||||
return this.registrations.values().stream()
|
return this.registrations.values().stream()
|
||||||
.filter(registration -> registration.getClientId().equals(clientId))
|
.filter(registration -> registration.getClientId().equals(clientId))
|
||||||
@ -57,10 +57,10 @@ public final class InMemoryClientRegistrationRepository implements ClientRegistr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientRegistration getRegistrationByClientAlias(String clientAlias) {
|
public ClientRegistration findByRegistrationId(String registrationId) {
|
||||||
Assert.hasText(clientAlias, "clientAlias cannot be empty");
|
Assert.hasText(registrationId, "registrationId cannot be empty");
|
||||||
return this.registrations.values().stream()
|
return this.registrations.values().stream()
|
||||||
.filter(registration -> registration.getClientAlias().equals(clientAlias))
|
.filter(registration -> registration.getRegistrationId().equals(registrationId))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
@ -19,17 +19,17 @@ import org.springframework.util.Assert;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link ClientRegistrationIdentifierStrategy} that identifies a {@link ClientRegistration}
|
* A {@link ClientRegistrationIdentifierStrategy} that identifies a {@link ClientRegistration}
|
||||||
* using the {@link ClientRegistration#getClientAlias()}.
|
* using the {@link ClientRegistration#getRegistrationId()}.
|
||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
* @see ClientRegistration
|
* @see ClientRegistration
|
||||||
*/
|
*/
|
||||||
public class ClientAliasIdentifierStrategy implements ClientRegistrationIdentifierStrategy<String> {
|
public class RegistrationIdIdentifierStrategy implements ClientRegistrationIdentifierStrategy<String> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIdentifier(ClientRegistration clientRegistration) {
|
public String getIdentifier(ClientRegistration clientRegistration) {
|
||||||
Assert.notNull(clientRegistration, "clientRegistration cannot be null");
|
Assert.notNull(clientRegistration, "clientRegistration cannot be null");
|
||||||
return clientRegistration.getClientAlias();
|
return clientRegistration.getRegistrationId();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -77,9 +77,6 @@ public final class InMemoryAccessTokenRepository implements SecurityTokenReposit
|
|||||||
// Access Token Response attributes
|
// Access Token Response attributes
|
||||||
builder.append("[").append(clientRegistration.getScope().toString()).append("]");
|
builder.append("[").append(clientRegistration.getScope().toString()).append("]");
|
||||||
|
|
||||||
// Client alias is unique as well
|
|
||||||
builder.append("[").append(clientRegistration.getClientAlias()).append("]");
|
|
||||||
|
|
||||||
return Base64.getEncoder().encodeToString(builder.toString().getBytes());
|
return Base64.getEncoder().encodeToString(builder.toString().getBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,8 +111,8 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public class AuthorizationCodeAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
|
public class AuthorizationCodeAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
|
||||||
public static final String DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI = "/oauth2/authorize/code";
|
public static final String DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI = "/oauth2/authorize/code";
|
||||||
public static final String CLIENT_ALIAS_URI_VARIABLE_NAME = "clientAlias";
|
public static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId";
|
||||||
public static final String DEFAULT_AUTHORIZATION_RESPONSE_URI = DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI + "/{" + CLIENT_ALIAS_URI_VARIABLE_NAME + "}";
|
public static final String DEFAULT_AUTHORIZATION_RESPONSE_URI = DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI + "/{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}";
|
||||||
private static final String AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE = "authorization_request_not_found";
|
private static final String AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE = "authorization_request_not_found";
|
||||||
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
|
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
|
||||||
private static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter";
|
private static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter";
|
||||||
@ -141,11 +141,11 @@ public class AuthorizationCodeAuthenticationProcessingFilter extends AbstractAut
|
|||||||
|
|
||||||
AuthorizationRequestAttributes matchingAuthorizationRequest = this.resolveAuthorizationRequest(request);
|
AuthorizationRequestAttributes matchingAuthorizationRequest = this.resolveAuthorizationRequest(request);
|
||||||
|
|
||||||
String clientAlias = ((RequestVariablesExtractor)this.getAuthorizationResponseMatcher())
|
String registrationId = ((RequestVariablesExtractor)this.getAuthorizationResponseMatcher())
|
||||||
.extractUriTemplateVariables(request).get(CLIENT_ALIAS_URI_VARIABLE_NAME);
|
.extractUriTemplateVariables(request).get(REGISTRATION_ID_URI_VARIABLE_NAME);
|
||||||
ClientRegistration clientRegistration = null;
|
ClientRegistration clientRegistration = null;
|
||||||
if (!StringUtils.isEmpty(clientAlias)) {
|
if (!StringUtils.isEmpty(registrationId)) {
|
||||||
clientRegistration = this.getClientRegistrationRepository().getRegistrationByClientAlias(clientAlias);
|
clientRegistration = this.getClientRegistrationRepository().findByRegistrationId(registrationId);
|
||||||
}
|
}
|
||||||
if (clientRegistration == null || !matchingAuthorizationRequest.getClientId().equals(clientRegistration.getClientId())) {
|
if (clientRegistration == null || !matchingAuthorizationRequest.getClientId().equals(clientRegistration.getClientId())) {
|
||||||
OAuth2Error oauth2Error = new OAuth2Error(OAuth2Error.INVALID_REQUEST_ERROR_CODE);
|
OAuth2Error oauth2Error = new OAuth2Error(OAuth2Error.INVALID_REQUEST_ERROR_CODE);
|
||||||
|
@ -61,8 +61,8 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class AuthorizationCodeRequestRedirectFilter extends OncePerRequestFilter {
|
public class AuthorizationCodeRequestRedirectFilter extends OncePerRequestFilter {
|
||||||
public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization/code";
|
public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization/code";
|
||||||
public static final String CLIENT_ALIAS_URI_VARIABLE_NAME = "clientAlias";
|
public static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId";
|
||||||
public static final String DEFAULT_AUTHORIZATION_REQUEST_URI = DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/{" + CLIENT_ALIAS_URI_VARIABLE_NAME + "}";
|
public static final String DEFAULT_AUTHORIZATION_REQUEST_URI = DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}";
|
||||||
private RequestMatcher authorizationRequestMatcher;
|
private RequestMatcher authorizationRequestMatcher;
|
||||||
private final ClientRegistrationRepository clientRegistrationRepository;
|
private final ClientRegistrationRepository clientRegistrationRepository;
|
||||||
private final AuthorizationRequestUriBuilder authorizationUriBuilder;
|
private final AuthorizationRequestUriBuilder authorizationUriBuilder;
|
||||||
@ -113,11 +113,11 @@ public class AuthorizationCodeRequestRedirectFilter extends OncePerRequestFilter
|
|||||||
protected void sendRedirectForAuthorizationCode(HttpServletRequest request, HttpServletResponse response)
|
protected void sendRedirectForAuthorizationCode(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
|
|
||||||
String clientAlias = ((RequestVariablesExtractor)this.authorizationRequestMatcher)
|
String registrationId = ((RequestVariablesExtractor)this.authorizationRequestMatcher)
|
||||||
.extractUriTemplateVariables(request).get(CLIENT_ALIAS_URI_VARIABLE_NAME);
|
.extractUriTemplateVariables(request).get(REGISTRATION_ID_URI_VARIABLE_NAME);
|
||||||
ClientRegistration clientRegistration = this.clientRegistrationRepository.getRegistrationByClientAlias(clientAlias);
|
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
|
||||||
if (clientRegistration == null) {
|
if (clientRegistration == null) {
|
||||||
throw new IllegalArgumentException("Invalid Client Identifier (Alias): " + clientAlias);
|
throw new IllegalArgumentException("Invalid Client Identifier (Registration Id): " + registrationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
String redirectUriStr = this.expandRedirectUri(request, clientRegistration);
|
String redirectUriStr = this.expandRedirectUri(request, clientRegistration);
|
||||||
@ -152,7 +152,7 @@ public class AuthorizationCodeRequestRedirectFilter extends OncePerRequestFilter
|
|||||||
uriVariables.put("serverName", request.getServerName());
|
uriVariables.put("serverName", request.getServerName());
|
||||||
uriVariables.put("serverPort", String.valueOf(request.getServerPort()));
|
uriVariables.put("serverPort", String.valueOf(request.getServerPort()));
|
||||||
uriVariables.put("contextPath", request.getContextPath());
|
uriVariables.put("contextPath", request.getContextPath());
|
||||||
uriVariables.put("clientAlias", clientRegistration.getClientAlias());
|
uriVariables.put("registrationId", clientRegistration.getRegistrationId());
|
||||||
|
|
||||||
return UriComponentsBuilder.fromUriString(clientRegistration.getRedirectUri())
|
return UriComponentsBuilder.fromUriString(clientRegistration.getRedirectUri())
|
||||||
.buildAndExpand(uriVariables)
|
.buildAndExpand(uriVariables)
|
||||||
|
@ -41,7 +41,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link AuthorizationCodeAuthenticationProcessingFilter}.
|
* Tests {@link AuthorizationCodeAuthenticationProcessingFilter}.
|
||||||
@ -247,7 +246,7 @@ public class AuthorizationCodeAuthenticationProcessingFilterTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MockHttpServletRequest setupRequest(ClientRegistration clientRegistration) {
|
private MockHttpServletRequest setupRequest(ClientRegistration clientRegistration) {
|
||||||
String requestURI = TestUtil.AUTHORIZE_BASE_URI + "/" + clientRegistration.getClientAlias();
|
String requestURI = TestUtil.AUTHORIZE_BASE_URI + "/" + clientRegistration.getRegistrationId();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestURI);
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestURI);
|
||||||
request.setScheme(TestUtil.DEFAULT_SCHEME);
|
request.setScheme(TestUtil.DEFAULT_SCHEME);
|
||||||
request.setServerName(TestUtil.DEFAULT_SERVER_NAME);
|
request.setServerName(TestUtil.DEFAULT_SERVER_NAME);
|
||||||
|
@ -31,7 +31,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link AuthorizationCodeRequestRedirectFilter}.
|
* Tests {@link AuthorizationCodeRequestRedirectFilter}.
|
||||||
@ -75,7 +74,7 @@ public class AuthorizationCodeRequestRedirectFilterTests {
|
|||||||
AuthorizationCodeRequestRedirectFilter filter =
|
AuthorizationCodeRequestRedirectFilter filter =
|
||||||
setupFilter(authorizationUri, clientRegistration);
|
setupFilter(authorizationUri, clientRegistration);
|
||||||
|
|
||||||
String requestUri = TestUtil.AUTHORIZATION_BASE_URI + "/" + clientRegistration.getClientAlias();
|
String requestUri = TestUtil.AUTHORIZATION_BASE_URI + "/" + clientRegistration.getRegistrationId();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
|
||||||
request.setServletPath(requestUri);
|
request.setServletPath(requestUri);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
@ -97,7 +96,7 @@ public class AuthorizationCodeRequestRedirectFilterTests {
|
|||||||
AuthorizationRequestRepository authorizationRequestRepository = new HttpSessionAuthorizationRequestRepository();
|
AuthorizationRequestRepository authorizationRequestRepository = new HttpSessionAuthorizationRequestRepository();
|
||||||
filter.setAuthorizationRequestRepository(authorizationRequestRepository);
|
filter.setAuthorizationRequestRepository(authorizationRequestRepository);
|
||||||
|
|
||||||
String requestUri = TestUtil.AUTHORIZATION_BASE_URI + "/" + clientRegistration.getClientAlias();
|
String requestUri = TestUtil.AUTHORIZATION_BASE_URI + "/" + clientRegistration.getRegistrationId();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
|
||||||
request.setServletPath(requestUri);
|
request.setServletPath(requestUri);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
@ -34,24 +34,24 @@ class TestUtil {
|
|||||||
static final String DEFAULT_SERVER_URL = DEFAULT_SCHEME + "://" + DEFAULT_SERVER_NAME + ":" + DEFAULT_SERVER_PORT;
|
static final String DEFAULT_SERVER_URL = DEFAULT_SCHEME + "://" + DEFAULT_SERVER_NAME + ":" + DEFAULT_SERVER_PORT;
|
||||||
static final String AUTHORIZATION_BASE_URI = "/oauth2/authorization/code";
|
static final String AUTHORIZATION_BASE_URI = "/oauth2/authorization/code";
|
||||||
static final String AUTHORIZE_BASE_URI = "/oauth2/authorize/code";
|
static final String AUTHORIZE_BASE_URI = "/oauth2/authorize/code";
|
||||||
static final String GOOGLE_CLIENT_ALIAS = "google";
|
static final String GOOGLE_REGISTRATION_ID = "google";
|
||||||
static final String GITHUB_CLIENT_ALIAS = "github";
|
static final String GITHUB_REGISTRATION_ID = "github";
|
||||||
|
|
||||||
static ClientRegistrationRepository clientRegistrationRepository(ClientRegistration... clientRegistrations) {
|
static ClientRegistrationRepository clientRegistrationRepository(ClientRegistration... clientRegistrations) {
|
||||||
return new InMemoryClientRegistrationRepository(Arrays.asList(clientRegistrations));
|
return new InMemoryClientRegistrationRepository(Arrays.asList(clientRegistrations));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ClientRegistration googleClientRegistration() {
|
static ClientRegistration googleClientRegistration() {
|
||||||
return googleClientRegistration(DEFAULT_SERVER_URL + AUTHORIZE_BASE_URI + "/" + GOOGLE_CLIENT_ALIAS);
|
return googleClientRegistration(DEFAULT_SERVER_URL + AUTHORIZE_BASE_URI + "/" + GOOGLE_REGISTRATION_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ClientRegistration googleClientRegistration(String redirectUri) {
|
static ClientRegistration googleClientRegistration(String redirectUri) {
|
||||||
ClientRegistrationProperties clientRegistrationProperties = new ClientRegistrationProperties();
|
ClientRegistrationProperties clientRegistrationProperties = new ClientRegistrationProperties();
|
||||||
|
clientRegistrationProperties.setRegistrationId(GOOGLE_REGISTRATION_ID);
|
||||||
clientRegistrationProperties.setClientId("google-client-id");
|
clientRegistrationProperties.setClientId("google-client-id");
|
||||||
clientRegistrationProperties.setClientSecret("secret");
|
clientRegistrationProperties.setClientSecret("secret");
|
||||||
clientRegistrationProperties.setAuthorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
|
clientRegistrationProperties.setAuthorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||||
clientRegistrationProperties.setClientName("Google Client");
|
clientRegistrationProperties.setClientName("Google Client");
|
||||||
clientRegistrationProperties.setClientAlias(GOOGLE_CLIENT_ALIAS);
|
|
||||||
clientRegistrationProperties.setAuthorizationUri("https://accounts.google.com/o/oauth2/auth");
|
clientRegistrationProperties.setAuthorizationUri("https://accounts.google.com/o/oauth2/auth");
|
||||||
clientRegistrationProperties.setTokenUri("https://accounts.google.com/o/oauth2/token");
|
clientRegistrationProperties.setTokenUri("https://accounts.google.com/o/oauth2/token");
|
||||||
clientRegistrationProperties.setUserInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
|
clientRegistrationProperties.setUserInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
|
||||||
@ -61,16 +61,16 @@ class TestUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ClientRegistration githubClientRegistration() {
|
static ClientRegistration githubClientRegistration() {
|
||||||
return githubClientRegistration(DEFAULT_SERVER_URL + AUTHORIZE_BASE_URI + "/" + GITHUB_CLIENT_ALIAS);
|
return githubClientRegistration(DEFAULT_SERVER_URL + AUTHORIZE_BASE_URI + "/" + GITHUB_REGISTRATION_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ClientRegistration githubClientRegistration(String redirectUri) {
|
static ClientRegistration githubClientRegistration(String redirectUri) {
|
||||||
ClientRegistrationProperties clientRegistrationProperties = new ClientRegistrationProperties();
|
ClientRegistrationProperties clientRegistrationProperties = new ClientRegistrationProperties();
|
||||||
|
clientRegistrationProperties.setRegistrationId(GITHUB_REGISTRATION_ID);
|
||||||
clientRegistrationProperties.setClientId("github-client-id");
|
clientRegistrationProperties.setClientId("github-client-id");
|
||||||
clientRegistrationProperties.setClientSecret("secret");
|
clientRegistrationProperties.setClientSecret("secret");
|
||||||
clientRegistrationProperties.setAuthorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
|
clientRegistrationProperties.setAuthorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||||
clientRegistrationProperties.setClientName("GitHub Client");
|
clientRegistrationProperties.setClientName("GitHub Client");
|
||||||
clientRegistrationProperties.setClientAlias(GITHUB_CLIENT_ALIAS);
|
|
||||||
clientRegistrationProperties.setAuthorizationUri("https://github.com/login/oauth/authorize");
|
clientRegistrationProperties.setAuthorizationUri("https://github.com/login/oauth/authorize");
|
||||||
clientRegistrationProperties.setTokenUri("https://github.com/login/oauth/access_token");
|
clientRegistrationProperties.setTokenUri("https://github.com/login/oauth/access_token");
|
||||||
clientRegistrationProperties.setUserInfoUri("https://api.github.com/user");
|
clientRegistrationProperties.setUserInfoUri("https://api.github.com/user");
|
||||||
|
@ -67,7 +67,7 @@ and have granted access to the OAuth Client _(created from the <<google-login-re
|
|||||||
|
|
||||||
For the sub-section, *_"Set a redirect URI"_*, ensure the *Authorised redirect URIs* is set to *http://localhost:8080/oauth2/authorize/code/google*
|
For the sub-section, *_"Set a redirect URI"_*, ensure the *Authorised redirect URIs* is set to *http://localhost:8080/oauth2/authorize/code/google*
|
||||||
|
|
||||||
TIP: The default redirect URI is *_"{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{clientAlias}"_*.
|
TIP: The default redirect URI is *_"{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{registrationId}"_*.
|
||||||
See <<oauth2-client-properties, OAuth client properties>> for more details on this default.
|
See <<oauth2-client-properties, OAuth client properties>> for more details on this default.
|
||||||
|
|
||||||
[[google-login-configure-application-yml]]
|
[[google-login-configure-application-yml]]
|
||||||
@ -93,7 +93,7 @@ Replace *${client-id}* and *${client-secret}* with the OAuth 2.0 credentials cre
|
|||||||
.OAuth client properties
|
.OAuth client properties
|
||||||
====
|
====
|
||||||
. *security.oauth2.client* is the *_base property prefix_* for OAuth client properties.
|
. *security.oauth2.client* is the *_base property prefix_* for OAuth client properties.
|
||||||
. Just below the *_base property prefix_* is the *_client property key_*, for example *security.oauth2.client.google*.
|
. Just below the *_base property prefix_* is the *_client property key_*, for example *security.oauth2.client.registrations.google*.
|
||||||
. At the base of the *_client property key_* are the properties for specifying the configuration for an OAuth Client.
|
. At the base of the *_client property key_* are the properties for specifying the configuration for an OAuth Client.
|
||||||
A list of these properties are detailed in <<oauth2-client-properties, OAuth client properties>>.
|
A list of these properties are detailed in <<oauth2-client-properties, OAuth client properties>>.
|
||||||
====
|
====
|
||||||
@ -133,7 +133,7 @@ While registering your application, ensure the *Authorization callback URL* is s
|
|||||||
NOTE: The *Authorization callback URL* (or redirect URI) is the path in the sample application that the end-user's user-agent is redirected back to after they have authenticated with GitHub
|
NOTE: The *Authorization callback URL* (or redirect URI) is the path in the sample application that the end-user's user-agent is redirected back to after they have authenticated with GitHub
|
||||||
and have granted access to the OAuth application on the *Authorize application* page.
|
and have granted access to the OAuth application on the *Authorize application* page.
|
||||||
|
|
||||||
TIP: The default redirect URI is *_"{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{clientAlias}"_*.
|
TIP: The default redirect URI is *_"{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{registrationId}"_*.
|
||||||
See <<oauth2-client-properties, OAuth client properties>> for more details on this default.
|
See <<oauth2-client-properties, OAuth client properties>> for more details on this default.
|
||||||
|
|
||||||
After completing the registration, you should have created a new *OAuth Application* with credentials consisting of a *Client ID* and *Client Secret*.
|
After completing the registration, you should have created a new *OAuth Application* with credentials consisting of a *Client ID* and *Client Secret*.
|
||||||
@ -161,7 +161,7 @@ Replace *${client-id}* and *${client-secret}* with the OAuth 2.0 credentials cre
|
|||||||
.OAuth client properties
|
.OAuth client properties
|
||||||
====
|
====
|
||||||
. *security.oauth2.client* is the *_base property prefix_* for OAuth client properties.
|
. *security.oauth2.client* is the *_base property prefix_* for OAuth client properties.
|
||||||
. Just below the *_base property prefix_* is the *_client property key_*, for example *security.oauth2.client.github*.
|
. Just below the *_base property prefix_* is the *_client property key_*, for example *security.oauth2.client.registrations.github*.
|
||||||
. At the base of the *_client property key_* are the properties for specifying the configuration for an OAuth Client.
|
. At the base of the *_client property key_* are the properties for specifying the configuration for an OAuth Client.
|
||||||
A list of these properties are detailed in <<oauth2-client-properties, OAuth client properties>>.
|
A list of these properties are detailed in <<oauth2-client-properties, OAuth client properties>>.
|
||||||
====
|
====
|
||||||
@ -210,7 +210,7 @@ For the field *Valid OAuth redirect URIs*, enter *http://localhost:8080/oauth2/a
|
|||||||
NOTE: The *OAuth redirect URI* is the path in the sample application that the end-user's user-agent is redirected back to after they have authenticated with Facebook
|
NOTE: The *OAuth redirect URI* is the path in the sample application that the end-user's user-agent is redirected back to after they have authenticated with Facebook
|
||||||
and have granted access to the application on the *Authorize application* page.
|
and have granted access to the application on the *Authorize application* page.
|
||||||
|
|
||||||
TIP: The default redirect URI is *_"{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{clientAlias}"_*.
|
TIP: The default redirect URI is *_"{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{registrationId}"_*.
|
||||||
See <<oauth2-client-properties, OAuth client properties>> for more details on this default.
|
See <<oauth2-client-properties, OAuth client properties>> for more details on this default.
|
||||||
|
|
||||||
Your application has now been assigned new OAuth 2.0 credentials under *App ID* and *App Secret*.
|
Your application has now been assigned new OAuth 2.0 credentials under *App ID* and *App Secret*.
|
||||||
@ -238,7 +238,7 @@ Replace *${app-id}* and *${app-secret}* with the OAuth 2.0 credentials created i
|
|||||||
.OAuth client properties
|
.OAuth client properties
|
||||||
====
|
====
|
||||||
. *security.oauth2.client* is the *_base property prefix_* for OAuth client properties.
|
. *security.oauth2.client* is the *_base property prefix_* for OAuth client properties.
|
||||||
. Just below the *_base property prefix_* is the *_client property key_*, for example *security.oauth2.client.facebook*.
|
. Just below the *_base property prefix_* is the *_client property key_*, for example *security.oauth2.client.registrations.facebook*.
|
||||||
. At the base of the *_client property key_* are the properties for specifying the configuration for an OAuth Client.
|
. At the base of the *_client property key_* are the properties for specifying the configuration for an OAuth Client.
|
||||||
A list of these properties are detailed in <<oauth2-client-properties, OAuth client properties>>.
|
A list of these properties are detailed in <<oauth2-client-properties, OAuth client properties>>.
|
||||||
====
|
====
|
||||||
@ -285,7 +285,7 @@ On the _"Configure OpenID Connect"_ page, enter *http://localhost:8080/oauth2/au
|
|||||||
NOTE: The *Redirect URI* is the path in the sample application that the end-user's user-agent is redirected back to after they have authenticated with Okta
|
NOTE: The *Redirect URI* is the path in the sample application that the end-user's user-agent is redirected back to after they have authenticated with Okta
|
||||||
and have granted access to the application on the *Authorize application* page.
|
and have granted access to the application on the *Authorize application* page.
|
||||||
|
|
||||||
TIP: The default redirect URI is *_"{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{clientAlias}"_*.
|
TIP: The default redirect URI is *_"{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{registrationId}"_*.
|
||||||
See <<oauth2-client-properties, OAuth client properties>> for more details on this default.
|
See <<oauth2-client-properties, OAuth client properties>> for more details on this default.
|
||||||
|
|
||||||
The next page presented displays the _"General"_ tab selected for the application.
|
The next page presented displays the _"General"_ tab selected for the application.
|
||||||
@ -326,7 +326,7 @@ As well, replace *${account-subdomain}* in _authorization-uri_, _token-uri_, _us
|
|||||||
.OAuth client properties
|
.OAuth client properties
|
||||||
====
|
====
|
||||||
. *security.oauth2.client* is the *_base property prefix_* for OAuth client properties.
|
. *security.oauth2.client* is the *_base property prefix_* for OAuth client properties.
|
||||||
. Just below the *_base property prefix_* is the *_client property key_*, for example *security.oauth2.client.okta*.
|
. Just below the *_base property prefix_* is the *_client property key_*, for example *security.oauth2.client.registrations.okta*.
|
||||||
. At the base of the *_client property key_* are the properties for specifying the configuration for an OAuth Client.
|
. At the base of the *_client property key_* are the properties for specifying the configuration for an OAuth Client.
|
||||||
A list of these properties are detailed in <<oauth2-client-properties, OAuth client properties>>.
|
A list of these properties are detailed in <<oauth2-client-properties, OAuth client properties>>.
|
||||||
====
|
====
|
||||||
@ -425,7 +425,7 @@ The following provides an overview of the Spring Boot auto-configuration classes
|
|||||||
*_org.springframework.boot.autoconfigure.security.oauth2.client.ClientRegistrationAutoConfiguration_*::
|
*_org.springframework.boot.autoconfigure.security.oauth2.client.ClientRegistrationAutoConfiguration_*::
|
||||||
`ClientRegistrationAutoConfiguration` is responsible for registering a `ClientRegistrationRepository` _bean_ with the `ApplicationContext`.
|
`ClientRegistrationAutoConfiguration` is responsible for registering a `ClientRegistrationRepository` _bean_ with the `ApplicationContext`.
|
||||||
The `ClientRegistrationRepository` is composed of one or more `ClientRegistration` instances, which are created from the OAuth client properties
|
The `ClientRegistrationRepository` is composed of one or more `ClientRegistration` instances, which are created from the OAuth client properties
|
||||||
configured in the `Environment` that are prefixed with `security.oauth2.client.[client-key]`, for example, `security.oauth2.client.google`.
|
configured in the `Environment` that are prefixed with `security.oauth2.client.registrations.[registration-id]`, for example, `security.oauth2.client.registrations.google`.
|
||||||
|
|
||||||
NOTE: `ClientRegistrationAutoConfiguration` also loads a _resource_ named *oauth2-clients-defaults.yml*,
|
NOTE: `ClientRegistrationAutoConfiguration` also loads a _resource_ named *oauth2-clients-defaults.yml*,
|
||||||
which provides a set of default client property values for a number of _well-known_ Providers.
|
which provides a set of default client property values for a number of _well-known_ Providers.
|
||||||
@ -446,7 +446,7 @@ The following specifies the common set of properties available for configuring a
|
|||||||
[TIP]
|
[TIP]
|
||||||
====
|
====
|
||||||
- *security.oauth2.client* is the *_base property prefix_* for OAuth client properties.
|
- *security.oauth2.client* is the *_base property prefix_* for OAuth client properties.
|
||||||
- Just below the *_base property prefix_* is the *_client property key_*, for example *security.oauth2.client.google*.
|
- Just below the *_base property prefix_* is the *_client property key_*, for example *security.oauth2.client.registrations.google*.
|
||||||
- At the base of the *_client property key_* are the properties for specifying the configuration for an OAuth Client.
|
- At the base of the *_client property key_* are the properties for specifying the configuration for an OAuth Client.
|
||||||
====
|
====
|
||||||
|
|
||||||
@ -456,7 +456,7 @@ The following specifies the common set of properties available for configuring a
|
|||||||
- *redirect-uri* - this is the client's _registered_ redirect URI that the _Authorization Server_ redirects the end-user's user-agent
|
- *redirect-uri* - this is the client's _registered_ redirect URI that the _Authorization Server_ redirects the end-user's user-agent
|
||||||
to after the end-user has authenticated and authorized access for the client.
|
to after the end-user has authenticated and authorized access for the client.
|
||||||
|
|
||||||
NOTE: The default redirect URI is _"{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{clientAlias}"_, which leverages *URI template variables*.
|
NOTE: The default redirect URI is _"{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{registrationId}"_, which leverages *URI template variables*.
|
||||||
|
|
||||||
- *scopes* - a comma-delimited string of scope(s) requested during the _Authorization Request_ flow, for example: _openid, email, profile_
|
- *scopes* - a comma-delimited string of scope(s) requested during the _Authorization Request_ flow, for example: _openid, email, profile_
|
||||||
|
|
||||||
@ -477,7 +477,7 @@ IMPORTANT: Standard _OAuth 2.0 Provider's_ may vary the naming of their *Name* a
|
|||||||
This is a *_required_* property for `DefaultOAuth2User`.
|
This is a *_required_* property for `DefaultOAuth2User`.
|
||||||
|
|
||||||
- *client-name* - this is a descriptive name used for the client. The name may be used in certain scenarios, for example, when displaying the name of the client in the _auto-generated login page_.
|
- *client-name* - this is a descriptive name used for the client. The name may be used in certain scenarios, for example, when displaying the name of the client in the _auto-generated login page_.
|
||||||
- *client-alias* - an _alias_ which uniquely identifies the client. It *must be* unique within a `ClientRegistrationRepository`.
|
- *registration-id* - an _id_ which uniquely identifies the client registration. It *must be* unique within a `ClientRegistrationRepository`.
|
||||||
|
|
||||||
[[oauth2-default-client-properties]]
|
[[oauth2-default-client-properties]]
|
||||||
=== Default client property values
|
=== Default client property values
|
||||||
@ -499,41 +499,37 @@ security:
|
|||||||
google:
|
google:
|
||||||
client-authentication-method: basic
|
client-authentication-method: basic
|
||||||
authorized-grant-type: authorization_code
|
authorized-grant-type: authorization_code
|
||||||
redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{clientAlias}"
|
redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{registrationId}"
|
||||||
scopes: openid, email, profile
|
scopes: openid, email, profile
|
||||||
authorization-uri: "https://accounts.google.com/o/oauth2/auth"
|
authorization-uri: "https://accounts.google.com/o/oauth2/auth"
|
||||||
token-uri: "https://accounts.google.com/o/oauth2/token"
|
token-uri: "https://accounts.google.com/o/oauth2/token"
|
||||||
user-info-uri: "https://www.googleapis.com/oauth2/v3/userinfo"
|
user-info-uri: "https://www.googleapis.com/oauth2/v3/userinfo"
|
||||||
jwk-set-uri: https://www.googleapis.com/oauth2/v3/certs
|
jwk-set-uri: https://www.googleapis.com/oauth2/v3/certs
|
||||||
client-name: Google
|
client-name: Google
|
||||||
client-alias: google
|
|
||||||
github:
|
github:
|
||||||
client-authentication-method: basic
|
client-authentication-method: basic
|
||||||
authorized-grant-type: authorization_code
|
authorized-grant-type: authorization_code
|
||||||
redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{clientAlias}"
|
redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{registrationId}"
|
||||||
scopes: user
|
scopes: user
|
||||||
authorization-uri: "https://github.com/login/oauth/authorize"
|
authorization-uri: "https://github.com/login/oauth/authorize"
|
||||||
token-uri: "https://github.com/login/oauth/access_token"
|
token-uri: "https://github.com/login/oauth/access_token"
|
||||||
user-info-uri: "https://api.github.com/user"
|
user-info-uri: "https://api.github.com/user"
|
||||||
client-name: GitHub
|
client-name: GitHub
|
||||||
client-alias: github
|
|
||||||
facebook:
|
facebook:
|
||||||
client-authentication-method: post
|
client-authentication-method: post
|
||||||
authorized-grant-type: authorization_code
|
authorized-grant-type: authorization_code
|
||||||
redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{clientAlias}"
|
redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{registrationId}"
|
||||||
scopes: public_profile, email
|
scopes: public_profile, email
|
||||||
authorization-uri: "https://www.facebook.com/v2.8/dialog/oauth"
|
authorization-uri: "https://www.facebook.com/v2.8/dialog/oauth"
|
||||||
token-uri: "https://graph.facebook.com/v2.8/oauth/access_token"
|
token-uri: "https://graph.facebook.com/v2.8/oauth/access_token"
|
||||||
user-info-uri: "https://graph.facebook.com/me"
|
user-info-uri: "https://graph.facebook.com/me"
|
||||||
client-name: Facebook
|
client-name: Facebook
|
||||||
client-alias: facebook
|
|
||||||
okta:
|
okta:
|
||||||
client-authentication-method: basic
|
client-authentication-method: basic
|
||||||
authorized-grant-type: authorization_code
|
authorized-grant-type: authorization_code
|
||||||
redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{clientAlias}"
|
redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{registrationId}"
|
||||||
scopes: openid, email, profile
|
scopes: openid, email, profile
|
||||||
client-name: Okta
|
client-name: Okta
|
||||||
client-alias: okta
|
|
||||||
----
|
----
|
||||||
|
|
||||||
= Appendix
|
= Appendix
|
||||||
@ -552,18 +548,17 @@ Let's assume we have a _properties file_ named *oauth2-clients.properties* on th
|
|||||||
.oauth2-clients.properties
|
.oauth2-clients.properties
|
||||||
[source,properties]
|
[source,properties]
|
||||||
----
|
----
|
||||||
security.oauth2.client.google.client-id=${client-id}
|
security.oauth2.client.registrations.google.client-id=${client-id}
|
||||||
security.oauth2.client.google.client-secret=${client-secret}
|
security.oauth2.client.registrations.google.client-secret=${client-secret}
|
||||||
security.oauth2.client.google.client-authentication-method=basic
|
security.oauth2.client.registrations.google.client-authentication-method=basic
|
||||||
security.oauth2.client.google.authorized-grant-type=authorization_code
|
security.oauth2.client.registrations.google.authorized-grant-type=authorization_code
|
||||||
security.oauth2.client.google.redirect-uri=http://localhost:8080/oauth2/authorize/code/google
|
security.oauth2.client.registrations.google.redirect-uri=http://localhost:8080/oauth2/authorize/code/google
|
||||||
security.oauth2.client.google.scopes=openid,email,profile
|
security.oauth2.client.registrations.google.scopes=openid,email,profile
|
||||||
security.oauth2.client.google.authorization-uri=https://accounts.google.com/o/oauth2/auth
|
security.oauth2.client.registrations.google.authorization-uri=https://accounts.google.com/o/oauth2/auth
|
||||||
security.oauth2.client.google.token-uri=https://accounts.google.com/o/oauth2/token
|
security.oauth2.client.registrations.google.token-uri=https://accounts.google.com/o/oauth2/token
|
||||||
security.oauth2.client.google.user-info-uri=https://www.googleapis.com/oauth2/v3/userinfo
|
security.oauth2.client.registrations.google.user-info-uri=https://www.googleapis.com/oauth2/v3/userinfo
|
||||||
security.oauth2.client.google.jwk-set-uri=https://www.googleapis.com/oauth2/v3/certs
|
security.oauth2.client.registrations.google.jwk-set-uri=https://www.googleapis.com/oauth2/v3/certs
|
||||||
security.oauth2.client.google.client-name=Google
|
security.oauth2.client.registrations.google.client-name=Google
|
||||||
security.oauth2.client.google.client-alias=google
|
|
||||||
----
|
----
|
||||||
|
|
||||||
The following _security configuration_ will enable OAuth 2.0 Login using _Google_ as the _Authentication Provider_:
|
The following _security configuration_ will enable OAuth 2.0 Login using _Google_ as the _Authentication Provider_:
|
||||||
@ -592,12 +587,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
@Bean
|
@Bean
|
||||||
public ClientRegistrationRepository clientRegistrationRepository() {
|
public ClientRegistrationRepository clientRegistrationRepository() {
|
||||||
List<ClientRegistration> clientRegistrations = Collections.singletonList(
|
List<ClientRegistration> clientRegistrations = Collections.singletonList(
|
||||||
clientRegistration("security.oauth2.client.google."));
|
clientRegistration("security.oauth2.client.registrations.google."));
|
||||||
|
|
||||||
return new InMemoryClientRegistrationRepository(clientRegistrations);
|
return new InMemoryClientRegistrationRepository(clientRegistrations);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientRegistration clientRegistration(String clientPropertyKey) {
|
private ClientRegistration clientRegistration(String clientPropertyKey) {
|
||||||
|
String registrationId = this.environment.getProperty(clientPropertyKey + "registration-id");
|
||||||
String clientId = this.environment.getProperty(clientPropertyKey + "client-id");
|
String clientId = this.environment.getProperty(clientPropertyKey + "client-id");
|
||||||
String clientSecret = this.environment.getProperty(clientPropertyKey + "client-secret");
|
String clientSecret = this.environment.getProperty(clientPropertyKey + "client-secret");
|
||||||
ClientAuthenticationMethod clientAuthenticationMethod = new ClientAuthenticationMethod(
|
ClientAuthenticationMethod clientAuthenticationMethod = new ClientAuthenticationMethod(
|
||||||
@ -611,9 +607,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
String userInfoUri = this.environment.getProperty(clientPropertyKey + "user-info-uri");
|
String userInfoUri = this.environment.getProperty(clientPropertyKey + "user-info-uri");
|
||||||
String jwkSetUri = this.environment.getProperty(clientPropertyKey + "jwk-set-uri");
|
String jwkSetUri = this.environment.getProperty(clientPropertyKey + "jwk-set-uri");
|
||||||
String clientName = this.environment.getProperty(clientPropertyKey + "client-name");
|
String clientName = this.environment.getProperty(clientPropertyKey + "client-name");
|
||||||
String clientAlias = this.environment.getProperty(clientPropertyKey + "client-alias");
|
|
||||||
|
|
||||||
return new ClientRegistration.Builder(clientId)
|
return new ClientRegistration.Builder(registrationId)
|
||||||
|
.clientId(clientId)
|
||||||
.clientSecret(clientSecret)
|
.clientSecret(clientSecret)
|
||||||
.clientAuthenticationMethod(clientAuthenticationMethod)
|
.clientAuthenticationMethod(clientAuthenticationMethod)
|
||||||
.authorizedGrantType(authorizationGrantType)
|
.authorizedGrantType(authorizationGrantType)
|
||||||
@ -624,7 +620,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
.userInfoUri(userInfoUri)
|
.userInfoUri(userInfoUri)
|
||||||
.jwkSetUri(jwkSetUri)
|
.jwkSetUri(jwkSetUri)
|
||||||
.clientName(clientName)
|
.clientName(clientName)
|
||||||
.clientAlias(clientAlias)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,10 +93,10 @@ public class OAuth2LoginApplicationTests {
|
|||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.webClient.getCookieManager().clearCookies();
|
this.webClient.getCookieManager().clearCookies();
|
||||||
this.googleClientRegistration = this.clientRegistrationRepository.getRegistrationByClientAlias("google");
|
this.googleClientRegistration = this.clientRegistrationRepository.findByRegistrationId("google");
|
||||||
this.githubClientRegistration = this.clientRegistrationRepository.getRegistrationByClientAlias("github");
|
this.githubClientRegistration = this.clientRegistrationRepository.findByRegistrationId("github");
|
||||||
this.facebookClientRegistration = this.clientRegistrationRepository.getRegistrationByClientAlias("facebook");
|
this.facebookClientRegistration = this.clientRegistrationRepository.findByRegistrationId("facebook");
|
||||||
this.oktaClientRegistration = this.clientRegistrationRepository.getRegistrationByClientAlias("okta");
|
this.oktaClientRegistration = this.clientRegistrationRepository.findByRegistrationId("okta");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -134,7 +134,7 @@ public class OAuth2LoginApplicationTests {
|
|||||||
|
|
||||||
assertThat(params.get(OAuth2Parameter.RESPONSE_TYPE)).isEqualTo(ResponseType.CODE.getValue());
|
assertThat(params.get(OAuth2Parameter.RESPONSE_TYPE)).isEqualTo(ResponseType.CODE.getValue());
|
||||||
assertThat(params.get(OAuth2Parameter.CLIENT_ID)).isEqualTo(this.githubClientRegistration.getClientId());
|
assertThat(params.get(OAuth2Parameter.CLIENT_ID)).isEqualTo(this.githubClientRegistration.getClientId());
|
||||||
String redirectUri = AUTHORIZE_BASE_URL + "/" + this.githubClientRegistration.getClientAlias();
|
String redirectUri = AUTHORIZE_BASE_URL + "/" + this.githubClientRegistration.getRegistrationId();
|
||||||
assertThat(URLDecoder.decode(params.get(OAuth2Parameter.REDIRECT_URI), "UTF-8")).isEqualTo(redirectUri);
|
assertThat(URLDecoder.decode(params.get(OAuth2Parameter.REDIRECT_URI), "UTF-8")).isEqualTo(redirectUri);
|
||||||
assertThat(URLDecoder.decode(params.get(OAuth2Parameter.SCOPE), "UTF-8"))
|
assertThat(URLDecoder.decode(params.get(OAuth2Parameter.SCOPE), "UTF-8"))
|
||||||
.isEqualTo(this.githubClientRegistration.getScope().stream().collect(Collectors.joining(" ")));
|
.isEqualTo(this.githubClientRegistration.getScope().stream().collect(Collectors.joining(" ")));
|
||||||
@ -194,7 +194,7 @@ public class OAuth2LoginApplicationTests {
|
|||||||
|
|
||||||
String code = "auth-code";
|
String code = "auth-code";
|
||||||
String state = "state";
|
String state = "state";
|
||||||
String redirectUri = AUTHORIZE_BASE_URL + "/" + this.googleClientRegistration.getClientAlias();
|
String redirectUri = AUTHORIZE_BASE_URL + "/" + this.googleClientRegistration.getRegistrationId();
|
||||||
|
|
||||||
String authorizationResponseUri =
|
String authorizationResponseUri =
|
||||||
UriComponentsBuilder.fromHttpUrl(redirectUri)
|
UriComponentsBuilder.fromHttpUrl(redirectUri)
|
||||||
@ -226,7 +226,7 @@ public class OAuth2LoginApplicationTests {
|
|||||||
|
|
||||||
String code = "auth-code";
|
String code = "auth-code";
|
||||||
String state = "invalid-state";
|
String state = "invalid-state";
|
||||||
String redirectUri = AUTHORIZE_BASE_URL + "/" + this.githubClientRegistration.getClientAlias();
|
String redirectUri = AUTHORIZE_BASE_URL + "/" + this.githubClientRegistration.getRegistrationId();
|
||||||
|
|
||||||
String authorizationResponseUri =
|
String authorizationResponseUri =
|
||||||
UriComponentsBuilder.fromHttpUrl(redirectUri)
|
UriComponentsBuilder.fromHttpUrl(redirectUri)
|
||||||
@ -284,7 +284,7 @@ public class OAuth2LoginApplicationTests {
|
|||||||
|
|
||||||
String error = OAuth2Error.INVALID_CLIENT_ERROR_CODE;
|
String error = OAuth2Error.INVALID_CLIENT_ERROR_CODE;
|
||||||
String state = "state";
|
String state = "state";
|
||||||
String redirectUri = AUTHORIZE_BASE_URL + "/" + this.githubClientRegistration.getClientAlias();
|
String redirectUri = AUTHORIZE_BASE_URL + "/" + this.githubClientRegistration.getRegistrationId();
|
||||||
|
|
||||||
String authorizationResponseUri =
|
String authorizationResponseUri =
|
||||||
UriComponentsBuilder.fromHttpUrl(redirectUri)
|
UriComponentsBuilder.fromHttpUrl(redirectUri)
|
||||||
@ -309,10 +309,10 @@ public class OAuth2LoginApplicationTests {
|
|||||||
assertThat(clientAnchorElements.size()).isEqualTo(expectedClients);
|
assertThat(clientAnchorElements.size()).isEqualTo(expectedClients);
|
||||||
|
|
||||||
String baseAuthorizeUri = AUTHORIZATION_BASE_URI + "/";
|
String baseAuthorizeUri = AUTHORIZATION_BASE_URI + "/";
|
||||||
String googleClientAuthorizeUri = baseAuthorizeUri + this.googleClientRegistration.getClientAlias();
|
String googleClientAuthorizeUri = baseAuthorizeUri + this.googleClientRegistration.getRegistrationId();
|
||||||
String githubClientAuthorizeUri = baseAuthorizeUri + this.githubClientRegistration.getClientAlias();
|
String githubClientAuthorizeUri = baseAuthorizeUri + this.githubClientRegistration.getRegistrationId();
|
||||||
String facebookClientAuthorizeUri = baseAuthorizeUri + this.facebookClientRegistration.getClientAlias();
|
String facebookClientAuthorizeUri = baseAuthorizeUri + this.facebookClientRegistration.getRegistrationId();
|
||||||
String oktaClientAuthorizeUri = baseAuthorizeUri + this.oktaClientRegistration.getClientAlias();
|
String oktaClientAuthorizeUri = baseAuthorizeUri + this.oktaClientRegistration.getRegistrationId();
|
||||||
|
|
||||||
for (int i=0; i<expectedClients; i++) {
|
for (int i=0; i<expectedClients; i++) {
|
||||||
assertThat(clientAnchorElements.get(i).getAttribute("href")).isIn(
|
assertThat(clientAnchorElements.get(i).getAttribute("href")).isIn(
|
||||||
|
@ -17,12 +17,21 @@ package org.springframework.boot.autoconfigure.security.oauth2.client;
|
|||||||
|
|
||||||
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||||
import org.springframework.boot.autoconfigure.condition.*;
|
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||||
import org.springframework.boot.context.properties.bind.BindResult;
|
import org.springframework.boot.context.properties.bind.BindResult;
|
||||||
import org.springframework.boot.context.properties.bind.Bindable;
|
import org.springframework.boot.context.properties.bind.Bindable;
|
||||||
import org.springframework.boot.context.properties.bind.Binder;
|
import org.springframework.boot.context.properties.bind.Binder;
|
||||||
import org.springframework.context.annotation.*;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.ConfigurationCondition;
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.env.MutablePropertySources;
|
import org.springframework.core.env.MutablePropertySources;
|
||||||
@ -35,7 +44,11 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
|
|||||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,7 +62,7 @@ import java.util.stream.Collectors;
|
|||||||
public class ClientRegistrationAutoConfiguration {
|
public class ClientRegistrationAutoConfiguration {
|
||||||
private static final String CLIENTS_DEFAULTS_RESOURCE = "META-INF/oauth2-clients-defaults.yml";
|
private static final String CLIENTS_DEFAULTS_RESOURCE = "META-INF/oauth2-clients-defaults.yml";
|
||||||
static final String CLIENT_ID_PROPERTY = "client-id";
|
static final String CLIENT_ID_PROPERTY = "client-id";
|
||||||
static final String CLIENT_PROPERTY_PREFIX = "security.oauth2.client";
|
static final String REGISTRATIONS_PROPERTY_PREFIX = "security.oauth2.client.registrations";
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Conditional(ClientPropertiesAvailableCondition.class)
|
@Conditional(ClientPropertiesAvailableCondition.class)
|
||||||
@ -69,14 +82,15 @@ public class ClientRegistrationAutoConfiguration {
|
|||||||
}
|
}
|
||||||
Binder binder = Binder.get(this.environment);
|
Binder binder = Binder.get(this.environment);
|
||||||
List<ClientRegistration> clientRegistrations = new ArrayList<>();
|
List<ClientRegistration> clientRegistrations = new ArrayList<>();
|
||||||
Set<String> clientPropertyKeys = resolveClientPropertyKeys(this.environment);
|
Set<String> registrationIds = getRegistrationIds(this.environment);
|
||||||
for (String clientPropertyKey : clientPropertyKeys) {
|
for (String registrationId : registrationIds) {
|
||||||
String fullClientPropertyKey = CLIENT_PROPERTY_PREFIX + "." + clientPropertyKey;
|
String fullRegistrationId = REGISTRATIONS_PROPERTY_PREFIX + "." + registrationId;
|
||||||
if (!this.environment.containsProperty(fullClientPropertyKey + "." + CLIENT_ID_PROPERTY)) {
|
if (!this.environment.containsProperty(fullRegistrationId + "." + CLIENT_ID_PROPERTY)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ClientRegistrationProperties clientRegistrationProperties = binder.bind(
|
ClientRegistrationProperties clientRegistrationProperties = binder.bind(
|
||||||
fullClientPropertyKey, Bindable.of(ClientRegistrationProperties.class)).get();
|
fullRegistrationId, Bindable.of(ClientRegistrationProperties.class)).get();
|
||||||
|
clientRegistrationProperties.setRegistrationId(registrationId);
|
||||||
ClientRegistration clientRegistration = new ClientRegistration.Builder(clientRegistrationProperties).build();
|
ClientRegistration clientRegistration = new ClientRegistration.Builder(clientRegistrationProperties).build();
|
||||||
clientRegistrations.add(clientRegistration);
|
clientRegistrations.add(clientRegistration);
|
||||||
}
|
}
|
||||||
@ -95,10 +109,10 @@ public class ClientRegistrationAutoConfiguration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Set<String> resolveClientPropertyKeys(Environment environment) {
|
static Set<String> getRegistrationIds(Environment environment) {
|
||||||
Binder binder = Binder.get(environment);
|
Binder binder = Binder.get(environment);
|
||||||
BindResult<Map<String, Object>> result = binder.bind(
|
BindResult<Map<String, Object>> result = binder.bind(
|
||||||
CLIENT_PROPERTY_PREFIX, Bindable.mapOf(String.class, Object.class));
|
REGISTRATIONS_PROPERTY_PREFIX, Bindable.mapOf(String.class, Object.class));
|
||||||
return result.get().keySet();
|
return result.get().keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,10 +126,10 @@ public class ClientRegistrationAutoConfiguration {
|
|||||||
@Override
|
@Override
|
||||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||||
ConditionMessage.Builder message = ConditionMessage.forCondition("OAuth2 Client Properties");
|
ConditionMessage.Builder message = ConditionMessage.forCondition("OAuth2 Client Properties");
|
||||||
Set<String> clientPropertyKeys = resolveClientPropertyKeys(context.getEnvironment());
|
Set<String> registrationIds = getRegistrationIds(context.getEnvironment());
|
||||||
if (!CollectionUtils.isEmpty(clientPropertyKeys)) {
|
if (!CollectionUtils.isEmpty(registrationIds)) {
|
||||||
return ConditionOutcome.match(message.foundExactly("OAuth2 Client(s) -> " +
|
return ConditionOutcome.match(message.foundExactly("OAuth2 Client(s) -> " +
|
||||||
clientPropertyKeys.stream().collect(Collectors.joining(", "))));
|
registrationIds.stream().collect(Collectors.joining(", "))));
|
||||||
}
|
}
|
||||||
return ConditionOutcome.noMatch(message.notAvailable("OAuth2 Client(s)"));
|
return ConditionOutcome.noMatch(message.notAvailable("OAuth2 Client(s)"));
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,40 @@
|
|||||||
security:
|
security:
|
||||||
oauth2:
|
oauth2:
|
||||||
client:
|
client:
|
||||||
google:
|
registrations:
|
||||||
client-authentication-method: basic
|
google:
|
||||||
authorization-grant-type: authorization_code
|
client-authentication-method: basic
|
||||||
redirect-uri: "{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}"
|
authorization-grant-type: authorization_code
|
||||||
scope: openid, profile, email, address, phone
|
redirect-uri: "{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{registrationId}"
|
||||||
authorization-uri: "https://accounts.google.com/o/oauth2/v2/auth"
|
scope: openid, profile, email, address, phone
|
||||||
token-uri: "https://www.googleapis.com/oauth2/v4/token"
|
authorization-uri: "https://accounts.google.com/o/oauth2/v2/auth"
|
||||||
user-info-uri: "https://www.googleapis.com/oauth2/v3/userinfo"
|
token-uri: "https://www.googleapis.com/oauth2/v4/token"
|
||||||
jwk-set-uri: "https://www.googleapis.com/oauth2/v3/certs"
|
user-info-uri: "https://www.googleapis.com/oauth2/v3/userinfo"
|
||||||
client-name: Google
|
jwk-set-uri: "https://www.googleapis.com/oauth2/v3/certs"
|
||||||
client-alias: google
|
client-name: Google
|
||||||
github:
|
github:
|
||||||
client-authentication-method: basic
|
client-authentication-method: basic
|
||||||
authorization-grant-type: authorization_code
|
authorization-grant-type: authorization_code
|
||||||
redirect-uri: "{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}"
|
redirect-uri: "{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{registrationId}"
|
||||||
scope: user
|
scope: user
|
||||||
authorization-uri: "https://github.com/login/oauth/authorize"
|
authorization-uri: "https://github.com/login/oauth/authorize"
|
||||||
token-uri: "https://github.com/login/oauth/access_token"
|
token-uri: "https://github.com/login/oauth/access_token"
|
||||||
user-info-uri: "https://api.github.com/user"
|
user-info-uri: "https://api.github.com/user"
|
||||||
user-name-attribute-name: "name"
|
user-name-attribute-name: "name"
|
||||||
client-name: GitHub
|
client-name: GitHub
|
||||||
client-alias: github
|
facebook:
|
||||||
facebook:
|
client-authentication-method: post
|
||||||
client-authentication-method: post
|
authorization-grant-type: authorization_code
|
||||||
authorization-grant-type: authorization_code
|
redirect-uri: "{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{registrationId}"
|
||||||
redirect-uri: "{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}"
|
scope: public_profile, email
|
||||||
scope: public_profile, email
|
authorization-uri: "https://www.facebook.com/v2.8/dialog/oauth"
|
||||||
authorization-uri: "https://www.facebook.com/v2.8/dialog/oauth"
|
token-uri: "https://graph.facebook.com/v2.8/oauth/access_token"
|
||||||
token-uri: "https://graph.facebook.com/v2.8/oauth/access_token"
|
user-info-uri: "https://graph.facebook.com/me"
|
||||||
user-info-uri: "https://graph.facebook.com/me"
|
user-name-attribute-name: "name"
|
||||||
user-name-attribute-name: "name"
|
client-name: Facebook
|
||||||
client-name: Facebook
|
okta:
|
||||||
client-alias: facebook
|
client-authentication-method: basic
|
||||||
okta:
|
authorization-grant-type: authorization_code
|
||||||
client-authentication-method: basic
|
redirect-uri: "{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{registrationId}"
|
||||||
authorization-grant-type: authorization_code
|
scope: openid, profile, email, address, phone
|
||||||
redirect-uri: "{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}"
|
client-name: Okta
|
||||||
scope: openid, profile, email, address, phone
|
|
||||||
client-name: Okta
|
|
||||||
client-alias: okta
|
|
||||||
|
@ -15,19 +15,20 @@ spring:
|
|||||||
security:
|
security:
|
||||||
oauth2:
|
oauth2:
|
||||||
client:
|
client:
|
||||||
google:
|
registrations:
|
||||||
client-id: your-app-client-id
|
google:
|
||||||
client-secret: your-app-client-secret
|
client-id: your-app-client-id
|
||||||
github:
|
client-secret: your-app-client-secret
|
||||||
client-id: your-app-client-id
|
github:
|
||||||
client-secret: your-app-client-secret
|
client-id: your-app-client-id
|
||||||
facebook:
|
client-secret: your-app-client-secret
|
||||||
client-id: your-app-client-id
|
facebook:
|
||||||
client-secret: your-app-client-secret
|
client-id: your-app-client-id
|
||||||
okta:
|
client-secret: your-app-client-secret
|
||||||
client-id: your-app-client-id
|
okta:
|
||||||
client-secret: your-app-client-secret
|
client-id: your-app-client-id
|
||||||
authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize
|
client-secret: your-app-client-secret
|
||||||
token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token
|
authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize
|
||||||
user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo
|
token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token
|
||||||
jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys
|
user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo
|
||||||
|
jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys
|
||||||
|
Loading…
x
Reference in New Issue
Block a user