View Javadoc

1   package org.springframework.security.config;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.apache.commons.logging.Log;
7   import org.apache.commons.logging.LogFactory;
8   import org.springframework.beans.BeanMetadataElement;
9   import org.springframework.beans.MutablePropertyValues;
10  import org.springframework.beans.PropertyValue;
11  import org.springframework.beans.factory.config.BeanDefinition;
12  import org.springframework.beans.factory.config.RuntimeBeanReference;
13  import org.springframework.beans.factory.support.BeanDefinitionBuilder;
14  import org.springframework.beans.factory.support.ManagedList;
15  import org.springframework.beans.factory.support.RootBeanDefinition;
16  import org.springframework.beans.factory.xml.ParserContext;
17  import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
18  import org.springframework.security.util.UrlUtils;
19  import org.springframework.security.vote.AffirmativeBased;
20  import org.springframework.security.vote.AuthenticatedVoter;
21  import org.springframework.security.vote.RoleVoter;
22  import org.springframework.util.StringUtils;
23  import org.w3c.dom.Element;
24  
25  /**
26   * Utility methods used internally by the Spring Security namespace configuration code.
27   *
28   * @author Luke Taylor
29   * @author Ben Alex
30   * @version $Id: ConfigUtils.java 3194 2008-07-30 11:01:23Z luke_t $
31   */
32  public abstract class ConfigUtils {
33      private static final Log logger = LogFactory.getLog(ConfigUtils.class);
34  
35      static void registerDefaultAccessManagerIfNecessary(ParserContext parserContext) {
36  
37          if (!parserContext.getRegistry().containsBeanDefinition(BeanIds.ACCESS_MANAGER)) {
38              ManagedList defaultVoters = new ManagedList(2);
39  
40              defaultVoters.add(new RootBeanDefinition(RoleVoter.class));
41              defaultVoters.add(new RootBeanDefinition(AuthenticatedVoter.class));
42  
43              BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class);
44              accessMgrBuilder.addPropertyValue("decisionVoters", defaultVoters);
45              BeanDefinition accessMgr = accessMgrBuilder.getBeanDefinition();
46  
47              parserContext.getRegistry().registerBeanDefinition(BeanIds.ACCESS_MANAGER, accessMgr);
48          }
49      }
50      
51      public static int countNonEmpty(String[] objects) {        
52          int nonNulls = 0;
53          
54          for (int i = 0; i < objects.length; i++) {
55              if (StringUtils.hasText(objects[i])) {
56                  nonNulls++;
57              }
58          }
59          
60          return nonNulls;
61      }
62  
63      public static void addVoter(BeanDefinition voter, ParserContext parserContext) {
64          registerDefaultAccessManagerIfNecessary(parserContext);
65  
66          BeanDefinition accessMgr = parserContext.getRegistry().getBeanDefinition(BeanIds.ACCESS_MANAGER);
67  
68          ManagedList voters = (ManagedList) accessMgr.getPropertyValues().getPropertyValue("decisionVoters").getValue();
69          voters.add(voter);
70          
71          accessMgr.getPropertyValues().addPropertyValue("decisionVoters", voters);
72      }
73  
74      /**
75       * Creates and registers the bean definition for the default ProviderManager instance and returns
76       * the BeanDefinition for it. This method will typically be called when registering authentication providers
77       * using the &lt;security:provider /> tag or by other beans which have a dependency on the
78       * authentication manager.
79       */
80      static void registerProviderManagerIfNecessary(ParserContext parserContext) {
81          if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) {
82              return;
83          }
84  
85          BeanDefinition authManager = new RootBeanDefinition(NamespaceAuthenticationManager.class);
86          authManager.getPropertyValues().addPropertyValue("providerBeanNames", new ArrayList());
87          parserContext.getRegistry().registerBeanDefinition(BeanIds.AUTHENTICATION_MANAGER, authManager);
88      }
89  
90      static void addAuthenticationProvider(ParserContext parserContext, String beanName) {
91          registerProviderManagerIfNecessary(parserContext);
92          BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
93          ((ArrayList) authManager.getPropertyValues().getPropertyValue("providerBeanNames").getValue()).add(beanName);
94      }
95      
96      static ManagedList getRegisteredAfterInvocationProviders(ParserContext parserContext) {
97          BeanDefinition manager = registerAfterInvocationProviderManagerIfNecessary(parserContext);
98          return (ManagedList) manager.getPropertyValues().getPropertyValue("providers").getValue();
99      }    
100     
101     private static BeanDefinition registerAfterInvocationProviderManagerIfNecessary(ParserContext parserContext) {
102         if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER)) {
103             return parserContext.getRegistry().getBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER);
104         }
105 
106         BeanDefinition manager = new RootBeanDefinition(AfterInvocationProviderManager.class);
107         manager.getPropertyValues().addPropertyValue("providers", new ManagedList());
108         parserContext.getRegistry().registerBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER, manager);
109 
110         return manager;
111     }
112 
113     private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
114         if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
115             return;
116         }
117         // Post processor specifically to assemble and order the filter chain immediately before the FilterChainProxy is initialized.
118         RootBeanDefinition filterChainPostProcessor = new RootBeanDefinition(FilterChainProxyPostProcessor.class);
119         filterChainPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
120         pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR, filterChainPostProcessor);
121         RootBeanDefinition filterList = new RootBeanDefinition(FilterChainList.class);
122         filterList.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
123         pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_LIST, filterList);
124     }
125     
126     static void addHttpFilter(ParserContext pc, BeanMetadataElement filter) {
127         registerFilterChainPostProcessorIfNecessary(pc);
128         
129         RootBeanDefinition filterList = (RootBeanDefinition) pc.getRegistry().getBeanDefinition(BeanIds.FILTER_LIST);
130         
131         ManagedList filters;
132         MutablePropertyValues pvs = filterList.getPropertyValues();
133         if (pvs.contains("filters")) {
134             filters = (ManagedList) pvs.getPropertyValue("filters").getValue();
135         } else {
136             filters = new ManagedList();
137             pvs.addPropertyValue("filters", filters);
138         }
139         
140         filters.add(filter);
141     }
142 
143     /**
144      * Bean which holds the list of filters which are maintained in the context and modified by calls to 
145      * addHttpFilter. The post processor retrieves these before injecting the list into the FilterChainProxy.
146      */
147     public static class FilterChainList {
148         List filters;
149 
150         public List getFilters() {
151             return filters;
152         }
153 
154         public void setFilters(List filters) {
155             this.filters = filters;
156         }
157     }
158     
159     /**
160      * Checks the value of an XML attribute which represents a redirect URL.
161      * If not empty or starting with "$" (potential placeholder), "/" or "http" it will raise an error. 
162      */
163     static void validateHttpRedirect(String url, ParserContext pc, Object source) {
164         if (UrlUtils.isValidRedirectUrl(url) || url.startsWith("$")) {
165             return;
166         }
167         pc.getReaderContext().warning(url + " is not a valid redirect URL (must start with '/' or http(s))", source);
168     }
169     
170     static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) {
171         registerProviderManagerIfNecessary(pc);
172         BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
173         PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController");
174         
175         if (pv != null && pv.getValue() != null) {
176             pc.getReaderContext().error("A session controller has already been set on the authentication manager. " +
177                     "The <concurrent-session-control> element isn't compatible with a custom session controller", 
178                     pc.extractSource(sourceElt));
179         }
180         
181         authManager.getPropertyValues().addPropertyValue("sessionController", new RuntimeBeanReference(beanName));
182     }
183 }