1   /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package org.acegisecurity.intercept.web;
17  
18  import junit.framework.TestCase;
19  
20  import org.acegisecurity.ConfigAttributeDefinition;
21  import org.acegisecurity.MockFilterChain;
22  import org.acegisecurity.SecurityConfig;
23  
24  import org.springframework.mock.web.MockHttpServletRequest;
25  import org.springframework.mock.web.MockHttpServletResponse;
26  
27  import java.util.Iterator;
28  
29  
30  /**
31   * Tests {@link FilterInvocationDefinitionSourceEditor} and its associated default {@link
32   * RegExpBasedFilterInvocationDefinitionMap}.
33   *
34   * @author Ben Alex
35   * @version $Id: FilterInvocationDefinitionSourceEditorTests.java 1748 2006-11-14 20:55:24Z benalex $
36   */
37  public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
38      //~ Constructors ===================================================================================================
39  
40      public FilterInvocationDefinitionSourceEditorTests() {
41          super();
42      }
43  
44      public FilterInvocationDefinitionSourceEditorTests(String arg0) {
45          super(arg0);
46      }
47  
48      //~ Methods ========================================================================================================
49  
50      public static void main(String[] args) {
51          junit.textui.TestRunner.run(FilterInvocationDefinitionSourceEditorTests.class);
52      }
53  
54      public final void setUp() throws Exception {
55          super.setUp();
56      }
57  
58      public void testConvertUrlToLowercaseDefaultSettingUnchangedByEditor() {
59          FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
60          editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
61  
62          RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor
63              .getValue();
64          assertFalse(map.isConvertUrlToLowercaseBeforeComparison());
65      }
66  
67      public void testConvertUrlToLowercaseDetectsUppercaseEntries() {
68          FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
69  
70          try {
71              editor.setAsText(
72                  "CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON\r\nPATTERN_TYPE_APACHE_ANT\r\n\\/secUre/super/**=ROLE_WE_DONT_HAVE");
73              fail("Should have thrown IllegalArgumentException");
74          } catch (IllegalArgumentException expected) {
75              assertTrue(expected.getMessage().lastIndexOf("you have specified an uppercase character in line") != -1);
76          }
77      }
78  
79      public void testConvertUrlToLowercaseSettingApplied() {
80          FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
81          editor.setAsText(
82              "CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON\r\n\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
83  
84          RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
85          assertTrue(map.isConvertUrlToLowercaseBeforeComparison());
86      }
87  
88      public void testDefaultIsRegularExpression() {
89          FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
90          editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
91  
92          FilterInvocationDefinitionMap map = (FilterInvocationDefinitionMap) editor.getValue();
93          assertTrue(map instanceof RegExpBasedFilterInvocationDefinitionMap);
94      }
95  
96      public void testDetectsDuplicateDirectivesOnSameLineSituation1() {
97          FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
98  
99          try {
100             editor.setAsText(
101                 "CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT\r\n\\/secure/super/**=ROLE_WE_DONT_HAVE");
102             fail("Should have thrown IllegalArgumentException");
103         } catch (IllegalArgumentException expected) {
104             assertTrue(expected.getMessage().lastIndexOf("Line appears to be malformed") != -1);
105         }
106     }
107 
108     public void testDetectsDuplicateDirectivesOnSameLineSituation2() {
109         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
110 
111         try {
112             editor.setAsText(
113                 "CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON\r\nPATTERN_TYPE_APACHE_ANT /secure/super/**=ROLE_WE_DONT_HAVE");
114             fail("Should have thrown IllegalArgumentException");
115         } catch (IllegalArgumentException expected) {
116             assertTrue(expected.getMessage().lastIndexOf("Line appears to be malformed") != -1);
117         }
118     }
119 
120     public void testDetectsDuplicateDirectivesOnSameLineSituation3() {
121         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
122 
123         try {
124             editor.setAsText(
125                 "PATTERN_TYPE_APACHE_ANT\r\nCONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON /secure/super/**=ROLE_WE_DONT_HAVE");
126             fail("Should have thrown IllegalArgumentException");
127         } catch (IllegalArgumentException expected) {
128             assertTrue(expected.getMessage().lastIndexOf("Line appears to be malformed") != -1);
129         }
130     }
131 
132     public void testEmptyStringReturnsEmptyMap() {
133         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
134         editor.setAsText("");
135 
136         RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
137         assertEquals(0, map.getMapSize());
138     }
139 
140     public void testInvalidRegularExpressionsDetected()
141         throws Exception {
142         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
143 
144         try {
145             editor.setAsText("*=SOME_ROLE");
146         } catch (IllegalArgumentException expected) {
147             assertEquals("Malformed regular expression: *", expected.getMessage());
148         }
149     }
150 
151     public void testIterator() {
152         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
153         editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
154 
155         RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
156         Iterator iter = map.getConfigAttributeDefinitions();
157         int counter = 0;
158 
159         while (iter.hasNext()) {
160             iter.next();
161             counter++;
162         }
163 
164         assertEquals(2, counter);
165     }
166 
167     public void testMapReturnsNullWhenNoMatchFound() throws Exception {
168         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
169         editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE,ANOTHER_ROLE");
170 
171         RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
172 
173         MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
174         httpRequest.setServletPath("/totally/different/path/index.html");
175 
176         ConfigAttributeDefinition returned = map.getAttributes(new FilterInvocation(httpRequest,
177                     new MockHttpServletResponse(), new MockFilterChain()));
178 
179         assertEquals(null, returned);
180     }
181 
182     public void testMultiUrlParsing() {
183         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
184         editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
185 
186         RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
187         assertEquals(2, map.getMapSize());
188     }
189 
190     public void testNoArgConstructorDoesntExist() {
191         Class clazz = RegExpBasedFilterInvocationDefinitionMap.EntryHolder.class;
192 
193         try {
194             clazz.getDeclaredConstructor((Class[]) null);
195             fail("Should have thrown NoSuchMethodException");
196         } catch (NoSuchMethodException expected) {
197             assertTrue(true);
198         }
199     }
200 
201     public void testNullReturnsEmptyMap() {
202         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
203         editor.setAsText(null);
204 
205         RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
206         assertEquals(0, map.getMapSize());
207     }
208 
209     public void testOrderOfEntriesIsPreservedOrderA() {
210         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
211         editor.setAsText(
212             "\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE,ANOTHER_ROLE\r\n\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER");
213 
214         RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
215 
216         // Test ensures we match the first entry, not the second
217         MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
218         httpRequest.setServletPath("/secure/super/very_secret.html");
219 
220         ConfigAttributeDefinition returned = map.getAttributes(new FilterInvocation(httpRequest,
221                     new MockHttpServletResponse(), new MockFilterChain()));
222 
223         ConfigAttributeDefinition expected = new ConfigAttributeDefinition();
224         expected.addConfigAttribute(new SecurityConfig("ROLE_WE_DONT_HAVE"));
225         expected.addConfigAttribute(new SecurityConfig("ANOTHER_ROLE"));
226 
227         assertEquals(expected, returned);
228     }
229 
230     public void testOrderOfEntriesIsPreservedOrderB() {
231         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
232         editor.setAsText(
233             "\\A/secure/.*\\Z=ROLE_SUPERVISOR,ROLE_TELLER\r\n\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE,ANOTHER_ROLE");
234 
235         RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
236 
237         MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
238         httpRequest.setServletPath("/secure/super/very_secret.html");
239 
240         ConfigAttributeDefinition returned = map.getAttributes(new FilterInvocation(httpRequest,
241                     new MockHttpServletResponse(), new MockFilterChain()));
242 
243         ConfigAttributeDefinition expected = new ConfigAttributeDefinition();
244         expected.addConfigAttribute(new SecurityConfig("ROLE_SUPERVISOR"));
245         expected.addConfigAttribute(new SecurityConfig("ROLE_TELLER"));
246 
247         assertEquals(expected, returned);
248     }
249 
250     public void testSingleUrlParsingWithRegularExpressions() throws Exception {
251         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
252         editor.setAsText("\\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE,ANOTHER_ROLE");
253 
254         RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
255 
256         MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
257         httpRequest.setServletPath("/secure/super/very_secret.html");
258 
259         ConfigAttributeDefinition returned = map.getAttributes(new FilterInvocation(httpRequest,
260                     new MockHttpServletResponse(), new MockFilterChain()));
261 
262         ConfigAttributeDefinition expected = new ConfigAttributeDefinition();
263         expected.addConfigAttribute(new SecurityConfig("ROLE_WE_DONT_HAVE"));
264         expected.addConfigAttribute(new SecurityConfig("ANOTHER_ROLE"));
265 
266         assertEquals(expected, returned);
267     }
268 
269     public void testSingleUrlParsingWithAntPaths() throws Exception {
270         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
271         editor.setAsText("PATTERN_TYPE_APACHE_ANT\r\n/secure/super/**=ROLE_WE_DONT_HAVE,ANOTHER_ROLE");
272 
273         PathBasedFilterInvocationDefinitionMap map = (PathBasedFilterInvocationDefinitionMap) editor.getValue();
274 
275         MockHttpServletRequest httpRequest = new MockHttpServletRequest(null, null);
276         httpRequest.setServletPath("/secure/super/very_secret.html");
277 
278         ConfigAttributeDefinition returned = map.getAttributes(new FilterInvocation(httpRequest,
279                     new MockHttpServletResponse(), new MockFilterChain()));
280 
281         ConfigAttributeDefinition expected = new ConfigAttributeDefinition();
282         expected.addConfigAttribute(new SecurityConfig("ROLE_WE_DONT_HAVE"));
283         expected.addConfigAttribute(new SecurityConfig("ANOTHER_ROLE"));
284 
285         assertEquals(expected, returned);
286     }
287     
288     public void testWhitespaceAndCommentsAndLinesWithoutEqualsSignsAreIgnored() {
289         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
290         editor.setAsText(
291             "         \\A/secure/super.*\\Z=ROLE_WE_DONT_HAVE,ANOTHER_ROLE      \r\n   \r\n     \r\n   // comment line  \r\n   \\A/testing.*\\Z=ROLE_TEST   \r\n");
292 
293         RegExpBasedFilterInvocationDefinitionMap map = (RegExpBasedFilterInvocationDefinitionMap) editor.getValue();
294         assertEquals(2, map.getMapSize());
295     }
296 }