1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.intercept;
17
18 import org.acegisecurity.AccessDecisionManager;
19 import org.acegisecurity.AccessDeniedException;
20 import org.acegisecurity.AcegiMessageSource;
21 import org.acegisecurity.AfterInvocationManager;
22 import org.acegisecurity.Authentication;
23 import org.acegisecurity.AuthenticationCredentialsNotFoundException;
24 import org.acegisecurity.AuthenticationException;
25 import org.acegisecurity.AuthenticationManager;
26 import org.acegisecurity.ConfigAttribute;
27 import org.acegisecurity.ConfigAttributeDefinition;
28 import org.acegisecurity.RunAsManager;
29
30 import org.acegisecurity.context.SecurityContextHolder;
31
32 import org.acegisecurity.event.authorization.AuthenticationCredentialsNotFoundEvent;
33 import org.acegisecurity.event.authorization.AuthorizationFailureEvent;
34 import org.acegisecurity.event.authorization.AuthorizedEvent;
35 import org.acegisecurity.event.authorization.PublicInvocationEvent;
36
37 import org.acegisecurity.runas.NullRunAsManager;
38
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41
42 import org.springframework.beans.factory.InitializingBean;
43
44 import org.springframework.context.ApplicationEvent;
45 import org.springframework.context.ApplicationEventPublisher;
46 import org.springframework.context.ApplicationEventPublisherAware;
47 import org.springframework.context.MessageSource;
48 import org.springframework.context.MessageSourceAware;
49 import org.springframework.context.support.MessageSourceAccessor;
50
51 import org.springframework.util.Assert;
52
53 import java.util.HashSet;
54 import java.util.Iterator;
55 import java.util.Set;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119 public abstract class AbstractSecurityInterceptor implements InitializingBean, ApplicationEventPublisherAware,
120 MessageSourceAware {
121
122
123
124 protected static final Log logger = LogFactory.getLog(AbstractSecurityInterceptor.class);
125
126
127
128
129 private AccessDecisionManager accessDecisionManager;
130
131 private AfterInvocationManager afterInvocationManager;
132
133 private ApplicationEventPublisher eventPublisher;
134
135 private AuthenticationManager authenticationManager;
136
137 protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
138
139 private RunAsManager runAsManager = new NullRunAsManager();
140
141 private boolean alwaysReauthenticate = false;
142
143 private boolean rejectPublicInvocations = false;
144
145 private boolean validateConfigAttributes = true;
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162 protected Object afterInvocation(InterceptorStatusToken token, Object returnedObject) {
163 if (token == null) {
164
165 return returnedObject;
166 }
167
168 if (token.isContextHolderRefreshRequired()) {
169 if (logger.isDebugEnabled()) {
170 logger.debug("Reverting to original Authentication: " + token.getAuthentication().toString());
171 }
172
173 SecurityContextHolder.getContext().setAuthentication(token.getAuthentication());
174 }
175
176 if (afterInvocationManager != null) {
177
178 try {
179 returnedObject = afterInvocationManager.decide(token.getAuthentication(), token.getSecureObject(),
180 token.getAttr(), returnedObject);
181 }
182 catch (AccessDeniedException accessDeniedException) {
183 AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(), token
184 .getAttr(), token.getAuthentication(), accessDeniedException);
185 publishEvent(event);
186
187 throw accessDeniedException;
188 }
189 }
190
191 return returnedObject;
192 }
193
194 public void afterPropertiesSet() throws Exception {
195 Assert.notNull(getSecureObjectClass(), "Subclass must provide a non-null response to getSecureObjectClass()");
196
197 Assert.notNull(this.messages, "A message source must be set");
198
199 Assert.notNull(this.authenticationManager, "An AuthenticationManager is required");
200
201 Assert.notNull(this.accessDecisionManager, "An AccessDecisionManager is required");
202
203 Assert.notNull(this.runAsManager, "A RunAsManager is required");
204
205 Assert.notNull(this.obtainObjectDefinitionSource(), "An ObjectDefinitionSource is required");
206
207 Assert.isTrue(this.obtainObjectDefinitionSource().supports(getSecureObjectClass()),
208 "ObjectDefinitionSource does not support secure object class: " + getSecureObjectClass());
209
210 Assert.isTrue(this.runAsManager.supports(getSecureObjectClass()),
211 "RunAsManager does not support secure object class: " + getSecureObjectClass());
212
213 Assert.isTrue(this.accessDecisionManager.supports(getSecureObjectClass()),
214 "AccessDecisionManager does not support secure object class: " + getSecureObjectClass());
215
216 if (this.afterInvocationManager != null) {
217 Assert.isTrue(this.afterInvocationManager.supports(getSecureObjectClass()),
218 "AfterInvocationManager does not support secure object class: " + getSecureObjectClass());
219 }
220
221 if (this.validateConfigAttributes) {
222 Iterator iter = this.obtainObjectDefinitionSource().getConfigAttributeDefinitions();
223
224 if (iter == null) {
225 logger.warn("Could not validate configuration attributes as the MethodDefinitionSource did not return "
226 + "a ConfigAttributeDefinition Iterator");
227 return;
228 }
229
230 Set unsupportedAttrs = new HashSet();
231
232 while (iter.hasNext()) {
233 ConfigAttributeDefinition def = (ConfigAttributeDefinition) iter.next();
234 Iterator attributes = def.getConfigAttributes();
235
236 while (attributes.hasNext()) {
237 ConfigAttribute attr = (ConfigAttribute) attributes.next();
238
239 if (!this.runAsManager.supports(attr) && !this.accessDecisionManager.supports(attr)
240 && ((this.afterInvocationManager == null) || !this.afterInvocationManager.supports(attr))) {
241 unsupportedAttrs.add(attr);
242 }
243 }
244 }
245
246 if (unsupportedAttrs.size() != 0) {
247 throw new IllegalArgumentException("Unsupported configuration attributes: " + unsupportedAttrs);
248 }
249
250 logger.info("Validated configuration attributes");
251 }
252 }
253
254 protected InterceptorStatusToken beforeInvocation(Object object) {
255 Assert.notNull(object, "Object was null");
256
257 if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {
258 throw new IllegalArgumentException("Security invocation attempted for object "
259 + object.getClass().getName()
260 + " but AbstractSecurityInterceptor only configured to support secure objects of type: "
261 + getSecureObjectClass());
262 }
263
264 ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource().getAttributes(object);
265
266 if (attr == null) {
267 if (rejectPublicInvocations) {
268 throw new IllegalArgumentException(
269 "No public invocations are allowed via this AbstractSecurityInterceptor. "
270 + "This indicates a configuration error because the "
271 + "AbstractSecurityInterceptor.rejectPublicInvocations property is set to 'true'");
272 }
273
274 if (logger.isDebugEnabled()) {
275 logger.debug("Public object - authentication not attempted");
276 }
277
278 publishEvent(new PublicInvocationEvent(object));
279
280 return null;
281 }
282
283 if (logger.isDebugEnabled()) {
284 logger.debug("Secure object: " + object.toString() + "; ConfigAttributes: " + attr.toString());
285 }
286
287 if (SecurityContextHolder.getContext().getAuthentication() == null) {
288 credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",
289 "An Authentication object was not found in the SecurityContext"), object, attr);
290 }
291
292
293
294 Authentication authenticated;
295
296 if (!SecurityContextHolder.getContext().getAuthentication().isAuthenticated() || alwaysReauthenticate) {
297 try {
298 authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext()
299 .getAuthentication());
300 }
301 catch (AuthenticationException authenticationException) {
302 throw authenticationException;
303 }
304
305
306
307 if (logger.isDebugEnabled()) {
308 logger.debug("Successfully Authenticated: " + authenticated.toString());
309 }
310
311 SecurityContextHolder.getContext().setAuthentication(authenticated);
312 }
313 else {
314 authenticated = SecurityContextHolder.getContext().getAuthentication();
315
316 if (logger.isDebugEnabled()) {
317 logger.debug("Previously Authenticated: " + authenticated.toString());
318 }
319 }
320
321
322 try {
323 this.accessDecisionManager.decide(authenticated, object, attr);
324 }
325 catch (AccessDeniedException accessDeniedException) {
326 AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, attr, authenticated,
327 accessDeniedException);
328 publishEvent(event);
329
330 throw accessDeniedException;
331 }
332
333 if (logger.isDebugEnabled()) {
334 logger.debug("Authorization successful");
335 }
336
337 AuthorizedEvent event = new AuthorizedEvent(object, attr, authenticated);
338 publishEvent(event);
339
340
341 Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attr);
342
343 if (runAs == null) {
344 if (logger.isDebugEnabled()) {
345 logger.debug("RunAsManager did not change Authentication object");
346 }
347
348
349 return new InterceptorStatusToken(authenticated, false, attr, object);
350 }
351 else {
352 if (logger.isDebugEnabled()) {
353 logger.debug("Switching to RunAs Authentication: " + runAs.toString());
354 }
355
356 SecurityContextHolder.getContext().setAuthentication(runAs);
357
358
359 return new InterceptorStatusToken(authenticated, true, attr, object);
360 }
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374 private void credentialsNotFound(String reason, Object secureObject, ConfigAttributeDefinition configAttribs) {
375 AuthenticationCredentialsNotFoundException exception = new AuthenticationCredentialsNotFoundException(reason);
376
377 AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(secureObject,
378 configAttribs, exception);
379 publishEvent(event);
380
381 throw exception;
382 }
383
384 public AccessDecisionManager getAccessDecisionManager() {
385 return accessDecisionManager;
386 }
387
388 public AfterInvocationManager getAfterInvocationManager() {
389 return afterInvocationManager;
390 }
391
392 public AuthenticationManager getAuthenticationManager() {
393 return this.authenticationManager;
394 }
395
396 public RunAsManager getRunAsManager() {
397 return runAsManager;
398 }
399
400
401
402
403
404
405
406
407
408 public abstract Class getSecureObjectClass();
409
410 public boolean isAlwaysReauthenticate() {
411 return alwaysReauthenticate;
412 }
413
414 public boolean isRejectPublicInvocations() {
415 return rejectPublicInvocations;
416 }
417
418 public boolean isValidateConfigAttributes() {
419 return validateConfigAttributes;
420 }
421
422 public abstract ObjectDefinitionSource obtainObjectDefinitionSource();
423
424 public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) {
425 this.accessDecisionManager = accessDecisionManager;
426 }
427
428 public void setAfterInvocationManager(AfterInvocationManager afterInvocationManager) {
429 this.afterInvocationManager = afterInvocationManager;
430 }
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445 public void setAlwaysReauthenticate(boolean alwaysReauthenticate) {
446 this.alwaysReauthenticate = alwaysReauthenticate;
447 }
448
449 public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
450 this.eventPublisher = applicationEventPublisher;
451 }
452
453 public void setAuthenticationManager(AuthenticationManager newManager) {
454 this.authenticationManager = newManager;
455 }
456
457 public void setMessageSource(MessageSource messageSource) {
458 this.messages = new MessageSourceAccessor(messageSource);
459 }
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478 public void setRejectPublicInvocations(boolean rejectPublicInvocations) {
479 this.rejectPublicInvocations = rejectPublicInvocations;
480 }
481
482 public void setRunAsManager(RunAsManager runAsManager) {
483 this.runAsManager = runAsManager;
484 }
485
486 public void setValidateConfigAttributes(boolean validateConfigAttributes) {
487 this.validateConfigAttributes = validateConfigAttributes;
488 }
489
490 private void publishEvent(ApplicationEvent event) {
491 if (this.eventPublisher != null) {
492 this.eventPublisher.publishEvent(event);
493 }
494 }
495 }