/* * 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.authserver; import java.util.Arrays; import java.util.Collections; import java.util.UUID; import javax.annotation.PostConstruct; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.security.oauth2.OAuth2ClientProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.oauth2.config.annotation.builders.ClientDetailsServiceBuilder; import org.springframework.security.oauth2.config.annotation.builders.InMemoryClientDetailsServiceBuilder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.client.BaseClientDetails; import org.springframework.security.oauth2.provider.token.AccessTokenConverter; import org.springframework.security.oauth2.provider.token.TokenStore; /** * Configuration for a Spring Security OAuth2 authorization server. Back off if another * {@link AuthorizationServerConfigurer} already exists or if authorization server is not * enabled. * * @author Greg Turnquist * @author Dave Syer * @since 1.3.0 */ @Configuration @ConditionalOnClass(EnableAuthorizationServer.class) @ConditionalOnMissingBean(AuthorizationServerConfigurer.class) @ConditionalOnBean(AuthorizationServerEndpointsConfiguration.class) @EnableConfigurationProperties(AuthorizationServerProperties.class) public class OAuth2AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { private static final Log logger = LogFactory .getLog(OAuth2AuthorizationServerConfiguration.class); private final BaseClientDetails details; private final AuthenticationManager authenticationManager; private final TokenStore tokenStore; private final AccessTokenConverter tokenConverter; private final AuthorizationServerProperties properties; public OAuth2AuthorizationServerConfiguration(BaseClientDetails details, AuthenticationManager authenticationManager, ObjectProvider<TokenStore> tokenStore, ObjectProvider<AccessTokenConverter> tokenConverter, AuthorizationServerProperties properties) { this.details = details; this.authenticationManager = authenticationManager; this.tokenStore = tokenStore.getIfAvailable(); this.tokenConverter = tokenConverter.getIfAvailable(); this.properties = properties; } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { ClientDetailsServiceBuilder<InMemoryClientDetailsServiceBuilder>.ClientBuilder builder = clients .inMemory().withClient(this.details.getClientId()); builder.secret(this.details.getClientSecret()) .resourceIds(this.details.getResourceIds().toArray(new String[0])) .authorizedGrantTypes( this.details.getAuthorizedGrantTypes().toArray(new String[0])) .authorities( AuthorityUtils.authorityListToSet(this.details.getAuthorities()) .toArray(new String[0])) .scopes(this.details.getScope().toArray(new String[0])); if (this.details.getAutoApproveScopes() != null) { builder.autoApprove( this.details.getAutoApproveScopes().toArray(new String[0])); } if (this.details.getAccessTokenValiditySeconds() != null) { builder.accessTokenValiditySeconds( this.details.getAccessTokenValiditySeconds()); } if (this.details.getRefreshTokenValiditySeconds() != null) { builder.refreshTokenValiditySeconds( this.details.getRefreshTokenValiditySeconds()); } if (this.details.getRegisteredRedirectUri() != null) { builder.redirectUris( this.details.getRegisteredRedirectUri().toArray(new String[0])); } } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { if (this.tokenConverter != null) { endpoints.accessTokenConverter(this.tokenConverter); } if (this.tokenStore != null) { endpoints.tokenStore(this.tokenStore); } if (this.details.getAuthorizedGrantTypes().contains("password")) { endpoints.authenticationManager(this.authenticationManager); } } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { if (this.properties.getCheckTokenAccess() != null) { security.checkTokenAccess(this.properties.getCheckTokenAccess()); } if (this.properties.getTokenKeyAccess() != null) { security.tokenKeyAccess(this.properties.getTokenKeyAccess()); } if (this.properties.getRealm() != null) { security.realm(this.properties.getRealm()); } } @Configuration protected static class ClientDetailsLogger { private final OAuth2ClientProperties credentials; protected ClientDetailsLogger(OAuth2ClientProperties credentials) { this.credentials = credentials; } @PostConstruct public void init() { String prefix = "security.oauth2.client"; boolean defaultSecret = this.credentials.isDefaultSecret(); logger.info(String.format( "Initialized OAuth2 Client%n%n%s.clientId = %s%n%s.secret = %s%n%n", prefix, this.credentials.getClientId(), prefix, defaultSecret ? this.credentials.getClientSecret() : "****")); } } @Configuration @ConditionalOnMissingBean(BaseClientDetails.class) protected static class BaseClientDetailsConfiguration { private final OAuth2ClientProperties client; protected BaseClientDetailsConfiguration(OAuth2ClientProperties client) { this.client = client; } @Bean @ConfigurationProperties(prefix = "security.oauth2.client") public BaseClientDetails oauth2ClientDetails() { BaseClientDetails details = new BaseClientDetails(); if (this.client.getClientId() == null) { this.client.setClientId(UUID.randomUUID().toString()); } details.setClientId(this.client.getClientId()); details.setClientSecret(this.client.getClientSecret()); details.setAuthorizedGrantTypes(Arrays.asList("authorization_code", "password", "client_credentials", "implicit", "refresh_token")); details.setAuthorities( AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER")); details.setRegisteredRedirectUri(Collections.<String>emptySet()); return details; } } }