/*
* Copyright 2015 Petr Bouda
*
* 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.joyrest.oauth2.initializer;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
import org.joyrest.context.initializer.BeanFactory;
import org.joyrest.context.initializer.InitContext;
import org.joyrest.context.initializer.Initializer;
import org.joyrest.oauth2.endpoint.AuthorizationEndpoint;
import org.joyrest.oauth2.endpoint.TokenEndpoint;
import org.joyrest.oauth2.handler.OAuthExceptionConfiguration;
import org.joyrest.oauth2.interceptor.AuthenticationInterceptor;
import org.joyrest.oauth2.interceptor.AuthorizationInterceptor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter;
import org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeTokenGranter;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.implicit.ImplicitTokenGranter;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.util.ClassUtils;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.Objects.isNull;
public class OAuth2Initializer implements Initializer {
@Override
@SuppressWarnings("unchecked")
public void init(InitContext context, BeanFactory beanFactory) {
AuthorizationServerConfiguration authServerConfig = beanFactory.get(AuthorizationServerConfiguration.class);
TokenStore tokenStore = authServerConfig.getTokenStore();
UserDetailsService userService = authServerConfig.getUserDetailsService();
ClientDetailsService clientService = authServerConfig.getClientDetailsService();
DataSource dataSource = authServerConfig.getDataSource();
PreAuthenticatedAuthenticationProvider preProvider = new PreAuthenticatedAuthenticationProvider();
preProvider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper(userService));
DaoAuthenticationProvider clientAuthProvider = new DaoAuthenticationProvider();
clientAuthProvider.setUserDetailsService(new ClientDetailsUserDetailsService(clientService));
DaoAuthenticationProvider userAuthProvider = new DaoAuthenticationProvider();
userAuthProvider.setUserDetailsService(userService);
ProviderManager clientManager = new ProviderManager(singletonList(clientAuthProvider));
ProviderManager userManager = new ProviderManager(asList(userAuthProvider, preProvider));
AuthorizationCodeServices authServices = new InMemoryAuthorizationCodeServices();
OAuth2RequestFactory requestFactory = new DefaultOAuth2RequestFactory(clientService);
DefaultTokenServices tokenServices = tokenServices(clientService, userManager, tokenStore, dataSource);
TokenGranter tokenGranter = compositeTokenGranter(clientService, userManager, tokenServices, requestFactory,
authServices);
TokenEndpoint tokenEndpoint = new TokenEndpoint(clientManager, clientService, tokenGranter);
TokenStoreUserApprovalHandler userApprovalHandler = new TokenStoreUserApprovalHandler();
userApprovalHandler.setClientDetailsService(clientService);
userApprovalHandler.setRequestFactory(requestFactory);
userApprovalHandler.setTokenStore(tokenStore);
AuthorizationEndpoint authorizationEndpoint = new AuthorizationEndpoint(
authServices, clientService, tokenGranter, userApprovalHandler, requestFactory);
context.addControllerConfiguration(tokenEndpoint);
context.addControllerConfiguration(authorizationEndpoint);
context.addExceptionConfiguration(new OAuthExceptionConfiguration());
context.addInterceptor(new AuthenticationInterceptor(clientManager));
context.addInterceptor(new AuthorizationInterceptor());
}
private TokenGranter compositeTokenGranter(final ClientDetailsService clientService,
final AuthenticationManager manager,
final DefaultTokenServices tokenServices,
final OAuth2RequestFactory requestFactory,
final AuthorizationCodeServices authorizationCodeServices) {
List<TokenGranter> granters = new ArrayList<>();
granters.add(new ClientCredentialsTokenGranter(tokenServices, clientService, requestFactory));
granters.add(new ImplicitTokenGranter(tokenServices, clientService, requestFactory));
granters.add(new ResourceOwnerPasswordTokenGranter(manager, tokenServices, clientService, requestFactory));
granters.add(new RefreshTokenGranter(tokenServices, clientService, requestFactory));
granters.add(new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientService, requestFactory));
return new CompositeTokenGranter(granters);
}
private DefaultTokenServices tokenServices(final ClientDetailsService clientService,
final AuthenticationManager manager,
final TokenStore tokenStore,
final DataSource dataSource) {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(clientService);
tokenServices.setAuthenticationManager(manager);
tokenServices.setTokenStore(tokenStore);
if (isNull(dataSource)) {
return tokenServices;
} else {
return txProxiedTokenServices(tokenServices, dataSource);
}
}
private DefaultTokenServices txProxiedTokenServices(DefaultTokenServices tokenServices, DataSource dataSource) {
AnnotationTransactionAttributeSource attrSource = new AnnotationTransactionAttributeSource();
DataSourceTransactionManager txManager = new DataSourceTransactionManager(dataSource);
TransactionInterceptor txInterceptor = transactionInterceptor(attrSource, txManager);
BeanFactoryTransactionAttributeSourceAdvisor txAdvisor = transactionAdvisor(attrSource, txInterceptor);
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
ProxyFactory proxyFactory = new ProxyFactory(tokenServices);
proxyFactory.addAdvice(txInterceptor);
proxyFactory.addAdvisor(txAdvisor);
proxyFactory.setInterfaces(
ClassUtils.getAllInterfacesForClass(
new SingletonTargetSource(tokenServices).getTargetClass(), classLoader));
return (DefaultTokenServices) proxyFactory.getProxy(classLoader);
}
private BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
AnnotationTransactionAttributeSource source, TransactionInterceptor interceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(source);
advisor.setAdvice(interceptor);
return advisor;
}
private TransactionInterceptor transactionInterceptor(
AnnotationTransactionAttributeSource source, PlatformTransactionManager txManager) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(source);
interceptor.setTransactionManager(txManager);
return interceptor;
}
}