View Javadoc
1   /*
2    * Copyright 2008-2009 Web Cohesion
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.security.oauth.config;
18  
19  import java.util.List;
20  
21  import org.springframework.beans.BeanMetadataElement;
22  import org.springframework.beans.factory.config.BeanDefinition;
23  import org.springframework.beans.factory.config.RuntimeBeanReference;
24  import org.springframework.beans.factory.support.BeanDefinitionBuilder;
25  import org.springframework.beans.factory.xml.BeanDefinitionParser;
26  import org.springframework.beans.factory.xml.ParserContext;
27  import org.springframework.security.config.BeanIds;
28  import org.springframework.security.oauth.provider.filter.AccessTokenProcessingFilter;
29  import org.springframework.security.oauth.provider.filter.ProtectedResourceProcessingFilter;
30  import org.springframework.security.oauth.provider.filter.UnauthenticatedRequestTokenProcessingFilter;
31  import org.springframework.security.oauth.provider.filter.UserAuthorizationProcessingFilter;
32  import org.springframework.security.oauth.provider.filter.UserAuthorizationSuccessfulAuthenticationHandler;
33  import org.springframework.security.oauth.provider.verifier.RandomValueVerifierServices;
34  import org.springframework.security.web.access.ExceptionTranslationFilter;
35  import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
36  import org.springframework.util.StringUtils;
37  import org.w3c.dom.Element;
38  
39  /**
40   * Parser for the OAuth "provider" element.
41   *
42   * @author Ryan Heaton
43   * @author Andrew McCall
44   */
45  public class OAuthProviderBeanDefinitionParser implements BeanDefinitionParser {
46  
47    public BeanDefinition parse(Element element, ParserContext parserContext) {
48      String consumerDetailsRef = element.getAttribute("consumer-details-service-ref");
49      String tokenServicesRef = element.getAttribute("token-services-ref");
50  
51      BeanDefinitionBuilder requestTokenFilterBean = BeanDefinitionBuilder.rootBeanDefinition(UnauthenticatedRequestTokenProcessingFilter.class);
52      if (StringUtils.hasText(consumerDetailsRef)) {
53        requestTokenFilterBean.addPropertyReference("consumerDetailsService", consumerDetailsRef);
54      }
55      if (StringUtils.hasText(tokenServicesRef)) {
56        requestTokenFilterBean.addPropertyReference("tokenServices", tokenServicesRef);
57      }
58      String requestTokenURL = element.getAttribute("request-token-url");
59      if (StringUtils.hasText(requestTokenURL)) {
60        requestTokenFilterBean.addPropertyValue("filterProcessesUrl", requestTokenURL);
61      }
62  
63      BeanDefinitionBuilder authenticateTokenFilterBean = BeanDefinitionBuilder.rootBeanDefinition(UserAuthorizationProcessingFilter.class);
64  
65      authenticateTokenFilterBean.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER);
66      if (StringUtils.hasText(tokenServicesRef)) {
67        authenticateTokenFilterBean.addPropertyReference("tokenServices", tokenServicesRef);
68      }
69  
70      String authenticateTokenURL = element.getAttribute("authenticate-token-url");
71      if (StringUtils.hasText(authenticateTokenURL)) {
72        authenticateTokenFilterBean.addPropertyValue("filterProcessesUrl", authenticateTokenURL);
73      }
74  
75      String accessGrantedURL = element.getAttribute("access-granted-url");
76      if (!StringUtils.hasText(accessGrantedURL)) {
77        // create the simple URl handler and add it.
78        accessGrantedURL = "/";
79      }
80      authenticateTokenFilterBean.addConstructorArgValue(accessGrantedURL);
81  
82      BeanDefinitionBuilder successfulAuthenticationHandler = BeanDefinitionBuilder.rootBeanDefinition(UserAuthorizationSuccessfulAuthenticationHandler.class);
83      successfulAuthenticationHandler.addConstructorArgValue(accessGrantedURL);
84  
85      String callbackUrlParam = element.getAttribute("callback-url-param");
86      if (StringUtils.hasText(callbackUrlParam)) {
87        successfulAuthenticationHandler.addPropertyValue("callbackParameterName", callbackUrlParam);
88      }
89      
90      // create a AuthenticationFailureHandler
91      BeanDefinitionBuilder simpleUrlAuthenticationFailureHandler = BeanDefinitionBuilder.rootBeanDefinition(SimpleUrlAuthenticationFailureHandler.class);
92      String authenticationFailedURL = element.getAttribute("authentication-failed-url");
93      if (StringUtils.hasText(authenticationFailedURL)) {
94        simpleUrlAuthenticationFailureHandler.addConstructorArgValue (authenticationFailedURL);
95      }
96  
97      // create a AuthenticationFailureHandler
98      BeanDefinitionBuilder failedAuthenticationHandler = BeanDefinitionBuilder.rootBeanDefinition(SimpleUrlAuthenticationFailureHandler.class);
99      String userApprovalUrl = element.getAttribute("user-approval-url");
100     if (StringUtils.hasText(userApprovalUrl)) {
101       failedAuthenticationHandler.addConstructorArgValue(userApprovalUrl);
102     } else {
103       failedAuthenticationHandler.addConstructorArgValue("/");
104     }
105 
106     String tokenIdParam = element.getAttribute("token-id-param");
107     if (StringUtils.hasText(tokenIdParam)) {
108       authenticateTokenFilterBean.addPropertyValue("tokenIdParameterName", tokenIdParam);
109       successfulAuthenticationHandler.addPropertyValue("tokenIdParameterName", tokenIdParam);
110     }
111 
112     BeanDefinitionBuilder accessTokenFilterBean = BeanDefinitionBuilder.rootBeanDefinition(AccessTokenProcessingFilter.class);
113 
114     if (StringUtils.hasText(consumerDetailsRef)) {
115       accessTokenFilterBean.addPropertyReference("consumerDetailsService", consumerDetailsRef);
116     }
117     if (StringUtils.hasText(tokenServicesRef)) {
118       accessTokenFilterBean.addPropertyReference("tokenServices", tokenServicesRef);
119     }
120 
121     String accessTokenURL = element.getAttribute("access-token-url");
122     if (StringUtils.hasText(accessTokenURL)) {
123       accessTokenFilterBean.addPropertyValue("filterProcessesUrl", accessTokenURL);
124     }
125 
126     BeanDefinitionBuilder protectedResourceFilterBean = BeanDefinitionBuilder.rootBeanDefinition(ProtectedResourceProcessingFilter.class);
127     if (StringUtils.hasText(consumerDetailsRef)) {
128       protectedResourceFilterBean.addPropertyReference("consumerDetailsService", consumerDetailsRef);
129     }
130     if (StringUtils.hasText(tokenServicesRef)) {
131       protectedResourceFilterBean.addPropertyReference("tokenServices", tokenServicesRef);
132     }
133 
134     String nonceServicesRef = element.getAttribute("nonce-services-ref");
135     if (StringUtils.hasText(nonceServicesRef)) {
136       requestTokenFilterBean.addPropertyReference("nonceServices", nonceServicesRef);
137       accessTokenFilterBean.addPropertyReference("nonceServices", nonceServicesRef);
138       protectedResourceFilterBean.addPropertyReference("nonceServices", nonceServicesRef);
139     }
140 
141     String supportRef = element.getAttribute("support-ref");
142     if (StringUtils.hasText(supportRef)) {
143       requestTokenFilterBean.addPropertyReference("providerSupport", supportRef);
144       accessTokenFilterBean.addPropertyReference("providerSupport", supportRef);
145       protectedResourceFilterBean.addPropertyReference("providerSupport", supportRef);
146     }
147 
148     String authHandlerRef = element.getAttribute("auth-handler-ref");
149     if (StringUtils.hasText(authHandlerRef)) {
150       protectedResourceFilterBean.addPropertyReference("authHandler", authHandlerRef);
151     }
152 
153     String require10a = element.getAttribute("require10a");
154     if (StringUtils.hasText(require10a)) {
155       requestTokenFilterBean.addPropertyValue("require10a", require10a);
156       authenticateTokenFilterBean.addPropertyValue("require10a", require10a);
157       accessTokenFilterBean.addPropertyValue("require10a", require10a);
158       successfulAuthenticationHandler.addPropertyValue("require10a", require10a);
159     }
160 
161     String verifierServicesRef = element.getAttribute("verifier-services-ref");
162     if (!StringUtils.hasText(verifierServicesRef)) {
163       BeanDefinitionBuilder verifierServices = BeanDefinitionBuilder.rootBeanDefinition(RandomValueVerifierServices.class);
164       parserContext.getRegistry().registerBeanDefinition("oauthVerifierServices", verifierServices.getBeanDefinition());
165       verifierServicesRef = "oauthVerifierServices";
166     }
167     authenticateTokenFilterBean.addPropertyReference("verifierServices", verifierServicesRef);
168 
169     // register the successfulAuthenticationHandler with the UserAuthorizationFilter
170     String oauthSuccessfulAuthenticationHandlerRef = "oauthSuccessfulAuthenticationHandler";
171     parserContext.getRegistry().registerBeanDefinition(oauthSuccessfulAuthenticationHandlerRef, successfulAuthenticationHandler.getBeanDefinition());
172     authenticateTokenFilterBean.addPropertyReference("authenticationSuccessHandler", oauthSuccessfulAuthenticationHandlerRef);
173 
174     // register the failure handler with the UserAuthorizationFilter
175     String oauthFailedAuthenticationHandlerRef = "oauthFailedAuthenticationHandler";
176     parserContext.getRegistry().registerBeanDefinition(oauthFailedAuthenticationHandlerRef, failedAuthenticationHandler.getBeanDefinition());
177     authenticateTokenFilterBean.addPropertyReference("authenticationFailureHandler", oauthFailedAuthenticationHandlerRef);
178 
179     List<BeanMetadataElement> filterChain = ConfigUtils.findFilterChain(parserContext, element.getAttribute("filter-chain-ref"));
180     int index = insertIndex(filterChain);
181     parserContext.getRegistry().registerBeanDefinition("oauthRequestTokenFilter", requestTokenFilterBean.getBeanDefinition());
182     filterChain.add(index++, new RuntimeBeanReference("oauthRequestTokenFilter"));
183     parserContext.getRegistry().registerBeanDefinition("oauthAuthenticateTokenFilter", authenticateTokenFilterBean.getBeanDefinition());
184     filterChain.add(index++, new RuntimeBeanReference("oauthAuthenticateTokenFilter"));
185     parserContext.getRegistry().registerBeanDefinition("oauthAccessTokenFilter", accessTokenFilterBean.getBeanDefinition());
186     filterChain.add(index++, new RuntimeBeanReference("oauthAccessTokenFilter"));
187     parserContext.getRegistry().registerBeanDefinition("oauthProtectedResourceFilter", protectedResourceFilterBean.getBeanDefinition());
188     filterChain.add(index++, new RuntimeBeanReference("oauthProtectedResourceFilter"));
189 
190     return null;
191   }
192 
193   /**
194    * Attempts to find the place in the filter chain to insert the spring security oauth filters. Currently,
195    * these filters are inserted after the ExceptionTranslationFilter.
196    *
197    * @param filterChain The filter chain configuration.
198    * @return The insert index.
199    */
200   private int insertIndex(List<BeanMetadataElement> filterChain) {
201     int i;
202     for (i = 0; i < filterChain.size(); i++) {
203       BeanMetadataElement filter = filterChain.get(i);
204       if (filter instanceof BeanDefinition) {
205         String beanName = ((BeanDefinition) filter).getBeanClassName();
206         if (beanName.equals(ExceptionTranslationFilter.class.getName())) {
207            return i + 1;
208         }
209       }
210     }
211     return filterChain.size();
212   }
213 }