View Javadoc

1   package org.springframework.security.config;
2   
3   import java.io.IOException;
4   
5   import javax.servlet.Filter;
6   import javax.servlet.FilterChain;
7   import javax.servlet.FilterConfig;
8   import javax.servlet.ServletException;
9   import javax.servlet.ServletRequest;
10  import javax.servlet.ServletResponse;
11  
12  import org.springframework.beans.factory.config.BeanDefinitionHolder;
13  import org.springframework.beans.factory.config.RuntimeBeanReference;
14  import org.springframework.beans.factory.support.BeanDefinitionBuilder;
15  import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
16  import org.springframework.beans.factory.xml.ParserContext;
17  import org.springframework.core.Ordered;
18  import org.springframework.security.ui.FilterChainOrder;
19  import org.springframework.util.Assert;
20  import org.springframework.util.StringUtils;
21  import org.w3c.dom.Element;
22  import org.w3c.dom.Node;
23  
24  /**
25   * Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.
26   * This allows user to add their own custom filters to the security chain. If the user's filter
27   * already implements Ordered, and no "order" attribute is specified, the filter's default order will be used.
28   *
29   * @author Luke Taylor
30   * @version $Id: OrderedFilterBeanDefinitionDecorator.java 3218 2008-08-05 23:26:01Z luke_t $
31   */
32  public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecorator {
33  
34      public static final String ATT_AFTER = "after";
35      public static final String ATT_BEFORE = "before";
36      public static final String ATT_POSITION = "position";
37  
38      public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
39          Element elt = (Element)node;
40          String order = getOrder(elt, parserContext);
41  
42          BeanDefinitionBuilder wrapper = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.config.OrderedFilterBeanDefinitionDecorator$OrderedFilterDecorator");
43          wrapper.addConstructorArg(holder.getBeanName());
44          wrapper.addConstructorArg(new RuntimeBeanReference(holder.getBeanName()));
45  
46          if (StringUtils.hasText(order)) {
47              wrapper.addPropertyValue("order", order);
48          }
49  
50          ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
51  
52          return holder;
53      }
54  
55      /**
56       * Attempts to get the order of the filter by parsing the 'before' or 'after' attributes.
57       */
58      private String getOrder(Element elt, ParserContext pc) {
59          String after = elt.getAttribute(ATT_AFTER);
60          String before = elt.getAttribute(ATT_BEFORE);
61          String position = elt.getAttribute(ATT_POSITION);
62  
63          if(ConfigUtils.countNonEmpty(new String[] {after, before, position}) != 1) {
64              pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" +
65                      ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt));
66          }
67  
68          if (StringUtils.hasText(position)) {
69              return Integer.toString(FilterChainOrder.getOrder(position));
70          }
71  
72          if (StringUtils.hasText(after)) {
73              int order = FilterChainOrder.getOrder(after);
74  
75              return Integer.toString(order == Integer.MAX_VALUE ? order : order + 1);
76          }
77  
78          if (StringUtils.hasText(before)) {
79              int order = FilterChainOrder.getOrder(before);
80  
81              return Integer.toString(order == Integer.MIN_VALUE ? order : order - 1);
82          }
83  
84          return null;
85      }
86  
87      static class OrderedFilterDecorator implements Filter, Ordered {
88          private Integer order = null;
89          private Filter delegate;
90          private String beanName;
91  
92          OrderedFilterDecorator(String beanName, Filter delegate) {
93              this.delegate = delegate;
94              this.beanName = beanName;
95          }
96  
97          public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
98              delegate.doFilter(request, response, chain);
99          }
100 
101         public final void init(FilterConfig filterConfig) throws ServletException {
102             delegate.init(filterConfig);
103         }
104 
105         public final void destroy() {
106             delegate.destroy();
107         }
108 
109         public final int getOrder() {
110             if(order == null) {
111                 Assert.isInstanceOf(Ordered.class, delegate, "Filter '"+ beanName +"' must implement the 'Ordered' interface " +
112                         " or you must specify one of the attributes '" + ATT_AFTER + "' or '" +
113                         ATT_BEFORE + "' in <" + Elements.CUSTOM_FILTER +">");
114 
115                 return ((Ordered)delegate).getOrder();
116             }
117             return order.intValue();
118         }
119 
120         public final void setOrder(int order) {
121             this.order = new Integer(order);
122         }
123 
124         public String getBeanName() {
125             return beanName;
126         }
127 
128         public String toString() {
129             return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
130         }
131 
132         Filter getDelegate() {
133             return delegate;
134         }
135     }
136 }