Add auto-config for spring-security-oauth2-client
Closes gh-10497
This commit is contained in:
parent
494b79c439
commit
dbe1d9608d
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
|
@ -532,6 +533,16 @@
|
|||
<artifactId>spring-security-webflux</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-jwt-jose</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-client</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session-core</artifactId>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 authorization grant types supported by Spring Boot.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public enum AuthorizationGrantType {
|
||||
|
||||
/**
|
||||
* An {@code "authorization_code"} grant type.
|
||||
*/
|
||||
AUTHORIZATION_CODE(
|
||||
org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
|
||||
private final org.springframework.security.oauth2.core.AuthorizationGrantType type;
|
||||
|
||||
AuthorizationGrantType(
|
||||
org.springframework.security.oauth2.core.AuthorizationGrantType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
org.springframework.security.oauth2.core.AuthorizationGrantType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 client authentication methods supported by Spring Boot.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
* @see org.springframework.security.oauth2.core.ClientAuthenticationMethod
|
||||
*/
|
||||
public enum ClientAuthenticationMethod {
|
||||
|
||||
/**
|
||||
* HTTP BASIC client authentication.
|
||||
*/
|
||||
BASIC(org.springframework.security.oauth2.core.ClientAuthenticationMethod.BASIC),
|
||||
|
||||
/**
|
||||
* HTTP POST client authentication.
|
||||
*/
|
||||
POST(org.springframework.security.oauth2.core.ClientAuthenticationMethod.POST);
|
||||
|
||||
private final org.springframework.security.oauth2.core.ClientAuthenticationMethod method;
|
||||
|
||||
ClientAuthenticationMethod(
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
|
||||
/**
|
||||
* Common OAuth2 Providers that can be used to create
|
||||
* {@link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder
|
||||
* builders} pre-configured with sensible defaults.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public enum CommonOAuth2Provider {
|
||||
|
||||
GOOGLE {
|
||||
|
||||
@Override
|
||||
public Builder getBuilder(String registrationId) {
|
||||
ClientRegistration.Builder builder = getBuilder(registrationId,
|
||||
ClientAuthenticationMethod.BASIC, DEFAULT_REDIRECT_URL);
|
||||
builder.scope("openid", "profile", "email", "address", "phone");
|
||||
builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth");
|
||||
builder.tokenUri("https://www.googleapis.com/oauth2/v4/token");
|
||||
builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs");
|
||||
builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
|
||||
builder.clientName("Google");
|
||||
return builder;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
GITHUB {
|
||||
|
||||
@Override
|
||||
public Builder getBuilder(String registrationId) {
|
||||
ClientRegistration.Builder builder = getBuilder(registrationId,
|
||||
ClientAuthenticationMethod.BASIC, DEFAULT_REDIRECT_URL);
|
||||
builder.scope("user");
|
||||
builder.authorizationUri("https://github.com/login/oauth/authorize");
|
||||
builder.tokenUri("https://github.com/login/oauth/access_token");
|
||||
builder.userInfoUri("https://api.github.com/user");
|
||||
builder.userNameAttributeName("name");
|
||||
builder.clientName("GitHub");
|
||||
return builder;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
FACEBOOK {
|
||||
|
||||
@Override
|
||||
public Builder getBuilder(String registrationId) {
|
||||
ClientRegistration.Builder builder = getBuilder(registrationId,
|
||||
ClientAuthenticationMethod.POST, DEFAULT_REDIRECT_URL);
|
||||
builder.scope("public_profile", "email");
|
||||
builder.authorizationUri("https://www.facebook.com/v2.8/dialog/oauth");
|
||||
builder.tokenUri("https://graph.facebook.com/v2.8/oauth/access_token");
|
||||
builder.userInfoUri("https://graph.facebook.com/me");
|
||||
builder.userNameAttributeName("name");
|
||||
builder.clientName("Facebook");
|
||||
return builder;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
OKTA {
|
||||
|
||||
@Override
|
||||
public Builder getBuilder(String registrationId) {
|
||||
ClientRegistration.Builder builder = getBuilder(registrationId,
|
||||
ClientAuthenticationMethod.BASIC, DEFAULT_REDIRECT_URL);
|
||||
builder.scope("openid", "profile", "email", "address", "phone");
|
||||
builder.clientName("Okta");
|
||||
return builder;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private static final String DEFAULT_REDIRECT_URL = "{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}";
|
||||
|
||||
protected final ClientRegistration.Builder getBuilder(String registrationId,
|
||||
ClientAuthenticationMethod method, String redirectUri) {
|
||||
ClientRegistration.Builder builder = new ClientRegistration.Builder(registrationId);
|
||||
builder.clientAuthenticationMethod(method);
|
||||
builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
builder.redirectUri(redirectUri);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new
|
||||
* {@link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder
|
||||
* ClientRegistration.Builder} pre-initialized with the provider settings.
|
||||
* @param registrationId the registration-id used with the new builder
|
||||
* @return a builder instance
|
||||
*/
|
||||
public abstract ClientRegistration.Builder getBuilder(String registrationId);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for OAuth client support.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureBefore(SecurityAutoConfiguration.class)
|
||||
@ConditionalOnClass({ EnableWebSecurity.class, ClientRegistration.class })
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@Import({ OAuth2ClientRegistrationRepositoryConfiguration.class,
|
||||
OAuth2WebSecurityConfiguration.class })
|
||||
public class OAuth2ClientAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 client properties.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.security.oauth2.client")
|
||||
public class OAuth2ClientProperties {
|
||||
|
||||
/**
|
||||
* OAuth provider details.
|
||||
*/
|
||||
private Map<String, Provider> provider = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Client registrations.
|
||||
*/
|
||||
private Map<String, Registration> registration = new HashMap<>();
|
||||
|
||||
public Map<String, Provider> getProvider() {
|
||||
return this.provider;
|
||||
}
|
||||
|
||||
public Map<String, Registration> getRegistration() {
|
||||
return this.registration;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void validate() {
|
||||
this.getRegistration().values().forEach(this::validateRegistration);
|
||||
}
|
||||
|
||||
private void validateRegistration(Registration registration) {
|
||||
if (!StringUtils.hasText(registration.getClientId())) {
|
||||
throw new IllegalStateException("Client id must not be empty.");
|
||||
}
|
||||
if (!StringUtils.hasText(registration.getClientSecret())) {
|
||||
throw new IllegalStateException("Client secret must not be empty.");
|
||||
}
|
||||
if (!StringUtils.hasText(registration.getProvider())) {
|
||||
throw new IllegalStateException("Provider must not be empty.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A single client registration.
|
||||
*/
|
||||
public static class Registration {
|
||||
|
||||
/**
|
||||
* Reference to the OAuth 2.0 provider to use. May reference an element from the
|
||||
* 'provider' property or used one of the commonly used providers (google, github,
|
||||
* facebook, okta).
|
||||
*/
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* Client ID for the registration.
|
||||
*/
|
||||
private String clientId;
|
||||
|
||||
/**
|
||||
* Client secret of the registration.
|
||||
*/
|
||||
private String clientSecret;
|
||||
|
||||
/**
|
||||
* The client authentication method. May be left bank then using a pre-defined
|
||||
* provider.
|
||||
*/
|
||||
private ClientAuthenticationMethod clientAuthenticationMethod;
|
||||
|
||||
/**
|
||||
* The authorization grant type. May be left bank then using a pre-defined
|
||||
* provider.
|
||||
*/
|
||||
private AuthorizationGrantType authorizationGrantType;
|
||||
|
||||
/**
|
||||
* The redirect URI. May be left bank then using a pre-defined provider.
|
||||
*/
|
||||
private String redirectUri;
|
||||
|
||||
/**
|
||||
* The authorization scopes. May be left bank then using a pre-defined provider.
|
||||
*/
|
||||
private Set<String> scope;
|
||||
|
||||
/**
|
||||
* The client name. May be left bank then using a pre-defined provider.
|
||||
*/
|
||||
private String clientName;
|
||||
|
||||
public String getProvider() {
|
||||
return this.provider;
|
||||
}
|
||||
|
||||
public void setProvider(String provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return this.clientId;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public String getClientSecret() {
|
||||
return this.clientSecret;
|
||||
}
|
||||
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
public ClientAuthenticationMethod getClientAuthenticationMethod() {
|
||||
return this.clientAuthenticationMethod;
|
||||
}
|
||||
|
||||
public void setClientAuthenticationMethod(
|
||||
ClientAuthenticationMethod clientAuthenticationMethod) {
|
||||
this.clientAuthenticationMethod = clientAuthenticationMethod;
|
||||
}
|
||||
|
||||
public AuthorizationGrantType getAuthorizationGrantType() {
|
||||
return this.authorizationGrantType;
|
||||
}
|
||||
|
||||
public void setAuthorizationGrantType(
|
||||
AuthorizationGrantType authorizationGrantType) {
|
||||
this.authorizationGrantType = authorizationGrantType;
|
||||
}
|
||||
|
||||
public String getRedirectUri() {
|
||||
return this.redirectUri;
|
||||
}
|
||||
|
||||
public void setRedirectUri(String redirectUri) {
|
||||
this.redirectUri = redirectUri;
|
||||
}
|
||||
|
||||
public Set<String> getScope() {
|
||||
return this.scope;
|
||||
}
|
||||
|
||||
public void setScope(Set<String> scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public String getClientName() {
|
||||
return this.clientName;
|
||||
}
|
||||
|
||||
public void setClientName(String clientName) {
|
||||
this.clientName = clientName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Provider {
|
||||
|
||||
/**
|
||||
* The authorization URI for the provider.
|
||||
*/
|
||||
private String authorizationUri;
|
||||
|
||||
/**
|
||||
* The token URI for the provider.
|
||||
*/
|
||||
private String tokenUri;
|
||||
|
||||
/**
|
||||
* The user info URI for the provider.
|
||||
*/
|
||||
private String userInfoUri;
|
||||
|
||||
/**
|
||||
* The name of the attribute that will be used to extract the username from the
|
||||
* call to 'userInfoUri'.
|
||||
*/
|
||||
private String userNameAttribute;
|
||||
|
||||
/**
|
||||
* The JWK set URI for the provider.
|
||||
*/
|
||||
private String jwkSetUri;
|
||||
|
||||
public String getAuthorizationUri() {
|
||||
return this.authorizationUri;
|
||||
}
|
||||
|
||||
public void setAuthorizationUri(String authorizationUri) {
|
||||
this.authorizationUri = authorizationUri;
|
||||
}
|
||||
|
||||
public String getTokenUri() {
|
||||
return this.tokenUri;
|
||||
}
|
||||
|
||||
public void setTokenUri(String tokenUri) {
|
||||
this.tokenUri = tokenUri;
|
||||
}
|
||||
|
||||
public String getUserInfoUri() {
|
||||
return this.userInfoUri;
|
||||
}
|
||||
|
||||
public void setUserInfoUri(String userInfoUri) {
|
||||
this.userInfoUri = userInfoUri;
|
||||
}
|
||||
|
||||
public String getUserNameAttribute() {
|
||||
return this.userNameAttribute;
|
||||
}
|
||||
|
||||
public void setUserNameAttribute(String userNameAttribute) {
|
||||
this.userNameAttribute = userNameAttribute;
|
||||
}
|
||||
|
||||
public String getJwkSetUri() {
|
||||
return this.jwkSetUri;
|
||||
}
|
||||
|
||||
public void setJwkSetUri(String jwkSetUri) {
|
||||
this.jwkSetUri = jwkSetUri;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Provider;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Registration;
|
||||
import org.springframework.boot.context.properties.bind.convert.BinderConversionService;
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder;
|
||||
|
||||
/**
|
||||
* Adapter class to convert {@link OAuth2ClientProperties} to a
|
||||
* {@link ClientRegistration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
final class OAuth2ClientPropertiesRegistrationAdapter {
|
||||
|
||||
private OAuth2ClientPropertiesRegistrationAdapter() {
|
||||
}
|
||||
|
||||
public static Map<String, ClientRegistration> getClientRegistrations(
|
||||
OAuth2ClientProperties properties) {
|
||||
Map<String, ClientRegistration> clientRegistrations = new HashMap<>();
|
||||
properties.getRegistration().forEach((key, value) -> {
|
||||
clientRegistrations.put(key,
|
||||
getClientRegistration(key, value, properties.getProvider()));
|
||||
});
|
||||
return clientRegistrations;
|
||||
}
|
||||
|
||||
private static ClientRegistration getClientRegistration(String registrationId, Registration properties,
|
||||
Map<String, Provider> providers) {
|
||||
Builder builder = getBuilder(registrationId, properties.getProvider(),
|
||||
providers);
|
||||
copyIfNotNull(properties::getClientId, builder::clientId);
|
||||
copyIfNotNull(properties::getClientSecret, builder::clientSecret);
|
||||
copyIfNotNull(() -> properties.getClientAuthenticationMethod(),
|
||||
builder::clientAuthenticationMethod,
|
||||
ClientAuthenticationMethod::getMethod);
|
||||
copyIfNotNull(() -> properties.getAuthorizationGrantType(),
|
||||
builder::authorizationGrantType, AuthorizationGrantType::getType);
|
||||
copyIfNotNull(properties::getRedirectUri, builder::redirectUri);
|
||||
copyIfNotNull(properties::getScope, builder::scope,
|
||||
(scope) -> scope.toArray(new String[scope.size()]));
|
||||
copyIfNotNull(properties::getClientName, builder::clientName);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static Builder getBuilder(String registrationId, String providerId,
|
||||
Map<String, Provider> providers) {
|
||||
CommonOAuth2Provider provider = getCommonProvider(providerId);
|
||||
if (provider == null && !providers.containsKey(providerId)) {
|
||||
throw new IllegalStateException("Unknown provider ID '" + providerId + "'");
|
||||
}
|
||||
Builder builder = (provider != null ? provider.getBuilder(registrationId) : new Builder(registrationId));
|
||||
if (providers.containsKey(providerId)) {
|
||||
return getBuilder(builder, providers.get(providerId));
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static Builder getBuilder(Builder builder, Provider provider) {
|
||||
copyIfNotNull(provider::getAuthorizationUri, builder::authorizationUri);
|
||||
copyIfNotNull(provider::getTokenUri, builder::tokenUri);
|
||||
copyIfNotNull(provider::getUserInfoUri, builder::userInfoUri);
|
||||
copyIfNotNull(provider::getJwkSetUri, builder::jwkSetUri);
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static CommonOAuth2Provider getCommonProvider(String providerId) {
|
||||
try {
|
||||
return new BinderConversionService(null).convert(providerId,
|
||||
CommonOAuth2Provider.class);
|
||||
}
|
||||
catch (ConversionException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void copyIfNotNull(Supplier<T> supplier, Consumer<T> consumer) {
|
||||
copyIfNotNull(supplier, consumer, Function.identity());
|
||||
}
|
||||
|
||||
private static <S, C> void copyIfNotNull(Supplier<S> supplier, Consumer<C> consumer,
|
||||
Function<S, C> converter) {
|
||||
S value = supplier.get();
|
||||
if (value != null) {
|
||||
consumer.accept(converter.apply(value));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Registration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
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.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||
|
||||
/**
|
||||
* {@link Configuration} used to map {@link OAuth2ClientProperties} to client
|
||||
* registrations.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(OAuth2ClientProperties.class)
|
||||
@Conditional(OAuth2ClientRegistrationRepositoryConfiguration.ClientsConfiguredCondition.class)
|
||||
class OAuth2ClientRegistrationRepositoryConfiguration {
|
||||
|
||||
private final OAuth2ClientProperties properties;
|
||||
|
||||
OAuth2ClientRegistrationRepositoryConfiguration(
|
||||
OAuth2ClientProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ClientRegistrationRepository.class)
|
||||
public InMemoryClientRegistrationRepository clientRegistrationRepository() {
|
||||
List<ClientRegistration> registrations = new ArrayList<>(
|
||||
OAuth2ClientPropertiesRegistrationAdapter
|
||||
.getClientRegistrations(this.properties).values());
|
||||
return new InMemoryClientRegistrationRepository(registrations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition that matches if any {@code spring.security.oauth2.client.registration}
|
||||
* properties are defined.
|
||||
*/
|
||||
static class ClientsConfiguredCondition extends SpringBootCondition {
|
||||
|
||||
private static final Bindable<Map<String, Registration>> BINDABLE_REGISTRATION = Bindable
|
||||
.mapOf(String.class, OAuth2ClientProperties.Registration.class);
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage
|
||||
.forCondition("OAuth2 Clients Configured Condition");
|
||||
Map<String, Registration> registrations = this
|
||||
.getRegistrations(context.getEnvironment());
|
||||
if (!registrations.isEmpty()) {
|
||||
return ConditionOutcome.match(message.foundExactly(
|
||||
"registered clients " + registrations.values().stream()
|
||||
.map(OAuth2ClientProperties.Registration::getClientId)
|
||||
.collect(Collectors.joining(", "))));
|
||||
}
|
||||
return ConditionOutcome.noMatch(message.notAvailable("registered clients"));
|
||||
}
|
||||
|
||||
private Map<String, Registration> getRegistrations(Environment environment) {
|
||||
return Binder.get(environment)
|
||||
.bind("spring.security.oauth2.client.registration",
|
||||
BINDABLE_REGISTRATION)
|
||||
.orElse(Collections.emptyMap());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
|
||||
/**
|
||||
* {@link WebSecurityConfigurerAdapter} to add OAuth client support.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnBean(ClientRegistrationRepository.class)
|
||||
class OAuth2WebSecurityConfiguration {
|
||||
|
||||
@Configuration
|
||||
private static class OAuth2WebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final ClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
OAuth2WebSecurityConfigurationAdapter(
|
||||
ClientRegistrationRepository clientRegistrationRepository) {
|
||||
this.clientRegistrationRepository = clientRegistrationRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest()
|
||||
.authenticated().and()
|
||||
.oauth2Login()
|
||||
.clients(this.clientRegistrationRepository);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -102,6 +102,7 @@ org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,
|
|||
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthorizationGrantType}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class AuthorizationGrantTypeTests {
|
||||
|
||||
@Test
|
||||
public void getTypeShouldGetSpringSecurityVariant() throws Exception {
|
||||
assertThat(AuthorizationGrantType.AUTHORIZATION_CODE.getType()).isEqualTo(
|
||||
org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClientAuthenticationMethod}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ClientAuthenticationMethodTests {
|
||||
|
||||
@Test
|
||||
public void getMethodShouldGetSpringSecurityVariant() throws Exception {
|
||||
assertThat(ClientAuthenticationMethod.BASIC.getMethod()).isEqualTo(
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod.BASIC);
|
||||
assertThat(ClientAuthenticationMethod.POST.getMethod()).isEqualTo(
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod.POST);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link CommonOAuth2Provider}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class CommonOAuth2ProviderTests {
|
||||
|
||||
private static final String DEFAULT_REDIRECT_URL = "{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}";
|
||||
|
||||
@Test
|
||||
public void getBuilderWhenGoogleShouldHaveGoogleSettings() throws Exception {
|
||||
ClientRegistration registration = build(CommonOAuth2Provider.GOOGLE);
|
||||
ProviderDetails providerDetails = registration.getProviderDetails();
|
||||
assertThat(providerDetails.getAuthorizationUri())
|
||||
.isEqualTo("https://accounts.google.com/o/oauth2/v2/auth");
|
||||
assertThat(providerDetails.getTokenUri())
|
||||
.isEqualTo("https://www.googleapis.com/oauth2/v4/token");
|
||||
assertThat(providerDetails.getUserInfoEndpoint().getUri())
|
||||
.isEqualTo("https://www.googleapis.com/oauth2/v3/userinfo");
|
||||
assertThat(providerDetails.getUserInfoEndpoint().getUserNameAttributeName())
|
||||
.isEqualTo(null);
|
||||
assertThat(providerDetails.getJwkSetUri())
|
||||
.isEqualTo("https://www.googleapis.com/oauth2/v3/certs");
|
||||
assertThat(registration.getClientAuthenticationMethod())
|
||||
.isEqualTo(ClientAuthenticationMethod.BASIC);
|
||||
assertThat(registration.getAuthorizationGrantType())
|
||||
.isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
assertThat(registration.getRedirectUri()).isEqualTo(DEFAULT_REDIRECT_URL);
|
||||
assertThat(registration.getScope()).containsOnly("openid", "profile", "email",
|
||||
"address", "phone");
|
||||
assertThat(registration.getClientName()).isEqualTo("Google");
|
||||
assertThat(registration.getRegistrationId()).isEqualTo("123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBuilderWhenGitHubShouldHaveGitHubSettings() throws Exception {
|
||||
ClientRegistration registration = build(CommonOAuth2Provider.GITHUB);
|
||||
ProviderDetails providerDetails = registration.getProviderDetails();
|
||||
assertThat(providerDetails.getAuthorizationUri())
|
||||
.isEqualTo("https://github.com/login/oauth/authorize");
|
||||
assertThat(providerDetails.getTokenUri())
|
||||
.isEqualTo("https://github.com/login/oauth/access_token");
|
||||
assertThat(providerDetails.getUserInfoEndpoint().getUri())
|
||||
.isEqualTo("https://api.github.com/user");
|
||||
assertThat(providerDetails.getUserInfoEndpoint().getUserNameAttributeName())
|
||||
.isEqualTo("name");
|
||||
assertThat(providerDetails.getJwkSetUri()).isNull();
|
||||
assertThat(registration.getClientAuthenticationMethod())
|
||||
.isEqualTo(ClientAuthenticationMethod.BASIC);
|
||||
assertThat(registration.getAuthorizationGrantType())
|
||||
.isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
assertThat(registration.getRedirectUri()).isEqualTo(DEFAULT_REDIRECT_URL);
|
||||
assertThat(registration.getScope()).containsOnly("user");
|
||||
assertThat(registration.getClientName()).isEqualTo("GitHub");
|
||||
assertThat(registration.getRegistrationId()).isEqualTo("123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBuilderWhenFacebookShouldHaveFacebookSettings() throws Exception {
|
||||
ClientRegistration registration = build(CommonOAuth2Provider.FACEBOOK);
|
||||
ProviderDetails providerDetails = registration.getProviderDetails();
|
||||
assertThat(providerDetails.getAuthorizationUri())
|
||||
.isEqualTo("https://www.facebook.com/v2.8/dialog/oauth");
|
||||
assertThat(providerDetails.getTokenUri())
|
||||
.isEqualTo("https://graph.facebook.com/v2.8/oauth/access_token");
|
||||
assertThat(providerDetails.getUserInfoEndpoint().getUri())
|
||||
.isEqualTo("https://graph.facebook.com/me");
|
||||
assertThat(providerDetails.getUserInfoEndpoint().getUserNameAttributeName())
|
||||
.isEqualTo("name");
|
||||
assertThat(providerDetails.getJwkSetUri()).isNull();
|
||||
assertThat(registration.getClientAuthenticationMethod())
|
||||
.isEqualTo(ClientAuthenticationMethod.POST);
|
||||
assertThat(registration.getAuthorizationGrantType())
|
||||
.isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
assertThat(registration.getRedirectUri()).isEqualTo(DEFAULT_REDIRECT_URL);
|
||||
assertThat(registration.getScope()).containsOnly("public_profile", "email");
|
||||
assertThat(registration.getClientName()).isEqualTo("Facebook");
|
||||
assertThat(registration.getRegistrationId()).isEqualTo("123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBuilderWhenOktaShouldHaveOktaSettings() throws Exception {
|
||||
ClientRegistration registration = builder(CommonOAuth2Provider.OKTA)
|
||||
.authorizationUri("http://example.com/auth")
|
||||
.tokenUri("http://example.com/token")
|
||||
.userInfoUri("http://example.com/info").build();
|
||||
ProviderDetails providerDetails = registration.getProviderDetails();
|
||||
assertThat(providerDetails.getAuthorizationUri())
|
||||
.isEqualTo("http://example.com/auth");
|
||||
assertThat(providerDetails.getTokenUri()).isEqualTo("http://example.com/token");
|
||||
assertThat(providerDetails.getUserInfoEndpoint().getUri()).isEqualTo("http://example.com/info");
|
||||
assertThat(providerDetails.getUserInfoEndpoint().getUserNameAttributeName())
|
||||
.isEqualTo(null);
|
||||
assertThat(providerDetails.getJwkSetUri()).isNull();
|
||||
assertThat(registration.getClientAuthenticationMethod())
|
||||
.isEqualTo(ClientAuthenticationMethod.BASIC);
|
||||
assertThat(registration.getAuthorizationGrantType())
|
||||
.isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
assertThat(registration.getRedirectUri()).isEqualTo(DEFAULT_REDIRECT_URL);
|
||||
assertThat(registration.getScope()).containsOnly("openid", "profile", "email",
|
||||
"address", "phone");
|
||||
assertThat(registration.getClientName()).isEqualTo("Okta");
|
||||
assertThat(registration.getRegistrationId()).isEqualTo("123");
|
||||
}
|
||||
|
||||
private ClientRegistration build(CommonOAuth2Provider provider) {
|
||||
return builder(provider).build();
|
||||
}
|
||||
|
||||
private Builder builder(CommonOAuth2Provider provider) {
|
||||
return provider.getBuilder("123")
|
||||
.clientId("abcd")
|
||||
.clientSecret("secret");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Provider;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Registration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2ClientPropertiesRegistrationAdapter}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class OAuth2ClientPropertiesRegistrationAdapterTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void getClientRegistrationsWhenUsingDefinedProviderShouldAdapt()
|
||||
throws Exception {
|
||||
OAuth2ClientProperties properties = new OAuth2ClientProperties();
|
||||
Provider provider = new Provider();
|
||||
provider.setAuthorizationUri("http://example.com/auth");
|
||||
provider.setTokenUri("http://example.com/token");
|
||||
provider.setUserInfoUri("http://example.com/info");
|
||||
provider.setJwkSetUri("http://example.com/jkw");
|
||||
Registration registration = new Registration();
|
||||
registration.setProvider("provider");
|
||||
registration.setClientId("clientId");
|
||||
registration.setClientSecret("clientSecret");
|
||||
registration.setClientAuthenticationMethod(ClientAuthenticationMethod.POST);
|
||||
registration.setAuthorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
registration.setRedirectUri("http://example.com/redirect");
|
||||
registration.setScope(Collections.singleton("scope"));
|
||||
registration.setClientName("clientName");
|
||||
properties.getProvider().put("provider", provider);
|
||||
properties.getRegistration().put("registration", registration);
|
||||
Map<String, ClientRegistration> registrations = OAuth2ClientPropertiesRegistrationAdapter
|
||||
.getClientRegistrations(properties);
|
||||
ClientRegistration adapted = registrations.get("registration");
|
||||
ProviderDetails adaptedProvider = adapted.getProviderDetails();
|
||||
assertThat(adaptedProvider.getAuthorizationUri())
|
||||
.isEqualTo("http://example.com/auth");
|
||||
assertThat(adaptedProvider.getTokenUri()).isEqualTo("http://example.com/token");
|
||||
assertThat(adaptedProvider.getUserInfoEndpoint().getUri()).isEqualTo("http://example.com/info");
|
||||
assertThat(adaptedProvider.getJwkSetUri()).isEqualTo("http://example.com/jkw");
|
||||
assertThat(adapted.getRegistrationId()).isEqualTo("registration");
|
||||
assertThat(adapted.getClientId()).isEqualTo("clientId");
|
||||
assertThat(adapted.getClientSecret()).isEqualTo("clientSecret");
|
||||
assertThat(adapted.getClientAuthenticationMethod()).isEqualTo(
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod.POST);
|
||||
assertThat(adapted.getAuthorizationGrantType()).isEqualTo(
|
||||
org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
assertThat(adapted.getRedirectUri()).isEqualTo("http://example.com/redirect");
|
||||
assertThat(adapted.getScope()).containsExactly("scope");
|
||||
assertThat(adapted.getClientName()).isEqualTo("clientName");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getClientRegistrationsWhenUsingCommonProviderShouldAdapt()
|
||||
throws Exception {
|
||||
OAuth2ClientProperties properties = new OAuth2ClientProperties();
|
||||
Registration registration = new Registration();
|
||||
registration.setProvider("google");
|
||||
registration.setClientId("clientId");
|
||||
registration.setClientSecret("clientSecret");
|
||||
properties.getRegistration().put("registration", registration);
|
||||
Map<String, ClientRegistration> registrations = OAuth2ClientPropertiesRegistrationAdapter
|
||||
.getClientRegistrations(properties);
|
||||
ClientRegistration adapted = registrations.get("registration");
|
||||
ProviderDetails adaptedProvider = adapted.getProviderDetails();
|
||||
assertThat(adaptedProvider.getAuthorizationUri())
|
||||
.isEqualTo("https://accounts.google.com/o/oauth2/v2/auth");
|
||||
assertThat(adaptedProvider.getTokenUri())
|
||||
.isEqualTo("https://www.googleapis.com/oauth2/v4/token");
|
||||
assertThat(adaptedProvider.getUserInfoEndpoint().getUri())
|
||||
.isEqualTo("https://www.googleapis.com/oauth2/v3/userinfo");
|
||||
assertThat(adaptedProvider.getJwkSetUri())
|
||||
.isEqualTo("https://www.googleapis.com/oauth2/v3/certs");
|
||||
assertThat(adapted.getRegistrationId()).isEqualTo("registration");
|
||||
assertThat(adapted.getClientId()).isEqualTo("clientId");
|
||||
assertThat(adapted.getClientSecret()).isEqualTo("clientSecret");
|
||||
assertThat(adapted.getClientAuthenticationMethod()).isEqualTo(
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod.BASIC);
|
||||
assertThat(adapted.getAuthorizationGrantType()).isEqualTo(
|
||||
org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
assertThat(adapted.getRedirectUri()).isEqualTo(
|
||||
"{scheme}://{serverName}:{serverPort}{contextPath}/oauth2/authorize/code/{clientAlias}");
|
||||
assertThat(adapted.getScope()).containsExactly("openid", "profile", "email",
|
||||
"address", "phone");
|
||||
assertThat(adapted.getClientName()).isEqualTo("Google");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getClientRegistrationsWhenUsingCommonProviderWithOverrideShouldAdapt()
|
||||
throws Exception {
|
||||
OAuth2ClientProperties properties = new OAuth2ClientProperties();
|
||||
Registration registration = new Registration();
|
||||
registration.setProvider("google");
|
||||
registration.setClientId("clientId");
|
||||
registration.setClientSecret("clientSecret");
|
||||
registration.setClientAuthenticationMethod(ClientAuthenticationMethod.POST);
|
||||
registration.setAuthorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
registration.setRedirectUri("http://example.com/redirect");
|
||||
registration.setScope(Collections.singleton("scope"));
|
||||
registration.setClientName("clientName");
|
||||
properties.getRegistration().put("registration", registration);
|
||||
Map<String, ClientRegistration> registrations = OAuth2ClientPropertiesRegistrationAdapter
|
||||
.getClientRegistrations(properties);
|
||||
ClientRegistration adapted = registrations.get("registration");
|
||||
ProviderDetails adaptedProvider = adapted.getProviderDetails();
|
||||
assertThat(adaptedProvider.getAuthorizationUri())
|
||||
.isEqualTo("https://accounts.google.com/o/oauth2/v2/auth");
|
||||
assertThat(adaptedProvider.getTokenUri())
|
||||
.isEqualTo("https://www.googleapis.com/oauth2/v4/token");
|
||||
assertThat(adaptedProvider.getUserInfoEndpoint().getUri())
|
||||
.isEqualTo("https://www.googleapis.com/oauth2/v3/userinfo");
|
||||
assertThat(adaptedProvider.getJwkSetUri())
|
||||
.isEqualTo("https://www.googleapis.com/oauth2/v3/certs");
|
||||
assertThat(adapted.getRegistrationId()).isEqualTo("registration");
|
||||
assertThat(adapted.getClientId()).isEqualTo("clientId");
|
||||
assertThat(adapted.getClientSecret()).isEqualTo("clientSecret");
|
||||
assertThat(adapted.getClientAuthenticationMethod()).isEqualTo(
|
||||
org.springframework.security.oauth2.core.ClientAuthenticationMethod.POST);
|
||||
assertThat(adapted.getAuthorizationGrantType()).isEqualTo(
|
||||
org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
assertThat(adapted.getRedirectUri()).isEqualTo("http://example.com/redirect");
|
||||
assertThat(adapted.getScope()).containsExactly("scope");
|
||||
assertThat(adapted.getClientName()).isEqualTo("clientName");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getClientRegistrationsWhenUnknownProviderShouldThrowException()
|
||||
throws Exception {
|
||||
OAuth2ClientProperties properties = new OAuth2ClientProperties();
|
||||
Registration registration = new Registration();
|
||||
registration.setProvider("missing");
|
||||
properties.getRegistration().put("registration", registration);
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Unknown provider ID 'missing'");
|
||||
OAuth2ClientPropertiesRegistrationAdapter.getClientRegistrations(properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2ClientProperties}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class OAuth2ClientPropertiesTests {
|
||||
|
||||
private OAuth2ClientProperties properties = new OAuth2ClientProperties();
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void clientIdAbsentThrowsException() throws Exception {
|
||||
OAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();
|
||||
registration.setClientSecret("secret");
|
||||
registration.setProvider("google");
|
||||
this.properties.getRegistration().put("foo", registration);
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Client id must not be empty.");
|
||||
this.properties.validate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clientSecretAbsentThrowsException() throws Exception {
|
||||
OAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();
|
||||
registration.setClientId("foo");
|
||||
registration.setProvider("google");
|
||||
this.properties.getRegistration().put("foo", registration);
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Client secret must not be empty.");
|
||||
this.properties.validate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void providerAbsentThrowsException() throws Exception {
|
||||
OAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();
|
||||
registration.setClientId("foo");
|
||||
registration.setClientSecret("secret");
|
||||
this.properties.getRegistration().put("foo", registration);
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Provider must not be empty.");
|
||||
this.properties.validate();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2ClientRegistrationRepositoryConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class OAuth2ClientRegistrationRepositoryConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
|
||||
|
||||
private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration";
|
||||
|
||||
@Test
|
||||
public void clientRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() throws Exception {
|
||||
this.contextRunner.withUserConfiguration(OAuth2ClientRegistrationRepositoryConfiguration.class)
|
||||
.run(context -> assertThat(context).doesNotHaveBean(ClientRegistrationRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clientRegistrationRepositoryBeanShouldBeCreatedWhenPropertiesPresent() throws Exception {
|
||||
this.contextRunner.withUserConfiguration(OAuth2ClientRegistrationRepositoryConfiguration.class)
|
||||
.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd",
|
||||
REGISTRATION_PREFIX + ".foo.client-secret=secret",
|
||||
REGISTRATION_PREFIX + ".foo.provider=github")
|
||||
.run(context -> {
|
||||
ClientRegistrationRepository repository = context.getBean(ClientRegistrationRepository.class);
|
||||
ClientRegistration registration = repository.findByRegistrationId("foo");
|
||||
assertThat(registration).isNotNull();
|
||||
assertThat(registration.getClientSecret()).isEqualTo("secret");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.AuthorizationCodeAuthenticationProcessingFilter;
|
||||
import org.springframework.security.oauth2.client.web.AuthorizationCodeRequestRedirectFilter;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2WebSecurityConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class OAuth2WebSecurityConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void securityConfigurerRegistersClientRegistrations() throws Exception {
|
||||
this.contextRunner.withUserConfiguration(
|
||||
ClientRepositoryConfiguration.class, OAuth2WebSecurityConfiguration.class)
|
||||
.run(context -> {
|
||||
ClientRegistrationRepository expected = context.getBean(ClientRegistrationRepository.class);
|
||||
ClientRegistrationRepository actual = (ClientRegistrationRepository) ReflectionTestUtils.getField(
|
||||
getAuthCodeFilters(context).get(0), "clientRegistrationRepository");
|
||||
assertThat(isEqual(expected.findByRegistrationId("first"),
|
||||
actual.findByRegistrationId("first"))).isTrue();
|
||||
assertThat(isEqual(expected.findByRegistrationId("second"),
|
||||
actual.findByRegistrationId("second"))).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void securityConfigurerBacksOffWhenClientRegistrationBeanAbsent() throws Exception {
|
||||
this.contextRunner.withUserConfiguration(TestConfig.class, OAuth2WebSecurityConfiguration.class)
|
||||
.run(context -> assertThat(getAuthCodeFilters(context)).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void securityConfigurerBacksOffWhenOtherWebSecurityAdapterPresent() throws Exception {
|
||||
this.contextRunner.withUserConfiguration(TestWebSecurityConfigurerConfig.class, OAuth2WebSecurityConfiguration.class)
|
||||
.run(context -> assertThat(getAuthCodeFilters(context)).isEmpty());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Filter> getAuthCodeFilters(AssertableApplicationContext context) {
|
||||
FilterChainProxy filterChain = (FilterChainProxy) context.getBean("springSecurityFilterChain");
|
||||
List<SecurityFilterChain> filterChains = filterChain.getFilterChains();
|
||||
List<Filter> filters = (List<Filter>) ReflectionTestUtils.getField(((List) filterChains).get(0), "filters");
|
||||
List<Filter> oauth2Filters = filters.stream().filter(
|
||||
f -> f instanceof AuthorizationCodeAuthenticationProcessingFilter ||
|
||||
f instanceof AuthorizationCodeRequestRedirectFilter).collect(Collectors.toList());
|
||||
return oauth2Filters.stream().filter(f -> f instanceof AuthorizationCodeAuthenticationProcessingFilter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private boolean isEqual(ClientRegistration reg1, ClientRegistration reg2) {
|
||||
boolean result = ObjectUtils.nullSafeEquals(reg1.getClientId(), reg2.getClientId());
|
||||
result = result && ObjectUtils.nullSafeEquals(reg1.getClientName(), reg2.getClientName());
|
||||
result = result && ObjectUtils.nullSafeEquals(reg1.getClientSecret(), reg2.getClientSecret());
|
||||
result = result && ObjectUtils.nullSafeEquals(reg1.getScope(), reg2.getScope());
|
||||
result = result && ObjectUtils.nullSafeEquals(reg1.getRedirectUri(), reg2.getRedirectUri());
|
||||
result = result && ObjectUtils.nullSafeEquals(reg1.getRegistrationId(), reg2.getRegistrationId());
|
||||
result = result && ObjectUtils.nullSafeEquals(reg1.getAuthorizationGrantType(), reg2.getAuthorizationGrantType());
|
||||
result = result && ObjectUtils.nullSafeEquals(reg1.getProviderDetails().getAuthorizationUri(),
|
||||
reg2.getProviderDetails().getAuthorizationUri());
|
||||
result = result && ObjectUtils.nullSafeEquals(reg1.getProviderDetails().getUserInfoEndpoint(),
|
||||
reg2.getProviderDetails().getUserInfoEndpoint());
|
||||
result = result && ObjectUtils.nullSafeEquals(reg1.getProviderDetails().getTokenUri(),
|
||||
reg2.getProviderDetails().getTokenUri());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
protected static class TestConfig {
|
||||
|
||||
@Bean
|
||||
public TomcatServletWebServerFactory tomcat() {
|
||||
return new TomcatServletWebServerFactory(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfig.class)
|
||||
static class ClientRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
public ClientRegistrationRepository clientRegistrationRepository() {
|
||||
List<ClientRegistration> registrations = new ArrayList<>();
|
||||
registrations.add(getClientRegistration("first", "http://user-info-uri.com"));
|
||||
registrations.add(getClientRegistration("second", "http://other-user-info"));
|
||||
return new InMemoryClientRegistrationRepository(registrations);
|
||||
}
|
||||
|
||||
private ClientRegistration getClientRegistration(String id, String userInfoUri) {
|
||||
ClientRegistration.Builder builder = new ClientRegistration.Builder(id);
|
||||
builder.clientName("foo")
|
||||
.clientId("foo")
|
||||
.clientAuthenticationMethod(org.springframework.security.oauth2.core.ClientAuthenticationMethod.BASIC)
|
||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||
.scope("read")
|
||||
.clientSecret("secret")
|
||||
.redirectUri("http://redirect-uri.com")
|
||||
.authorizationUri("http://authorization-uri.com")
|
||||
.tokenUri("http://token-uri.com")
|
||||
.userInfoUri(userInfoUri)
|
||||
.userNameAttributeName("login");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ ClientRepositoryConfiguration.class })
|
||||
static class TestWebSecurityConfigurerConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2750,6 +2750,58 @@ NOTE: By default, a `WebSecurityConfigurerAdapter` will match any path. If you d
|
|||
to completely override Spring Boot's auto-configured access rules, your adapter must
|
||||
explicitly configure the paths that you do want to override.
|
||||
|
||||
[[boot-features-security-oauth2]]
|
||||
=== OAuth2
|
||||
|
||||
=== Client
|
||||
|
||||
If you have `spring-security-oauth2-client` on your classpath you can take advantage of some
|
||||
auto-configuration to make it easy to set up an OAuth2 Client. This configuration makes use of
|
||||
the properties under `OAuth2ClientProperties`.
|
||||
You can register multiple OAuth2 clients and providers under the `spring.security.oauth2.client` prefix.
|
||||
For example,
|
||||
|
||||
[source,yaml,indent=0]
|
||||
----
|
||||
# application.yml
|
||||
|
||||
spring:
|
||||
security:
|
||||
oauth2:
|
||||
client:
|
||||
registration:
|
||||
my-client-1:
|
||||
client-id: abcd
|
||||
client-secret: password
|
||||
client-name: Client for user scope
|
||||
provider: my-oauth-provider
|
||||
scope: user
|
||||
redirect-uri: http://my-redirect-uri.com
|
||||
authentication-method: basic
|
||||
authorization-grant-type: authorization_code
|
||||
my-client2:
|
||||
client-id: abcd
|
||||
client-secret: password
|
||||
client-name: Client for email scope
|
||||
provider: my-oauth-provider
|
||||
scope: email
|
||||
redirect-uri: http://my-redirect-uri.com
|
||||
authentication-method: basic
|
||||
authorization-grant-type: authorization_code
|
||||
provider:
|
||||
my-oauth-provider:
|
||||
authorization-uri: http://my-auth-server/oauth/authorize
|
||||
token-uri: http://my-auth-server/oauth/token
|
||||
user-info-uri: http://my-auth-server/userinfo
|
||||
jwk-set-uri: http://my-auth-server/token_keys
|
||||
user-name-attribute: name
|
||||
|
||||
# additional configuration as required
|
||||
----
|
||||
|
||||
NOTE: For common OAuth2 and OpenID providers such as Google, Github, Facebook and Okta, we provide a set of
|
||||
provider defaults. If you don't need to customize these providers, you do not need to provide the `provider`
|
||||
configuration. The client registration `provider` key should reference one these providers.
|
||||
|
||||
|
||||
[[boot-features-security-actuator]]
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
<module>spring-boot-sample-junit-jupiter</module>
|
||||
<module>spring-boot-sample-liquibase</module>
|
||||
<module>spring-boot-sample-logback</module>
|
||||
<module>spring-boot-sample-oauth2-client</module>
|
||||
<module>spring-boot-sample-parent-context</module>
|
||||
<module>spring-boot-sample-profile</module>
|
||||
<module>spring-boot-sample-property-validation</module>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-samples</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-sample-oauth2-client</artifactId>
|
||||
<name>Spring Boot Sample OAuth2 Client</name>
|
||||
<description>Spring Boot Sample OAuth2 Client</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<!-- Compile -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-jwt-jose</artifactId>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package sample.oauth2.client;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@RestController
|
||||
public class ExampleController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String email(Principal principal) {
|
||||
return "Hello " + principal.getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package sample.oauth2.client;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SampleOAuth2ClientApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleOAuth2ClientApplication.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
spring:
|
||||
security:
|
||||
oauth2:
|
||||
client:
|
||||
registration:
|
||||
github-client-1:
|
||||
client-id: 1b4c6c2d23a2dbec8959
|
||||
client-secret: 8bdb4047d98f37e1c6aeba9ffd2017bc31682e1b
|
||||
client-name: Github user
|
||||
provider: github
|
||||
scope: user
|
||||
redirect_uri: http://localhost:8080/oauth2/authorize/code/github
|
||||
github-client-2:
|
||||
client-id: 1b4c6c2d23a2dbec8959
|
||||
client-secret: 8bdb4047d98f37e1c6aeba9ffd2017bc31682e1b
|
||||
client-name: Github email
|
||||
provider: github
|
||||
scope: user:email
|
||||
redirect_uri: http://localhost:8080/oauth2/authorize/code/github
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package sample.oauth2.client;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for an OAuth2 client application.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@DirtiesContext
|
||||
public class SampleOAuth2ClientApplicationTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
public void everythingShouldRedirectToLogin() throws Exception {
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
|
||||
assertThat(entity.getHeaders().getLocation())
|
||||
.isEqualTo(URI.create("http://localhost:" + this.port + "/login"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loginShouldHaveBothOAuthClientsToChooseFrom() throws Exception {
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/login", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("/oauth2/authorization/code/github-client-1");
|
||||
assertThat(entity.getBody()).contains("/oauth2/authorization/code/github-client-2");
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue