001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.acegisecurity.intercept.web;
017:
018: import junit.framework.TestCase;
019:
020: import org.acegisecurity.AccessDecisionManager;
021: import org.acegisecurity.AccessDeniedException;
022: import org.acegisecurity.Authentication;
023: import org.acegisecurity.ConfigAttribute;
024: import org.acegisecurity.ConfigAttributeDefinition;
025: import org.acegisecurity.GrantedAuthority;
026: import org.acegisecurity.GrantedAuthorityImpl;
027: import org.acegisecurity.MockAccessDecisionManager;
028: import org.acegisecurity.MockApplicationContext;
029: import org.acegisecurity.MockAuthenticationManager;
030: import org.acegisecurity.MockRunAsManager;
031: import org.acegisecurity.RunAsManager;
032: import org.acegisecurity.SecurityConfig;
033: import org.acegisecurity.context.SecurityContextHolder;
034: import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
035: import org.springframework.mock.web.MockHttpServletRequest;
036: import org.springframework.mock.web.MockHttpServletResponse;
037:
038: import java.io.IOException;
039:
040: import java.util.ArrayList;
041: import java.util.Iterator;
042: import java.util.List;
043:
044: import javax.servlet.FilterChain;
045: import javax.servlet.ServletException;
046: import javax.servlet.ServletRequest;
047: import javax.servlet.ServletResponse;
048:
049: /**
050: * Tests {@link FilterSecurityInterceptor}.
051: *
052: * @author Ben Alex
053: * @version $Id: FilterSecurityInterceptorTests.java 1570 2006-07-06 17:05:08Z carlossg $
054: */
055: public class FilterSecurityInterceptorTests extends TestCase {
056: //~ Constructors ===================================================================================================
057:
058: public FilterSecurityInterceptorTests() {
059: super ();
060: }
061:
062: public FilterSecurityInterceptorTests(String arg0) {
063: super (arg0);
064: }
065:
066: //~ Methods ========================================================================================================
067:
068: public static void main(String[] args) {
069: junit.textui.TestRunner
070: .run(FilterSecurityInterceptorTests.class);
071: }
072:
073: public final void setUp() throws Exception {
074: super .setUp();
075: }
076:
077: public void testEnsuresAccessDecisionManagerSupportsFilterInvocationClass()
078: throws Exception {
079: FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor();
080: interceptor
081: .setAuthenticationManager(new MockAuthenticationManager());
082: interceptor
083: .setObjectDefinitionSource(new RegExpBasedFilterInvocationDefinitionMap());
084: interceptor.setRunAsManager(new MockRunAsManager());
085:
086: interceptor
087: .setAccessDecisionManager(new AccessDecisionManager() {
088: public boolean supports(Class clazz) {
089: return false;
090: }
091:
092: public boolean supports(ConfigAttribute attribute) {
093: return true;
094: }
095:
096: public void decide(Authentication authentication,
097: Object object,
098: ConfigAttributeDefinition config)
099: throws AccessDeniedException {
100: throw new UnsupportedOperationException(
101: "mock method not implemented");
102: }
103: });
104:
105: try {
106: interceptor.afterPropertiesSet();
107: fail("Should have thrown IllegalArgumentException");
108: } catch (IllegalArgumentException expected) {
109: assertEquals(
110: "AccessDecisionManager does not support secure object class: class org.acegisecurity.intercept.web.FilterInvocation",
111: expected.getMessage());
112: }
113: }
114:
115: public void testEnsuresRunAsManagerSupportsFilterInvocationClass()
116: throws Exception {
117: FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor();
118: interceptor
119: .setAccessDecisionManager(new MockAccessDecisionManager());
120: interceptor
121: .setAuthenticationManager(new MockAuthenticationManager());
122: interceptor
123: .setObjectDefinitionSource(new RegExpBasedFilterInvocationDefinitionMap());
124:
125: interceptor.setRunAsManager(new RunAsManager() {
126: public boolean supports(Class clazz) {
127: return false;
128: }
129:
130: public boolean supports(ConfigAttribute attribute) {
131: return true;
132: }
133:
134: public Authentication buildRunAs(
135: Authentication authentication, Object object,
136: ConfigAttributeDefinition config) {
137: throw new UnsupportedOperationException(
138: "mock method not implemented");
139: }
140: });
141:
142: try {
143: interceptor.afterPropertiesSet();
144: fail("Should have thrown IllegalArgumentException");
145: } catch (IllegalArgumentException expected) {
146: assertEquals(
147: "RunAsManager does not support secure object class: class org.acegisecurity.intercept.web.FilterInvocation",
148: expected.getMessage());
149: }
150: }
151:
152: public void testHttpsInvocationReflectsPortNumber()
153: throws Throwable {
154: // Setup the FilterSecurityInterceptor
155: FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor();
156: interceptor
157: .setAccessDecisionManager(new MockAccessDecisionManager());
158: interceptor
159: .setAuthenticationManager(new MockAuthenticationManager());
160: interceptor.setRunAsManager(new MockRunAsManager());
161: interceptor.setApplicationEventPublisher(MockApplicationContext
162: .getContext());
163:
164: // Setup a mock config attribute definition
165: ConfigAttributeDefinition def = new ConfigAttributeDefinition();
166: def.addConfigAttribute(new SecurityConfig("MOCK_OK"));
167:
168: MockFilterInvocationDefinitionMap mockSource = new MockFilterInvocationDefinitionMap(
169: "/secure/page.html", def);
170: interceptor.setObjectDefinitionSource(mockSource);
171:
172: // Setup our expectation that the filter chain will be invoked, as access is granted
173: MockFilterChain chain = new MockFilterChain(true);
174:
175: // Setup our HTTPS request and response
176: MockHttpServletResponse response = new MockHttpServletResponse();
177: MockHttpServletRequest request = new MockHttpServletRequest();
178: request.setServletPath("/secure/page.html");
179: request.setScheme("https");
180: request.setServerPort(443);
181:
182: // Setup a Context
183: UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
184: "Test", "Password",
185: new GrantedAuthority[] { new GrantedAuthorityImpl(
186: "MOCK_OK") });
187: SecurityContextHolder.getContext().setAuthentication(token);
188:
189: // Create and test our secure object
190: FilterInvocation fi = new FilterInvocation(request, response,
191: chain);
192: interceptor.invoke(fi);
193:
194: // Destroy the Context
195: SecurityContextHolder.clearContext();
196: }
197:
198: public void testNormalStartupAndGetter() throws Exception {
199: FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor();
200: interceptor
201: .setAccessDecisionManager(new MockAccessDecisionManager());
202: interceptor
203: .setAuthenticationManager(new MockAuthenticationManager());
204:
205: RegExpBasedFilterInvocationDefinitionMap fidp = new RegExpBasedFilterInvocationDefinitionMap();
206: interceptor.setObjectDefinitionSource(fidp);
207: interceptor.setRunAsManager(new MockRunAsManager());
208: interceptor.afterPropertiesSet();
209: assertTrue(true);
210: assertEquals(fidp, interceptor.getObjectDefinitionSource());
211: }
212:
213: /**
214: * We just test invocation works in a success event. There is no need to test access denied events as the
215: * abstract parent enforces that logic, which is extensively tested separately.
216: *
217: * @throws Throwable DOCUMENT ME!
218: */
219: public void testSuccessfulInvocation() throws Throwable {
220: // Setup the FilterSecurityInterceptor
221: FilterSecurityInterceptor interceptor = new FilterSecurityInterceptor();
222: interceptor
223: .setAccessDecisionManager(new MockAccessDecisionManager());
224: interceptor
225: .setAuthenticationManager(new MockAuthenticationManager());
226: interceptor.setRunAsManager(new MockRunAsManager());
227: interceptor.setApplicationEventPublisher(MockApplicationContext
228: .getContext());
229:
230: // Setup a mock config attribute definition
231: ConfigAttributeDefinition def = new ConfigAttributeDefinition();
232: def.addConfigAttribute(new SecurityConfig("MOCK_OK"));
233:
234: MockFilterInvocationDefinitionMap mockSource = new MockFilterInvocationDefinitionMap(
235: "/secure/page.html", def);
236: interceptor.setObjectDefinitionSource(mockSource);
237:
238: // Setup our expectation that the filter chain will be invoked, as access is granted
239: MockFilterChain chain = new MockFilterChain(true);
240:
241: // Setup our HTTP request and response
242: MockHttpServletResponse response = new MockHttpServletResponse();
243: MockHttpServletRequest request = new MockHttpServletRequest();
244: request.setServletPath("/secure/page.html");
245:
246: // Setup a Context
247: UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
248: "Test", "Password",
249: new GrantedAuthority[] { new GrantedAuthorityImpl(
250: "MOCK_OK") });
251: SecurityContextHolder.getContext().setAuthentication(token);
252:
253: // Create and test our secure object
254: FilterInvocation fi = new FilterInvocation(request, response,
255: chain);
256: interceptor.invoke(fi);
257:
258: // Destroy the Context
259: SecurityContextHolder.clearContext();
260: }
261:
262: public void testNotLoadedFromApplicationContext() throws Exception {
263: FilterInvocationDefinitionSourceMapping mapping = new FilterInvocationDefinitionSourceMapping();
264: mapping.setUrl("/secure/**");
265: mapping.addConfigAttribute("ROLE_USER");
266:
267: List mappings = new ArrayList(1);
268: mappings.add(mapping);
269:
270: PathBasedFilterInvocationDefinitionMap filterInvocationDefinitionSource = new PathBasedFilterInvocationDefinitionMap();
271: filterInvocationDefinitionSource
272: .setConvertUrlToLowercaseBeforeComparison(true);
273: FilterInvocationDefinitionDecorator decorator = new FilterInvocationDefinitionDecorator(
274: filterInvocationDefinitionSource);
275: decorator.setMappings(mappings);
276:
277: FilterSecurityInterceptor filter = new FilterSecurityInterceptor();
278: filter
279: .setObjectDefinitionSource(filterInvocationDefinitionSource);
280:
281: MockFilterChain filterChain = new MockFilterChain();
282: filterChain.expectToProceed = true;
283:
284: FilterInvocation fi = new FilterInvocation(
285: new MockHttpServletRequest(),
286: new MockHttpServletResponse(), filterChain);
287: filter.invoke(fi);
288: }
289:
290: //~ Inner Classes ==================================================================================================
291:
292: private class MockFilterChain implements FilterChain {
293: private boolean expectToProceed;
294:
295: public MockFilterChain(boolean expectToProceed) {
296: this .expectToProceed = expectToProceed;
297: }
298:
299: private MockFilterChain() {
300: super ();
301: }
302:
303: public void doFilter(ServletRequest request,
304: ServletResponse response) throws IOException,
305: ServletException {
306: if (expectToProceed) {
307: assertTrue(true);
308: } else {
309: fail("Did not expect filter chain to proceed");
310: }
311: }
312: }
313:
314: private class MockFilterInvocationDefinitionMap implements
315: FilterInvocationDefinitionSource {
316: private ConfigAttributeDefinition toReturn;
317: private String servletPath;
318:
319: public MockFilterInvocationDefinitionMap(String servletPath,
320: ConfigAttributeDefinition toReturn) {
321: this .servletPath = servletPath;
322: this .toReturn = toReturn;
323: }
324:
325: private MockFilterInvocationDefinitionMap() {
326: super ();
327: }
328:
329: public ConfigAttributeDefinition getAttributes(Object object)
330: throws IllegalArgumentException {
331: FilterInvocation fi = (FilterInvocation) object;
332:
333: if (servletPath
334: .equals(fi.getHttpRequest().getServletPath())) {
335: return toReturn;
336: } else {
337: return null;
338: }
339: }
340:
341: public Iterator getConfigAttributeDefinitions() {
342: return null;
343: }
344:
345: public boolean supports(Class clazz) {
346: return true;
347: }
348: }
349: }
|