Source Code Cross Referenced for AbstractSecurityInterceptor.java in  » Security » acegi-security » org » acegisecurity » intercept » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Security » acegi security » org.acegisecurity.intercept 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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;
017:
018:        import org.acegisecurity.AccessDecisionManager;
019:        import org.acegisecurity.AccessDeniedException;
020:        import org.acegisecurity.AcegiMessageSource;
021:        import org.acegisecurity.AfterInvocationManager;
022:        import org.acegisecurity.Authentication;
023:        import org.acegisecurity.AuthenticationCredentialsNotFoundException;
024:        import org.acegisecurity.AuthenticationException;
025:        import org.acegisecurity.AuthenticationManager;
026:        import org.acegisecurity.ConfigAttribute;
027:        import org.acegisecurity.ConfigAttributeDefinition;
028:        import org.acegisecurity.RunAsManager;
029:
030:        import org.acegisecurity.context.SecurityContextHolder;
031:
032:        import org.acegisecurity.event.authorization.AuthenticationCredentialsNotFoundEvent;
033:        import org.acegisecurity.event.authorization.AuthorizationFailureEvent;
034:        import org.acegisecurity.event.authorization.AuthorizedEvent;
035:        import org.acegisecurity.event.authorization.PublicInvocationEvent;
036:
037:        import org.acegisecurity.runas.NullRunAsManager;
038:
039:        import org.apache.commons.logging.Log;
040:        import org.apache.commons.logging.LogFactory;
041:
042:        import org.springframework.beans.factory.InitializingBean;
043:
044:        import org.springframework.context.ApplicationEvent;
045:        import org.springframework.context.ApplicationEventPublisher;
046:        import org.springframework.context.ApplicationEventPublisherAware;
047:        import org.springframework.context.MessageSource;
048:        import org.springframework.context.MessageSourceAware;
049:        import org.springframework.context.support.MessageSourceAccessor;
050:
051:        import org.springframework.util.Assert;
052:
053:        import java.util.HashSet;
054:        import java.util.Iterator;
055:        import java.util.Set;
056:
057:        /**
058:         * Abstract class that implements security interception for secure objects.
059:         * <p>
060:         * The <code>AbstractSecurityInterceptor</code> will ensure the proper startup
061:         * configuration of the security interceptor. It will also implement the proper
062:         * handling of secure object invocations, being:
063:         * <ol>
064:         * <li>Obtain the {@link Authentication} object from the
065:         * {@link SecurityContextHolder}.</li>
066:         * <li>Determine if the request relates to a secured or public invocation by
067:         * looking up the secure object request against the
068:         * {@link ObjectDefinitionSource}.</li>
069:         * <li>For an invocation that is secured (there is a
070:         * <code>ConfigAttributeDefinition</code> for the secure object invocation):
071:         * <ol type="a">
072:         * <li>If either the {@link org.acegisecurity.Authentication#isAuthenticated()}
073:         * returns <code>false</code>, or the {@link #alwaysReauthenticate} is
074:         * <code>true</code>, authenticate the request against the configured
075:         * {@link AuthenticationManager}. When authenticated, replace the
076:         * <code>Authentication</code> object on the
077:         * <code>SecurityContextHolder</code> with the returned value.</li>
078:         * <li>Authorize the request against the configured
079:         * {@link AccessDecisionManager}.</li>
080:         * <li>Perform any run-as replacement via the configured {@link RunAsManager}.</li>
081:         * <li>Pass control back to the concrete subclass, which will actually proceed
082:         * with executing the object. A {@link InterceptorStatusToken} is returned so
083:         * that after the subclass has finished proceeding with execution of the object,
084:         * its finally clause can ensure the <code>AbstractSecurityInterceptor</code>
085:         * is re-called and tidies up correctly.</li>
086:         * <li>The concrete subclass will re-call the
087:         * <code>AbstractSecurityInterceptor</code> via the
088:         * {@link #afterInvocation(InterceptorStatusToken, Object)} method.</li>
089:         * <li>If the <code>RunAsManager</code> replaced the
090:         * <code>Authentication</code> object, return the
091:         * <code>SecurityContextHolder</code> to the object that existed after the
092:         * call to <code>AuthenticationManager</code>.</li>
093:         * <li>If an <code>AfterInvocationManager</code> is defined, invoke the
094:         * invocation manager and allow it to replace the object due to be returned to
095:         * the caller.</li>
096:         * </ol>
097:         * </li>
098:         * <li>For an invocation that is public (there is no
099:         * <code>ConfigAttributeDefinition</code> for the secure object invocation):
100:         * <ol type="a">
101:         * <li>As described above, the concrete subclass will be returned an
102:         * <code>InterceptorStatusToken</code> which is subsequently re-presented to
103:         * the <code>AbstractSecurityInterceptor</code> after the secure object has
104:         * been executed. The <code>AbstractSecurityInterceptor</code> will take no
105:         * further action when its {@link #afterInvocation(InterceptorStatusToken,
106:         * Object)} is called.</li>
107:         * </ol>
108:         * </li>
109:         * <li>Control again returns to the concrete subclass, along with the
110:         * <code>Object</code> that should be returned to the caller. The subclass
111:         * will then return that result or exception to the original caller.</li>
112:         * </ol>
113:         * </p>
114:         * 
115:         * @author Ben Alex
116:         * @version $Id: AbstractSecurityInterceptor.java 1790 2007-03-30 18:27:19Z
117:         * luke_t $
118:         */
119:        public abstract class AbstractSecurityInterceptor implements 
120:                InitializingBean, ApplicationEventPublisherAware,
121:                MessageSourceAware {
122:            // ~ Static fields/initializers
123:            // =====================================================================================
124:
125:            protected static final Log logger = LogFactory
126:                    .getLog(AbstractSecurityInterceptor.class);
127:
128:            // ~ Instance fields
129:            // ================================================================================================
130:
131:            private AccessDecisionManager accessDecisionManager;
132:
133:            private AfterInvocationManager afterInvocationManager;
134:
135:            private ApplicationEventPublisher eventPublisher;
136:
137:            private AuthenticationManager authenticationManager;
138:
139:            protected MessageSourceAccessor messages = AcegiMessageSource
140:                    .getAccessor();
141:
142:            private RunAsManager runAsManager = new NullRunAsManager();
143:
144:            private boolean alwaysReauthenticate = false;
145:
146:            private boolean rejectPublicInvocations = false;
147:
148:            private boolean validateConfigAttributes = true;
149:
150:            // ~ Methods
151:            // ========================================================================================================
152:
153:            /**
154:             * Completes the work of the <code>AbstractSecurityInterceptor</code>
155:             * after the secure object invocation has been complete
156:             * 
157:             * @param token as returned by the {@link #beforeInvocation(Object)}}
158:             * method
159:             * @param returnedObject any object returned from the secure object
160:             * invocation (may be<code>null</code>)
161:             * 
162:             * @return the object the secure object invocation should ultimately return
163:             * to its caller (may be <code>null</code>)
164:             */
165:            protected Object afterInvocation(InterceptorStatusToken token,
166:                    Object returnedObject) {
167:                if (token == null) {
168:                    // public object
169:                    return returnedObject;
170:                }
171:
172:                if (token.isContextHolderRefreshRequired()) {
173:                    if (logger.isDebugEnabled()) {
174:                        logger.debug("Reverting to original Authentication: "
175:                                + token.getAuthentication().toString());
176:                    }
177:
178:                    SecurityContextHolder.getContext().setAuthentication(
179:                            token.getAuthentication());
180:                }
181:
182:                if (afterInvocationManager != null) {
183:                    // Attempt after invocation handling
184:                    try {
185:                        returnedObject = afterInvocationManager.decide(token
186:                                .getAuthentication(), token.getSecureObject(),
187:                                token.getAttr(), returnedObject);
188:                    } catch (AccessDeniedException accessDeniedException) {
189:                        AuthorizationFailureEvent event = new AuthorizationFailureEvent(
190:                                token.getSecureObject(), token.getAttr(), token
191:                                        .getAuthentication(),
192:                                accessDeniedException);
193:                        publishEvent(event);
194:
195:                        throw accessDeniedException;
196:                    }
197:                }
198:
199:                return returnedObject;
200:            }
201:
202:            public void afterPropertiesSet() throws Exception {
203:                Assert
204:                        .notNull(getSecureObjectClass(),
205:                                "Subclass must provide a non-null response to getSecureObjectClass()");
206:
207:                Assert.notNull(this .messages, "A message source must be set");
208:
209:                Assert.notNull(this .authenticationManager,
210:                        "An AuthenticationManager is required");
211:
212:                Assert.notNull(this .accessDecisionManager,
213:                        "An AccessDecisionManager is required");
214:
215:                Assert.notNull(this .runAsManager, "A RunAsManager is required");
216:
217:                Assert.notNull(this .obtainObjectDefinitionSource(),
218:                        "An ObjectDefinitionSource is required");
219:
220:                Assert.isTrue(this .obtainObjectDefinitionSource().supports(
221:                        getSecureObjectClass()),
222:                        "ObjectDefinitionSource does not support secure object class: "
223:                                + getSecureObjectClass());
224:
225:                Assert.isTrue(this .runAsManager
226:                        .supports(getSecureObjectClass()),
227:                        "RunAsManager does not support secure object class: "
228:                                + getSecureObjectClass());
229:
230:                Assert.isTrue(this .accessDecisionManager
231:                        .supports(getSecureObjectClass()),
232:                        "AccessDecisionManager does not support secure object class: "
233:                                + getSecureObjectClass());
234:
235:                if (this .afterInvocationManager != null) {
236:                    Assert.isTrue(this .afterInvocationManager
237:                            .supports(getSecureObjectClass()),
238:                            "AfterInvocationManager does not support secure object class: "
239:                                    + getSecureObjectClass());
240:                }
241:
242:                if (this .validateConfigAttributes) {
243:                    Iterator iter = this .obtainObjectDefinitionSource()
244:                            .getConfigAttributeDefinitions();
245:
246:                    if (iter == null) {
247:                        logger
248:                                .warn("Could not validate configuration attributes as the MethodDefinitionSource did not return "
249:                                        + "a ConfigAttributeDefinition Iterator");
250:                        return;
251:                    }
252:
253:                    Set unsupportedAttrs = new HashSet();
254:
255:                    while (iter.hasNext()) {
256:                        ConfigAttributeDefinition def = (ConfigAttributeDefinition) iter
257:                                .next();
258:                        Iterator attributes = def.getConfigAttributes();
259:
260:                        while (attributes.hasNext()) {
261:                            ConfigAttribute attr = (ConfigAttribute) attributes
262:                                    .next();
263:
264:                            if (!this .runAsManager.supports(attr)
265:                                    && !this .accessDecisionManager
266:                                            .supports(attr)
267:                                    && ((this .afterInvocationManager == null) || !this .afterInvocationManager
268:                                            .supports(attr))) {
269:                                unsupportedAttrs.add(attr);
270:                            }
271:                        }
272:                    }
273:
274:                    if (unsupportedAttrs.size() != 0) {
275:                        throw new IllegalArgumentException(
276:                                "Unsupported configuration attributes: "
277:                                        + unsupportedAttrs);
278:                    }
279:
280:                    logger.info("Validated configuration attributes");
281:                }
282:            }
283:
284:            protected InterceptorStatusToken beforeInvocation(Object object) {
285:                Assert.notNull(object, "Object was null");
286:
287:                if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {
288:                    throw new IllegalArgumentException(
289:                            "Security invocation attempted for object "
290:                                    + object.getClass().getName()
291:                                    + " but AbstractSecurityInterceptor only configured to support secure objects of type: "
292:                                    + getSecureObjectClass());
293:                }
294:
295:                ConfigAttributeDefinition attr = this 
296:                        .obtainObjectDefinitionSource().getAttributes(object);
297:
298:                if (attr == null) {
299:                    if (rejectPublicInvocations) {
300:                        throw new IllegalArgumentException(
301:                                "No public invocations are allowed via this AbstractSecurityInterceptor. "
302:                                        + "This indicates a configuration error because the "
303:                                        + "AbstractSecurityInterceptor.rejectPublicInvocations property is set to 'true'");
304:                    }
305:
306:                    if (logger.isDebugEnabled()) {
307:                        logger
308:                                .debug("Public object - authentication not attempted");
309:                    }
310:
311:                    publishEvent(new PublicInvocationEvent(object));
312:
313:                    return null; // no further work post-invocation
314:                }
315:
316:                if (logger.isDebugEnabled()) {
317:                    logger.debug("Secure object: " + object.toString()
318:                            + "; ConfigAttributes: " + attr.toString());
319:                }
320:
321:                if (SecurityContextHolder.getContext().getAuthentication() == null) {
322:                    credentialsNotFound(
323:                            messages
324:                                    .getMessage(
325:                                            "AbstractSecurityInterceptor.authenticationNotFound",
326:                                            "An Authentication object was not found in the SecurityContext"),
327:                            object, attr);
328:                }
329:
330:                // Attempt authentication if not already authenticated, or user always
331:                // wants reauthentication
332:                Authentication authenticated;
333:
334:                if (!SecurityContextHolder.getContext().getAuthentication()
335:                        .isAuthenticated()
336:                        || alwaysReauthenticate) {
337:                    try {
338:                        authenticated = this .authenticationManager
339:                                .authenticate(SecurityContextHolder
340:                                        .getContext().getAuthentication());
341:                    } catch (AuthenticationException authenticationException) {
342:                        throw authenticationException;
343:                    }
344:
345:                    // We don't authenticated.setAuthentication(true), because each
346:                    // provider should do that
347:                    if (logger.isDebugEnabled()) {
348:                        logger.debug("Successfully Authenticated: "
349:                                + authenticated.toString());
350:                    }
351:
352:                    SecurityContextHolder.getContext().setAuthentication(
353:                            authenticated);
354:                } else {
355:                    authenticated = SecurityContextHolder.getContext()
356:                            .getAuthentication();
357:
358:                    if (logger.isDebugEnabled()) {
359:                        logger.debug("Previously Authenticated: "
360:                                + authenticated.toString());
361:                    }
362:                }
363:
364:                // Attempt authorization
365:                try {
366:                    this .accessDecisionManager.decide(authenticated, object,
367:                            attr);
368:                } catch (AccessDeniedException accessDeniedException) {
369:                    AuthorizationFailureEvent event = new AuthorizationFailureEvent(
370:                            object, attr, authenticated, accessDeniedException);
371:                    publishEvent(event);
372:
373:                    throw accessDeniedException;
374:                }
375:
376:                if (logger.isDebugEnabled()) {
377:                    logger.debug("Authorization successful");
378:                }
379:
380:                AuthorizedEvent event = new AuthorizedEvent(object, attr,
381:                        authenticated);
382:                publishEvent(event);
383:
384:                // Attempt to run as a different user
385:                Authentication runAs = this .runAsManager.buildRunAs(
386:                        authenticated, object, attr);
387:
388:                if (runAs == null) {
389:                    if (logger.isDebugEnabled()) {
390:                        logger
391:                                .debug("RunAsManager did not change Authentication object");
392:                    }
393:
394:                    // no further work post-invocation
395:                    return new InterceptorStatusToken(authenticated, false,
396:                            attr, object);
397:                } else {
398:                    if (logger.isDebugEnabled()) {
399:                        logger.debug("Switching to RunAs Authentication: "
400:                                + runAs.toString());
401:                    }
402:
403:                    SecurityContextHolder.getContext().setAuthentication(runAs);
404:
405:                    // revert to token.Authenticated post-invocation
406:                    return new InterceptorStatusToken(authenticated, true,
407:                            attr, object);
408:                }
409:            }
410:
411:            /**
412:             * Helper method which generates an exception containing the passed reason,
413:             * and publishes an event to the application context.
414:             * <p>
415:             * Always throws an exception.
416:             * </p>
417:             * 
418:             * @param reason to be provided in the exception detail
419:             * @param secureObject that was being called
420:             * @param configAttribs that were defined for the secureObject
421:             */
422:            private void credentialsNotFound(String reason,
423:                    Object secureObject, ConfigAttributeDefinition configAttribs) {
424:                AuthenticationCredentialsNotFoundException exception = new AuthenticationCredentialsNotFoundException(
425:                        reason);
426:
427:                AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(
428:                        secureObject, configAttribs, exception);
429:                publishEvent(event);
430:
431:                throw exception;
432:            }
433:
434:            public AccessDecisionManager getAccessDecisionManager() {
435:                return accessDecisionManager;
436:            }
437:
438:            public AfterInvocationManager getAfterInvocationManager() {
439:                return afterInvocationManager;
440:            }
441:
442:            public AuthenticationManager getAuthenticationManager() {
443:                return this .authenticationManager;
444:            }
445:
446:            public RunAsManager getRunAsManager() {
447:                return runAsManager;
448:            }
449:
450:            /**
451:             * Indicates the type of secure objects the subclass will be presenting to
452:             * the abstract parent for processing. This is used to ensure collaborators
453:             * wired to the <code>AbstractSecurityInterceptor</code> all support the
454:             * indicated secure object class.
455:             * 
456:             * @return the type of secure object the subclass provides services for
457:             */
458:            public abstract Class getSecureObjectClass();
459:
460:            public boolean isAlwaysReauthenticate() {
461:                return alwaysReauthenticate;
462:            }
463:
464:            public boolean isRejectPublicInvocations() {
465:                return rejectPublicInvocations;
466:            }
467:
468:            public boolean isValidateConfigAttributes() {
469:                return validateConfigAttributes;
470:            }
471:
472:            public abstract ObjectDefinitionSource obtainObjectDefinitionSource();
473:
474:            public void setAccessDecisionManager(
475:                    AccessDecisionManager accessDecisionManager) {
476:                this .accessDecisionManager = accessDecisionManager;
477:            }
478:
479:            public void setAfterInvocationManager(
480:                    AfterInvocationManager afterInvocationManager) {
481:                this .afterInvocationManager = afterInvocationManager;
482:            }
483:
484:            /**
485:             * Indicates whether the <code>AbstractSecurityInterceptor</code> should
486:             * ignore the {@link Authentication#isAuthenticated()} property. Defaults to
487:             * <code>false</code>, meaning by default the
488:             * <code>Authentication.isAuthenticated()</code> property is trusted and
489:             * re-authentication will not occur if the principal has already been
490:             * authenticated.
491:             * 
492:             * @param alwaysReauthenticate <code>true</code> to force
493:             * <code>AbstractSecurityInterceptor</code> to disregard the value of
494:             * <code>Authentication.isAuthenticated()</code> and always
495:             * re-authenticate the request (defaults to <code>false</code>).
496:             */
497:            public void setAlwaysReauthenticate(boolean alwaysReauthenticate) {
498:                this .alwaysReauthenticate = alwaysReauthenticate;
499:            }
500:
501:            public void setApplicationEventPublisher(
502:                    ApplicationEventPublisher applicationEventPublisher) {
503:                this .eventPublisher = applicationEventPublisher;
504:            }
505:
506:            public void setAuthenticationManager(
507:                    AuthenticationManager newManager) {
508:                this .authenticationManager = newManager;
509:            }
510:
511:            public void setMessageSource(MessageSource messageSource) {
512:                this .messages = new MessageSourceAccessor(messageSource);
513:            }
514:
515:            /**
516:             * By rejecting public invocations (and setting this property to
517:             * <code>true</code>), essentially you are ensuring that every secure
518:             * object invocation advised by <code>AbstractSecurityInterceptor</code>
519:             * has a configuration attribute defined. This is useful to ensure a "fail
520:             * safe" mode where undeclared secure objects will be rejected and
521:             * configuration omissions detected early. An
522:             * <code>IllegalArgumentException</code> will be thrown by the
523:             * <code>AbstractSecurityInterceptor</code> if you set this property to
524:             * <code>true</code> and an attempt is made to invoke a secure object that
525:             * has no configuration attributes.
526:             * 
527:             * @param rejectPublicInvocations set to <code>true</code> to reject
528:             * invocations of secure objects that have no configuration attributes (by
529:             * default it is <code>false</code> which treats undeclared secure objects
530:             * as "public" or unauthorized)
531:             */
532:            public void setRejectPublicInvocations(
533:                    boolean rejectPublicInvocations) {
534:                this .rejectPublicInvocations = rejectPublicInvocations;
535:            }
536:
537:            public void setRunAsManager(RunAsManager runAsManager) {
538:                this .runAsManager = runAsManager;
539:            }
540:
541:            public void setValidateConfigAttributes(
542:                    boolean validateConfigAttributes) {
543:                this .validateConfigAttributes = validateConfigAttributes;
544:            }
545:
546:            private void publishEvent(ApplicationEvent event) {
547:                if (this.eventPublisher != null) {
548:                    this.eventPublisher.publishEvent(event);
549:                }
550:            }
551:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.