/*
* Copyright 2008-2009 Web Cohesion
*
* 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.security.oauth.config;
import java.util.List;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.config.BeanIds;
import org.springframework.security.oauth.provider.filter.AccessTokenProcessingFilter;
import org.springframework.security.oauth.provider.filter.ProtectedResourceProcessingFilter;
import org.springframework.security.oauth.provider.filter.UnauthenticatedRequestTokenProcessingFilter;
import org.springframework.security.oauth.provider.filter.UserAuthorizationProcessingFilter;
import org.springframework.security.oauth.provider.filter.UserAuthorizationSuccessfulAuthenticationHandler;
import org.springframework.security.oauth.provider.verifier.RandomValueVerifierServices;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Parser for the OAuth "provider" element.
*
* @author Ryan Heaton
* @author Andrew McCall
*/
public class OAuthProviderBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
String consumerDetailsRef = element.getAttribute("consumer-details-service-ref");
String tokenServicesRef = element.getAttribute("token-services-ref");
BeanDefinitionBuilder requestTokenFilterBean = BeanDefinitionBuilder.rootBeanDefinition(UnauthenticatedRequestTokenProcessingFilter.class);
if (StringUtils.hasText(consumerDetailsRef)) {
requestTokenFilterBean.addPropertyReference("consumerDetailsService", consumerDetailsRef);
}
if (StringUtils.hasText(tokenServicesRef)) {
requestTokenFilterBean.addPropertyReference("tokenServices", tokenServicesRef);
}
String requestTokenURL = element.getAttribute("request-token-url");
if (StringUtils.hasText(requestTokenURL)) {
requestTokenFilterBean.addPropertyValue("filterProcessesUrl", requestTokenURL);
}
BeanDefinitionBuilder authenticateTokenFilterBean = BeanDefinitionBuilder.rootBeanDefinition(UserAuthorizationProcessingFilter.class);
authenticateTokenFilterBean.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER);
if (StringUtils.hasText(tokenServicesRef)) {
authenticateTokenFilterBean.addPropertyReference("tokenServices", tokenServicesRef);
}
String authenticateTokenURL = element.getAttribute("authenticate-token-url");
if (StringUtils.hasText(authenticateTokenURL)) {
authenticateTokenFilterBean.addPropertyValue("filterProcessesUrl", authenticateTokenURL);
}
String accessGrantedURL = element.getAttribute("access-granted-url");
if (!StringUtils.hasText(accessGrantedURL)) {
// create the simple URl handler and add it.
accessGrantedURL = "/";
}
authenticateTokenFilterBean.addConstructorArgValue(accessGrantedURL);
BeanDefinitionBuilder successfulAuthenticationHandler = BeanDefinitionBuilder.rootBeanDefinition(UserAuthorizationSuccessfulAuthenticationHandler.class);
successfulAuthenticationHandler.addConstructorArgValue(accessGrantedURL);
String callbackUrlParam = element.getAttribute("callback-url-param");
if (StringUtils.hasText(callbackUrlParam)) {
successfulAuthenticationHandler.addPropertyValue("callbackParameterName", callbackUrlParam);
}
// create a AuthenticationFailureHandler
BeanDefinitionBuilder simpleUrlAuthenticationFailureHandler = BeanDefinitionBuilder.rootBeanDefinition(SimpleUrlAuthenticationFailureHandler.class);
String authenticationFailedURL = element.getAttribute("authentication-failed-url");
if (StringUtils.hasText(authenticationFailedURL)) {
simpleUrlAuthenticationFailureHandler.addConstructorArgValue (authenticationFailedURL);
}
// create a AuthenticationFailureHandler
BeanDefinitionBuilder failedAuthenticationHandler = BeanDefinitionBuilder.rootBeanDefinition(SimpleUrlAuthenticationFailureHandler.class);
String userApprovalUrl = element.getAttribute("user-approval-url");
if (StringUtils.hasText(userApprovalUrl)) {
failedAuthenticationHandler.addConstructorArgValue(userApprovalUrl);
} else {
failedAuthenticationHandler.addConstructorArgValue("/");
}
String tokenIdParam = element.getAttribute("token-id-param");
if (StringUtils.hasText(tokenIdParam)) {
authenticateTokenFilterBean.addPropertyValue("tokenIdParameterName", tokenIdParam);
successfulAuthenticationHandler.addPropertyValue("tokenIdParameterName", tokenIdParam);
}
BeanDefinitionBuilder accessTokenFilterBean = BeanDefinitionBuilder.rootBeanDefinition(AccessTokenProcessingFilter.class);
if (StringUtils.hasText(consumerDetailsRef)) {
accessTokenFilterBean.addPropertyReference("consumerDetailsService", consumerDetailsRef);
}
if (StringUtils.hasText(tokenServicesRef)) {
accessTokenFilterBean.addPropertyReference("tokenServices", tokenServicesRef);
}
String accessTokenURL = element.getAttribute("access-token-url");
if (StringUtils.hasText(accessTokenURL)) {
accessTokenFilterBean.addPropertyValue("filterProcessesUrl", accessTokenURL);
}
BeanDefinitionBuilder protectedResourceFilterBean = BeanDefinitionBuilder.rootBeanDefinition(ProtectedResourceProcessingFilter.class);
if (StringUtils.hasText(consumerDetailsRef)) {
protectedResourceFilterBean.addPropertyReference("consumerDetailsService", consumerDetailsRef);
}
if (StringUtils.hasText(tokenServicesRef)) {
protectedResourceFilterBean.addPropertyReference("tokenServices", tokenServicesRef);
}
String nonceServicesRef = element.getAttribute("nonce-services-ref");
if (StringUtils.hasText(nonceServicesRef)) {
requestTokenFilterBean.addPropertyReference("nonceServices", nonceServicesRef);
accessTokenFilterBean.addPropertyReference("nonceServices", nonceServicesRef);
protectedResourceFilterBean.addPropertyReference("nonceServices", nonceServicesRef);
}
String supportRef = element.getAttribute("support-ref");
if (StringUtils.hasText(supportRef)) {
requestTokenFilterBean.addPropertyReference("providerSupport", supportRef);
accessTokenFilterBean.addPropertyReference("providerSupport", supportRef);
protectedResourceFilterBean.addPropertyReference("providerSupport", supportRef);
}
String authHandlerRef = element.getAttribute("auth-handler-ref");
if (StringUtils.hasText(authHandlerRef)) {
protectedResourceFilterBean.addPropertyReference("authHandler", authHandlerRef);
}
String require10a = element.getAttribute("require10a");
if (StringUtils.hasText(require10a)) {
requestTokenFilterBean.addPropertyValue("require10a", require10a);
authenticateTokenFilterBean.addPropertyValue("require10a", require10a);
accessTokenFilterBean.addPropertyValue("require10a", require10a);
successfulAuthenticationHandler.addPropertyValue("require10a", require10a);
}
String verifierServicesRef = element.getAttribute("verifier-services-ref");
if (!StringUtils.hasText(verifierServicesRef)) {
BeanDefinitionBuilder verifierServices = BeanDefinitionBuilder.rootBeanDefinition(RandomValueVerifierServices.class);
parserContext.getRegistry().registerBeanDefinition("oauthVerifierServices", verifierServices.getBeanDefinition());
verifierServicesRef = "oauthVerifierServices";
}
authenticateTokenFilterBean.addPropertyReference("verifierServices", verifierServicesRef);
// register the successfulAuthenticationHandler with the UserAuthorizationFilter
String oauthSuccessfulAuthenticationHandlerRef = "oauthSuccessfulAuthenticationHandler";
parserContext.getRegistry().registerBeanDefinition(oauthSuccessfulAuthenticationHandlerRef, successfulAuthenticationHandler.getBeanDefinition());
authenticateTokenFilterBean.addPropertyReference("authenticationSuccessHandler", oauthSuccessfulAuthenticationHandlerRef);
// register the failure handler with the UserAuthorizationFilter
String oauthFailedAuthenticationHandlerRef = "oauthFailedAuthenticationHandler";
parserContext.getRegistry().registerBeanDefinition(oauthFailedAuthenticationHandlerRef, failedAuthenticationHandler.getBeanDefinition());
authenticateTokenFilterBean.addPropertyReference("authenticationFailureHandler", oauthFailedAuthenticationHandlerRef);
List<BeanMetadataElement> filterChain = ConfigUtils.findFilterChain(parserContext, element.getAttribute("filter-chain-ref"));
int index = insertIndex(filterChain);
parserContext.getRegistry().registerBeanDefinition("oauthRequestTokenFilter", requestTokenFilterBean.getBeanDefinition());
filterChain.add(index++, new RuntimeBeanReference("oauthRequestTokenFilter"));
parserContext.getRegistry().registerBeanDefinition("oauthAuthenticateTokenFilter", authenticateTokenFilterBean.getBeanDefinition());
filterChain.add(index++, new RuntimeBeanReference("oauthAuthenticateTokenFilter"));
parserContext.getRegistry().registerBeanDefinition("oauthAccessTokenFilter", accessTokenFilterBean.getBeanDefinition());
filterChain.add(index++, new RuntimeBeanReference("oauthAccessTokenFilter"));
parserContext.getRegistry().registerBeanDefinition("oauthProtectedResourceFilter", protectedResourceFilterBean.getBeanDefinition());
filterChain.add(index++, new RuntimeBeanReference("oauthProtectedResourceFilter"));
return null;
}
/**
* Attempts to find the place in the filter chain to insert the spring security oauth filters. Currently,
* these filters are inserted after the ExceptionTranslationFilter.
*
* @param filterChain The filter chain configuration.
* @return The insert index.
*/
private int insertIndex(List<BeanMetadataElement> filterChain) {
int i;
for (i = 0; i < filterChain.size(); i++) {
BeanMetadataElement filter = filterChain.get(i);
if (filter instanceof BeanDefinition) {
String beanName = ((BeanDefinition) filter).getBeanClassName();
if (beanName.equals(ExceptionTranslationFilter.class.getName())) {
return i + 1;
}
}
}
return filterChain.size();
}
}