2 changed files with 191 additions and 147 deletions
@ -0,0 +1,172 @@
@@ -0,0 +1,172 @@
|
||||
/* |
||||
* Copyright 2020-2021 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 |
||||
* |
||||
* https://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.security.config.annotation.web.configurers.oauth2.server.authorization; |
||||
|
||||
import java.util.Map; |
||||
|
||||
import com.nimbusds.jose.jwk.source.JWKSource; |
||||
import com.nimbusds.jose.proc.SecurityContext; |
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils; |
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException; |
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.core.ResolvableType; |
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder; |
||||
import org.springframework.security.oauth2.jwt.JwtEncoder; |
||||
import org.springframework.security.oauth2.jwt.NimbusJwsEncoder; |
||||
import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService; |
||||
import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; |
||||
import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; |
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; |
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; |
||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; |
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; |
||||
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* Utility methods for the OAuth 2.0 Configurers. |
||||
* |
||||
* @author Joe Grandja |
||||
* @since 0.1.2 |
||||
*/ |
||||
final class OAuth2ConfigurerUtils { |
||||
|
||||
private OAuth2ConfigurerUtils() { |
||||
} |
||||
|
||||
static <B extends HttpSecurityBuilder<B>> RegisteredClientRepository getRegisteredClientRepository(B builder) { |
||||
RegisteredClientRepository registeredClientRepository = builder.getSharedObject(RegisteredClientRepository.class); |
||||
if (registeredClientRepository == null) { |
||||
registeredClientRepository = getBean(builder, RegisteredClientRepository.class); |
||||
builder.setSharedObject(RegisteredClientRepository.class, registeredClientRepository); |
||||
} |
||||
return registeredClientRepository; |
||||
} |
||||
|
||||
static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizationService getAuthorizationService(B builder) { |
||||
OAuth2AuthorizationService authorizationService = builder.getSharedObject(OAuth2AuthorizationService.class); |
||||
if (authorizationService == null) { |
||||
authorizationService = getOptionalBean(builder, OAuth2AuthorizationService.class); |
||||
if (authorizationService == null) { |
||||
authorizationService = new InMemoryOAuth2AuthorizationService(); |
||||
} |
||||
builder.setSharedObject(OAuth2AuthorizationService.class, authorizationService); |
||||
} |
||||
return authorizationService; |
||||
} |
||||
|
||||
static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizationConsentService getAuthorizationConsentService(B builder) { |
||||
OAuth2AuthorizationConsentService authorizationConsentService = builder.getSharedObject(OAuth2AuthorizationConsentService.class); |
||||
if (authorizationConsentService == null) { |
||||
authorizationConsentService = getOptionalBean(builder, OAuth2AuthorizationConsentService.class); |
||||
if (authorizationConsentService == null) { |
||||
authorizationConsentService = new InMemoryOAuth2AuthorizationConsentService(); |
||||
} |
||||
builder.setSharedObject(OAuth2AuthorizationConsentService.class, authorizationConsentService); |
||||
} |
||||
return authorizationConsentService; |
||||
} |
||||
|
||||
static <B extends HttpSecurityBuilder<B>> JwtEncoder getJwtEncoder(B builder) { |
||||
JwtEncoder jwtEncoder = builder.getSharedObject(JwtEncoder.class); |
||||
if (jwtEncoder == null) { |
||||
jwtEncoder = getOptionalBean(builder, JwtEncoder.class); |
||||
if (jwtEncoder == null) { |
||||
JWKSource<SecurityContext> jwkSource = getJwkSource(builder); |
||||
jwtEncoder = new NimbusJwsEncoder(jwkSource); |
||||
} |
||||
builder.setSharedObject(JwtEncoder.class, jwtEncoder); |
||||
} |
||||
return jwtEncoder; |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
static <B extends HttpSecurityBuilder<B>> JWKSource<SecurityContext> getJwkSource(B builder) { |
||||
JWKSource<SecurityContext> jwkSource = builder.getSharedObject(JWKSource.class); |
||||
if (jwkSource == null) { |
||||
ResolvableType type = ResolvableType.forClassWithGenerics(JWKSource.class, SecurityContext.class); |
||||
jwkSource = getBean(builder, type); |
||||
builder.setSharedObject(JWKSource.class, jwkSource); |
||||
} |
||||
return jwkSource; |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
static <B extends HttpSecurityBuilder<B>> OAuth2TokenCustomizer<JwtEncodingContext> getJwtCustomizer(B builder) { |
||||
OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = builder.getSharedObject(OAuth2TokenCustomizer.class); |
||||
if (jwtCustomizer == null) { |
||||
ResolvableType type = ResolvableType.forClassWithGenerics(OAuth2TokenCustomizer.class, JwtEncodingContext.class); |
||||
jwtCustomizer = getOptionalBean(builder, type); |
||||
if (jwtCustomizer != null) { |
||||
builder.setSharedObject(OAuth2TokenCustomizer.class, jwtCustomizer); |
||||
} |
||||
} |
||||
return jwtCustomizer; |
||||
} |
||||
|
||||
static <B extends HttpSecurityBuilder<B>> ProviderSettings getProviderSettings(B builder) { |
||||
ProviderSettings providerSettings = builder.getSharedObject(ProviderSettings.class); |
||||
if (providerSettings == null) { |
||||
providerSettings = getOptionalBean(builder, ProviderSettings.class); |
||||
if (providerSettings == null) { |
||||
providerSettings = new ProviderSettings(); |
||||
} |
||||
builder.setSharedObject(ProviderSettings.class, providerSettings); |
||||
} |
||||
return providerSettings; |
||||
} |
||||
|
||||
static <B extends HttpSecurityBuilder<B>, T> T getBean(B builder, Class<T> type) { |
||||
return builder.getSharedObject(ApplicationContext.class).getBean(type); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
static <B extends HttpSecurityBuilder<B>, T> T getBean(B builder, ResolvableType type) { |
||||
ApplicationContext context = builder.getSharedObject(ApplicationContext.class); |
||||
String[] names = context.getBeanNamesForType(type); |
||||
if (names.length == 1) { |
||||
return (T) context.getBean(names[0]); |
||||
} |
||||
if (names.length > 1) { |
||||
throw new NoUniqueBeanDefinitionException(type, names); |
||||
} |
||||
throw new NoSuchBeanDefinitionException(type); |
||||
} |
||||
|
||||
static <B extends HttpSecurityBuilder<B>, T> T getOptionalBean(B builder, Class<T> type) { |
||||
Map<String, T> beansMap = BeanFactoryUtils.beansOfTypeIncludingAncestors( |
||||
builder.getSharedObject(ApplicationContext.class), type); |
||||
if (beansMap.size() > 1) { |
||||
throw new NoUniqueBeanDefinitionException(type, beansMap.size(), |
||||
"Expected single matching bean of type '" + type.getName() + "' but found " + |
||||
beansMap.size() + ": " + StringUtils.collectionToCommaDelimitedString(beansMap.keySet())); |
||||
} |
||||
return (!beansMap.isEmpty() ? beansMap.values().iterator().next() : null); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
static <B extends HttpSecurityBuilder<B>, T> T getOptionalBean(B builder, ResolvableType type) { |
||||
ApplicationContext context = builder.getSharedObject(ApplicationContext.class); |
||||
String[] names = context.getBeanNamesForType(type); |
||||
if (names.length > 1) { |
||||
throw new NoUniqueBeanDefinitionException(type, names); |
||||
} |
||||
return names.length == 1 ? (T) context.getBean(names[0]) : null; |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue