Added net.sf.acegisecurity.intercept.event package.

This commit is contained in:
Ben Alex 2004-10-30 06:07:17 +00:00
parent 26f5f1a9b3
commit 537a58d754
9 changed files with 581 additions and 8 deletions

View File

@ -7,6 +7,7 @@ Changes in version 0.7 (2004-xx-xx)
* Added MethodDefinitionMap querying of interfaces defined by secure objects
* Added AuthenticationProcessingFilter.setDetails for use by subclasses
* Added 403-causing exception to HttpSession via SecurityEnforcementFilter
* Added net.sf.acegisecurity.intercept.event package
* Refactored MethodDefinitionSource to work with Method, not MethodInvocation
* Refactored AbstractSecurityInterceptor to better support other AOP libraries
* Fixed AbstractProcessingFitler to use removeAttribute (JRun compatibility)

View File

@ -16,8 +16,10 @@
package net.sf.acegisecurity.intercept;
import net.sf.acegisecurity.AccessDecisionManager;
import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationManager;
import net.sf.acegisecurity.ConfigAttribute;
import net.sf.acegisecurity.ConfigAttributeDefinition;
@ -25,13 +27,22 @@ import net.sf.acegisecurity.RunAsManager;
import net.sf.acegisecurity.context.Context;
import net.sf.acegisecurity.context.ContextHolder;
import net.sf.acegisecurity.context.SecureContext;
import net.sf.acegisecurity.intercept.event.AuthenticationCredentialsNotFoundEvent;
import net.sf.acegisecurity.intercept.event.AuthenticationFailureEvent;
import net.sf.acegisecurity.intercept.event.AuthorizationFailureEvent;
import net.sf.acegisecurity.intercept.event.AuthorizedEvent;
import net.sf.acegisecurity.intercept.event.PublicInvocationEvent;
import net.sf.acegisecurity.runas.NullRunAsManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@ -127,7 +138,8 @@ import java.util.Set;
* @author Ben Alex
* @version $Id$
*/
public abstract class AbstractSecurityInterceptor implements InitializingBean {
public abstract class AbstractSecurityInterceptor implements InitializingBean,
ApplicationContextAware {
//~ Static fields/initializers =============================================
protected static final Log logger = LogFactory.getLog(AbstractSecurityInterceptor.class);
@ -135,12 +147,18 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
//~ Instance fields ========================================================
private AccessDecisionManager accessDecisionManager;
private ApplicationContext context;
private AuthenticationManager authenticationManager;
private RunAsManager runAsManager = new NullRunAsManager();
private boolean validateConfigAttributes = true;
//~ Methods ================================================================
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
}
public abstract ObjectDefinitionSource obtainObjectDefinitionSource();
public void setAccessDecisionManager(
@ -253,6 +271,12 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
}
protected InterceptorStatusToken beforeInvocation(Object object) {
if (this.context != null) {
System.out.println("xx");
} else {
System.out.println("null");
}
if (object == null) {
throw new IllegalArgumentException("Object was null");
}
@ -275,8 +299,8 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
// Ensure ContextHolder presents a populated SecureContext
if ((ContextHolder.getContext() == null)
|| !(ContextHolder.getContext() instanceof SecureContext)) {
throw new AuthenticationCredentialsNotFoundException(
"A valid SecureContext was not provided in the RequestContext");
credentialsNotFound("A valid SecureContext was not provided in the RequestContext",
object, attr);
}
SecureContext context = (SecureContext) ContextHolder.getContext();
@ -284,13 +308,27 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
// We check for just the property we're interested in (we do
// not call Context.validate() like the ContextInterceptor)
if (context.getAuthentication() == null) {
throw new AuthenticationCredentialsNotFoundException(
"Authentication credentials were not found in the SecureContext");
credentialsNotFound("Authentication credentials were not found in the SecureContext",
object, attr);
}
// Attempt authentication
Authentication authenticated = this.authenticationManager
.authenticate(context.getAuthentication());
Authentication authenticated;
try {
authenticated = this.authenticationManager.authenticate(context
.getAuthentication());
} catch (AuthenticationException authenticationException) {
if (this.context != null) {
AuthenticationFailureEvent event = new AuthenticationFailureEvent(object,
attr, context.getAuthentication(),
authenticationException);
this.context.publishEvent(event);
}
throw authenticationException;
}
authenticated.setAuthenticated(true);
if (logger.isDebugEnabled()) {
@ -301,12 +339,28 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
ContextHolder.setContext((Context) context);
// Attempt authorization
this.accessDecisionManager.decide(authenticated, object, attr);
try {
this.accessDecisionManager.decide(authenticated, object, attr);
} catch (AccessDeniedException accessDeniedException) {
if (this.context != null) {
AuthorizationFailureEvent event = new AuthorizationFailureEvent(object,
attr, authenticated, accessDeniedException);
this.context.publishEvent(event);
}
throw accessDeniedException;
}
if (logger.isDebugEnabled()) {
logger.debug("Authorization successful");
}
if (this.context != null) {
AuthorizedEvent event = new AuthorizedEvent(object, attr,
authenticated);
this.context.publishEvent(event);
}
// Attempt to run as a different user
Authentication runAs = this.runAsManager.buildRunAs(authenticated,
object, attr);
@ -337,6 +391,10 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
logger.debug("Public object - authentication not attempted");
}
if (this.context != null) {
this.context.publishEvent(new PublicInvocationEvent(object));
}
// Set Authentication object (if it exists) to be unauthenticated
if ((ContextHolder.getContext() != null)
&& ContextHolder.getContext() instanceof SecureContext) {
@ -359,4 +417,29 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean {
return null; // no further work post-invocation
}
}
/**
* Helper method which generates an exception contained the passed reason,
* and publishes an event to the application context.
*
* <P>
* Always throws an exception.
* </p>
*
* @param reason to be provided in the exceptiond detail
* @param secureObject that was being called
* @param configAttribs that were defined for the secureObject
*/
private void credentialsNotFound(String reason, Object secureObject,
ConfigAttributeDefinition configAttribs) {
AuthenticationCredentialsNotFoundException exception = new AuthenticationCredentialsNotFoundException(reason);
if (this.context != null) {
AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(secureObject,
configAttribs, exception);
this.context.publishEvent(event);
}
throw exception;
}
}

View File

@ -0,0 +1,72 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.intercept.event;
import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException;
import net.sf.acegisecurity.ConfigAttributeDefinition;
/**
* Indicates a secure object invocation failed because the
* <code>Authentication</code> could not be obtained from the
* <code>ContextHolder</code>.
*
* @author Ben Alex
* @version $Id$
*/
public class AuthenticationCredentialsNotFoundEvent
extends SecurityInterceptionEvent {
//~ Instance fields ========================================================
private AuthenticationCredentialsNotFoundException credentialsNotFoundException;
private ConfigAttributeDefinition configAttributeDefinition;
//~ Constructors ===========================================================
/**
* Construct the event.
*
* @param secureObject the secure object
* @param configAttribs that apply to the secure object
* @param credentialsNotFoundException exception returned to the caller
* (contains reason)
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public AuthenticationCredentialsNotFoundEvent(Object secureObject,
ConfigAttributeDefinition configAttribs,
AuthenticationCredentialsNotFoundException credentialsNotFoundException) {
super(secureObject);
if ((configAttribs == null) || (credentialsNotFoundException == null)) {
throw new IllegalArgumentException(
"All parameters are required and cannot be null");
}
this.configAttributeDefinition = configAttribs;
this.credentialsNotFoundException = credentialsNotFoundException;
}
//~ Methods ================================================================
public ConfigAttributeDefinition getConfigAttributeDefinition() {
return configAttributeDefinition;
}
public AuthenticationCredentialsNotFoundException getCredentialsNotFoundException() {
return credentialsNotFoundException;
}
}

View File

@ -0,0 +1,79 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.intercept.event;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.ConfigAttributeDefinition;
/**
* Indicates a secure object invocation failed because the principal could not
* be authenticated.
*
* @author Ben Alex
* @version $Id$
*/
public class AuthenticationFailureEvent extends SecurityInterceptionEvent {
//~ Instance fields ========================================================
private Authentication authentication;
private AuthenticationException authenticationException;
private ConfigAttributeDefinition configAttributeDefinition;
//~ Constructors ===========================================================
/**
* Construct the event.
*
* @param secureObject the secure object
* @param configAttribs that apply to the secure object
* @param authentication that was found on the <code>ContextHolder</code>
* @param authenticationException that was returned by the
* <code>AuthenticationManager</code>
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public AuthenticationFailureEvent(Object secureObject,
ConfigAttributeDefinition configAttribs, Authentication authentication,
AuthenticationException authenticationException) {
super(secureObject);
if ((configAttribs == null) || (authentication == null)
|| (authenticationException == null)) {
throw new IllegalArgumentException(
"All parameters are required and cannot be null");
}
this.configAttributeDefinition = configAttribs;
this.authentication = authentication;
this.authenticationException = authenticationException;
}
//~ Methods ================================================================
public Authentication getAuthentication() {
return authentication;
}
public AuthenticationException getAuthenticationException() {
return authenticationException;
}
public ConfigAttributeDefinition getConfigAttributeDefinition() {
return configAttributeDefinition;
}
}

View File

@ -0,0 +1,79 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.intercept.event;
import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.ConfigAttributeDefinition;
/**
* Indicates a secure object invocation failed because the principal could not
* be authorized for the request.
*
* @author Ben Alex
* @version $Id$
*/
public class AuthorizationFailureEvent extends SecurityInterceptionEvent {
//~ Instance fields ========================================================
private AccessDeniedException accessDeniedException;
private Authentication authentication;
private ConfigAttributeDefinition configAttributeDefinition;
//~ Constructors ===========================================================
/**
* Construct the event.
*
* @param secureObject the secure object
* @param configAttribs that apply to the secure object
* @param authentication that was found on the <code>ContextHolder</code>
* @param accessDeniedException that was returned by the
* <code>AccessDecisionManager</code>
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public AuthorizationFailureEvent(Object secureObject,
ConfigAttributeDefinition configAttribs, Authentication authentication,
AccessDeniedException accessDeniedException) {
super(secureObject);
if ((configAttribs == null) || (authentication == null)
|| (accessDeniedException == null)) {
throw new IllegalArgumentException(
"All parameters are required and cannot be null");
}
this.configAttributeDefinition = configAttribs;
this.authentication = authentication;
this.accessDeniedException = accessDeniedException;
}
//~ Methods ================================================================
public AccessDeniedException getAccessDeniedException() {
return accessDeniedException;
}
public Authentication getAuthentication() {
return authentication;
}
public ConfigAttributeDefinition getConfigAttributeDefinition() {
return configAttributeDefinition;
}
}

View File

@ -0,0 +1,71 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.intercept.event;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.ConfigAttributeDefinition;
/**
* Event indicating a secure object was invoked successfully.
*
* <P>
* Published just before the secure object attempts to proceed.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class AuthorizedEvent extends SecurityInterceptionEvent {
//~ Instance fields ========================================================
private Authentication authentication;
private ConfigAttributeDefinition configAttributeDefinition;
//~ Constructors ===========================================================
/**
* Construct the event.
*
* @param secureObject the secure object
* @param configAttribs that apply to the secure object
* @param authentication that successfully called the secure object
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public AuthorizedEvent(Object secureObject,
ConfigAttributeDefinition configAttribs, Authentication authentication) {
super(secureObject);
if ((configAttribs == null) || (authentication == null)) {
throw new IllegalArgumentException(
"All parameters are required and cannot be null");
}
this.configAttributeDefinition = configAttribs;
this.authentication = authentication;
}
//~ Methods ================================================================
public Authentication getAuthentication() {
return authentication;
}
public ConfigAttributeDefinition getConfigAttributeDefinition() {
return configAttributeDefinition;
}
}

View File

@ -0,0 +1,104 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.intercept.event;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
/**
* Outputs interceptor-related application events to Commons Logging.
*
* <P>
* All failures are logged at the warning level, with success events logged at
* the information level, and public invocation events logged at the debug
* level.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class LoggerListener implements ApplicationListener {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(LoggerListener.class);
//~ Methods ================================================================
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof AuthenticationCredentialsNotFoundEvent) {
AuthenticationCredentialsNotFoundEvent authEvent = (AuthenticationCredentialsNotFoundEvent) event;
if (logger.isWarnEnabled()) {
logger.warn("Security interception failed due to: "
+ authEvent.getCredentialsNotFoundException()
+ "; secure object: " + authEvent.getSource()
+ "; configuration attributes: "
+ authEvent.getConfigAttributeDefinition());
}
}
if (event instanceof AuthenticationFailureEvent) {
AuthenticationFailureEvent authEvent = (AuthenticationFailureEvent) event;
if (logger.isWarnEnabled()) {
logger.warn("Security authentication failed due to: "
+ authEvent.getAuthenticationException()
+ "; for authentication request: "
+ authEvent.getAuthentication() + "; secure object: "
+ authEvent.getSource() + "; configuration attributes: "
+ authEvent.getConfigAttributeDefinition());
}
}
if (event instanceof AuthorizationFailureEvent) {
AuthorizationFailureEvent authEvent = (AuthorizationFailureEvent) event;
if (logger.isWarnEnabled()) {
logger.warn("Security authorization failed due to: "
+ authEvent.getAccessDeniedException()
+ "; authenticated principal: "
+ authEvent.getAuthentication() + "; secure object: "
+ authEvent.getSource() + "; configuration attributes: "
+ authEvent.getConfigAttributeDefinition());
}
}
if (event instanceof AuthorizedEvent) {
AuthorizedEvent authEvent = (AuthorizedEvent) event;
if (logger.isInfoEnabled()) {
logger.info("Security authorized for authenticated principal: "
+ authEvent.getAuthentication() + "; secure object: "
+ authEvent.getSource() + "; configuration attributes: "
+ authEvent.getConfigAttributeDefinition());
}
}
if (event instanceof PublicInvocationEvent) {
PublicInvocationEvent authEvent = (PublicInvocationEvent) event;
if (logger.isInfoEnabled()) {
logger.info(
"Security interception not required for public secure object: "
+ authEvent.getSource());
}
}
}
}

View File

@ -0,0 +1,46 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.intercept.event;
/**
* Event that is generated whenever a public secure object is invoked.
*
* <P>
* A public secure object is a secure object that has no
* <code>ConfigAttributeDefinition</code> defined. A public secure object will
* not cause the <code>ContextHolder</code> to be inspected or authenticated,
* and no authorization will take place.
* </p>
*
* <P>
* Published just before the secure object attempts to proceed.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class PublicInvocationEvent extends SecurityInterceptionEvent {
//~ Constructors ===========================================================
/**
* Construct the event, passing in the public secure object.
*
* @param secureObject the public secure object
*/
public PublicInvocationEvent(Object secureObject) {
super(secureObject);
}
}

View File

@ -0,0 +1,38 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.intercept.event;
import org.springframework.context.ApplicationEvent;
/**
* Abstract superclass for all security interception related events.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class SecurityInterceptionEvent extends ApplicationEvent {
//~ Constructors ===========================================================
/**
* Construct the event, passing in the secure object being intercepted.
*
* @param secureObject the secure object
*/
public SecurityInterceptionEvent(Object secureObject) {
super(secureObject);
}
}