mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-12 05:13:33 +00:00
Initial commit.
This commit is contained in:
parent
6ddc006012
commit
738fd2161d
@ -0,0 +1,366 @@
|
|||||||
|
/* 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;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.AccessDecisionManager;
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException;
|
||||||
|
import net.sf.acegisecurity.AuthenticationManager;
|
||||||
|
import net.sf.acegisecurity.ConfigAttribute;
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||||
|
import net.sf.acegisecurity.RunAsManager;
|
||||||
|
import net.sf.acegisecurity.context.Context;
|
||||||
|
import net.sf.acegisecurity.context.ContextHolder;
|
||||||
|
import net.sf.acegisecurity.context.SecureContext;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class that implements security interception for secure objects.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* The <code>AbstractSecurityInterceptor</code> will ensure the proper startup
|
||||||
|
* configuration of the security interceptor. It will also implement the
|
||||||
|
* proper handling of secure object invocations, being:
|
||||||
|
*
|
||||||
|
* <ol>
|
||||||
|
* <li>
|
||||||
|
* Extract the {@link SecureContext} from the {@link ContextHolder}, handling
|
||||||
|
* any errors such as invalid or <code>null</code> objects.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* Obtain the {@link Authentication} object from the extracted
|
||||||
|
* <code>SecureContext</code>.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* Determine if the request relates to a secured or public invocation by
|
||||||
|
* looking up the secure object request against the {@link
|
||||||
|
* ObjectDefinitionSource}.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* For an invocation that is secured (there is a
|
||||||
|
* <code>ConfigAttributeDefinition</code> for the secure object invocation):
|
||||||
|
*
|
||||||
|
* <ol>
|
||||||
|
* <li>
|
||||||
|
* Authenticate the request against the configured {@link
|
||||||
|
* AuthenticationManager}, replacing the <code>Authentication</code> object on
|
||||||
|
* the <code>ContextHolder</code> with the returned value.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* Authorize the request against the configured {@link AccessDecisionManager}.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* Perform any run-as replacement via the configured {@link RunAsManager}.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* Perform a callback to the {@link SecurityInterceptorCallback}, which will
|
||||||
|
* actually proceed with executing the object.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* If the <code>RunAsManager</code> replaced the <code>Authentication</code>
|
||||||
|
* object, return the <code>ContextHolder</code> to the object that existed
|
||||||
|
* after the call to <code>AuthenticationManager</code>.
|
||||||
|
* </li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* For an invocation that is public (there is no
|
||||||
|
* <code>ConfigAttributeDefinition</code> for the secure object invocation):
|
||||||
|
*
|
||||||
|
* <ol>
|
||||||
|
* <li>
|
||||||
|
* If the <code>ContextHolder</code> contains a <code>SecureContext</code>, set
|
||||||
|
* the <code>isAuthenticated</code> flag on the <code>Authentication</code>
|
||||||
|
* object to false.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* Perform a callback to the {@link SecurityInterceptorCallback}, which will
|
||||||
|
* actually proceed with the invocation.
|
||||||
|
* </li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* Return the result from the <code>SecurityInterceptorCallback</code> to the
|
||||||
|
* method that called {@link AbstractSecurityInterceptor#interceptor(Object,
|
||||||
|
* SecurityInterceptorCallback)}. This is almost always a concrete subclass of
|
||||||
|
* the <code>AbstractSecurityInterceptor</code>.
|
||||||
|
* </li>
|
||||||
|
* </ol>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public abstract class AbstractSecurityInterceptor implements InitializingBean {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
protected static final Log logger = LogFactory.getLog(AbstractSecurityInterceptor.class);
|
||||||
|
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private AccessDecisionManager accessDecisionManager;
|
||||||
|
private AuthenticationManager authenticationManager;
|
||||||
|
private RunAsManager runAsManager;
|
||||||
|
private boolean validateConfigAttributes = true;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public abstract ObjectDefinitionSource obtainObjectDefinitionSource();
|
||||||
|
|
||||||
|
public void setAccessDecisionManager(
|
||||||
|
AccessDecisionManager accessDecisionManager) {
|
||||||
|
this.accessDecisionManager = accessDecisionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessDecisionManager getAccessDecisionManager() {
|
||||||
|
return accessDecisionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthenticationManager(AuthenticationManager newManager) {
|
||||||
|
this.authenticationManager = newManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationManager getAuthenticationManager() {
|
||||||
|
return this.authenticationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRunAsManager(RunAsManager runAsManager) {
|
||||||
|
this.runAsManager = runAsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RunAsManager getRunAsManager() {
|
||||||
|
return runAsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValidateConfigAttributes(boolean validateConfigAttributes) {
|
||||||
|
this.validateConfigAttributes = validateConfigAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValidateConfigAttributes() {
|
||||||
|
return validateConfigAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
if (this.authenticationManager == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"An AuthenticationManager is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.accessDecisionManager == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"An AccessDecisionManager is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.runAsManager == null) {
|
||||||
|
throw new IllegalArgumentException("A RunAsManager is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.obtainObjectDefinitionSource() == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"An ObjectDefinitionSource is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.validateConfigAttributes) {
|
||||||
|
Iterator iter = this.obtainObjectDefinitionSource()
|
||||||
|
.getConfigAttributeDefinitions();
|
||||||
|
|
||||||
|
if (iter == null) {
|
||||||
|
if (logger.isWarnEnabled()) {
|
||||||
|
logger.warn(
|
||||||
|
"Could not validate configuration attributes as the MethodDefinitionSource did not return a ConfigAttributeDefinition Iterator");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set set = new HashSet();
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
ConfigAttributeDefinition def = (ConfigAttributeDefinition) iter
|
||||||
|
.next();
|
||||||
|
Iterator attributes = def.getConfigAttributes();
|
||||||
|
|
||||||
|
while (attributes.hasNext()) {
|
||||||
|
ConfigAttribute attr = (ConfigAttribute) attributes.next();
|
||||||
|
|
||||||
|
if (!this.runAsManager.supports(attr)
|
||||||
|
&& !this.accessDecisionManager.supports(attr)) {
|
||||||
|
set.add(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set.size() == 0) {
|
||||||
|
if (logger.isInfoEnabled()) {
|
||||||
|
logger.info("Validated configuration attributes");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unsupported configuration attributes: " + set.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the work of authenticating and authorizing the request.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Throws {@link net.sf.acegisecurity.AcegiSecurityException} and its
|
||||||
|
* subclasses.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param object details of a secure object invocation
|
||||||
|
* @param callback the object that will complete the target secure object
|
||||||
|
* invocation
|
||||||
|
*
|
||||||
|
* @return The value that was returned by the
|
||||||
|
* <code>SecurityInterceptorCallback</code>
|
||||||
|
*
|
||||||
|
* @throws Throwable if any error occurs during the
|
||||||
|
* <code>SecurityInterceptorCallback</code>
|
||||||
|
* @throws IllegalArgumentException if a required argument was missing or
|
||||||
|
* invalid
|
||||||
|
* @throws AuthenticationCredentialsNotFoundException if the
|
||||||
|
* <code>ContextHolder</code> is not populated with a valid
|
||||||
|
* <code>SecureContext</code>
|
||||||
|
*/
|
||||||
|
public Object interceptor(Object object,
|
||||||
|
SecurityInterceptorCallback callback) throws Throwable {
|
||||||
|
if (object == null) {
|
||||||
|
throw new IllegalArgumentException("Object was null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback == null) {
|
||||||
|
throw new IllegalArgumentException("Callback was null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.obtainObjectDefinitionSource().supports(object.getClass())) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"ObjectDefinitionSource does not support objects of type "
|
||||||
|
+ object.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource()
|
||||||
|
.getAttributes(object);
|
||||||
|
|
||||||
|
if (attr != null) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Secure object: " + object.toString()
|
||||||
|
+ "; ConfigAttributes: " + attr.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
SecureContext context = (SecureContext) ContextHolder.getContext();
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt authentication
|
||||||
|
Authentication authenticated = this.authenticationManager
|
||||||
|
.authenticate(context.getAuthentication());
|
||||||
|
authenticated.setAuthenticated(true);
|
||||||
|
logger.debug("Authenticated: " + authenticated.toString());
|
||||||
|
context.setAuthentication(authenticated);
|
||||||
|
ContextHolder.setContext((Context) context);
|
||||||
|
|
||||||
|
// Attempt authorization
|
||||||
|
this.accessDecisionManager.decide(authenticated, object, attr);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Authorization successful");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to run as a different user
|
||||||
|
Authentication runAs = this.runAsManager.buildRunAs(authenticated,
|
||||||
|
object, attr);
|
||||||
|
|
||||||
|
if (runAs == null) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"RunAsManager did not change Authentication object");
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback.proceedWithObject(object);
|
||||||
|
} else {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Switching to RunAs Authentication: "
|
||||||
|
+ runAs.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
context.setAuthentication(runAs);
|
||||||
|
ContextHolder.setContext((Context) context);
|
||||||
|
|
||||||
|
Object ret = callback.proceedWithObject(object);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Reverting to original Authentication: "
|
||||||
|
+ authenticated.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
context.setAuthentication(authenticated);
|
||||||
|
ContextHolder.setContext((Context) context);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Public object - authentication not attempted");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Authentication object (if it exists) to be unauthenticated
|
||||||
|
if ((ContextHolder.getContext() != null)
|
||||||
|
&& ContextHolder.getContext() instanceof SecureContext) {
|
||||||
|
SecureContext context = (SecureContext) ContextHolder
|
||||||
|
.getContext();
|
||||||
|
|
||||||
|
if (context.getAuthentication() != null) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"Authentication object detected and tagged as unauthenticated");
|
||||||
|
}
|
||||||
|
|
||||||
|
Authentication authenticated = context.getAuthentication();
|
||||||
|
authenticated.setAuthenticated(false);
|
||||||
|
context.setAuthentication(authenticated);
|
||||||
|
ContextHolder.setContext((Context) context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback.proceedWithObject(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/* 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;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented by classes that store and can identify the {@link
|
||||||
|
* ConfigAttributeDefinition} that applies to a given secure object
|
||||||
|
* invocation.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public interface ObjectDefinitionSource {
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accesses the <code>ConfigAttributeDefinition</code> that applies to a
|
||||||
|
* given secure object.
|
||||||
|
*
|
||||||
|
* @param object the object being secured
|
||||||
|
*
|
||||||
|
* @return the <code>ConfigAttributeDefinition</code> that applies to the
|
||||||
|
* passed object
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if the passed object is not of a type
|
||||||
|
* supported by the <code>ObjectDefinitionSource</code>
|
||||||
|
* implementation
|
||||||
|
*/
|
||||||
|
public ConfigAttributeDefinition getAttributes(Object object)
|
||||||
|
throws IllegalArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If available, all of the <code>ConfigAttributeDefinition</code>s defined
|
||||||
|
* by the implementing class.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* This is used by the {@link AbstractSecurityInterceptor} to perform
|
||||||
|
* startup time validation of each <code>ConfigAttribute</code> configured
|
||||||
|
* against it.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return an iterator over all the <code>ConfigAttributeDefinition</code>s
|
||||||
|
* or <code>null</code> if unsupported
|
||||||
|
*/
|
||||||
|
public Iterator getConfigAttributeDefinitions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the <code>ObjectDefinitionSource</code> implementation
|
||||||
|
* is able to provide <code>ConfigAttributeDefinition</code>s for the
|
||||||
|
* indicated secure object type.
|
||||||
|
*
|
||||||
|
* @param clazz the class that is being queried
|
||||||
|
*
|
||||||
|
* @return true if the implementation can process the indicated class
|
||||||
|
*/
|
||||||
|
public boolean supports(Class clazz);
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the {@link AbstractSecurityInterceptor} to continue the secure object
|
||||||
|
* invocation at the appropriate time.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Concrete <code>AbstractSecurityInterceptor</code> subclasses are required to
|
||||||
|
* provide a <code>SecurityInterceptorCallback</code>. This is called by the
|
||||||
|
* <code>AbstractSecurityInterceptor</code> at the exact time the secure
|
||||||
|
* object should have its processing continued. The exact way processing is
|
||||||
|
* continued is specific to the type of secure object. For example, it may
|
||||||
|
* involve proceeding with a method invocation, servicing a request, or
|
||||||
|
* continuing a filter chain.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* The result from processing the secure object should be returned to the
|
||||||
|
* <code>AbstractSecurityInterceptor</code>, which in turn will ultimately
|
||||||
|
* return it to the calling class.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public interface SecurityInterceptorCallback {
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Continues to process the secured object.
|
||||||
|
*
|
||||||
|
* @return the result (if any) from calling the secured object
|
||||||
|
*/
|
||||||
|
public Object proceedWithObject(Object object) throws Throwable;
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/* 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.method;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract implementation of <Code>MethodDefinitionSource</code>.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public abstract class AbstractMethodDefinitionSource
|
||||||
|
implements MethodDefinitionSource {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AbstractMethodDefinitionSource.class);
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public ConfigAttributeDefinition getAttributes(Object object)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
if ((object == null) || !this.supports(object.getClass())) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Object must be a MethodInvocation");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.lookupAttributes((MethodInvocation) object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supports(Class clazz) {
|
||||||
|
if (MethodInvocation.class.isAssignableFrom(clazz)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the actual lookup of the relevant
|
||||||
|
* <code>ConfigAttributeDefinition</code> for the specified
|
||||||
|
* <code>MethodInvocation</code>.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Provided so subclasses need only to provide one basic method to properly
|
||||||
|
* interface with the <code>MethodDefinitionSource</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return the <code>ConfigAttributeDefinition</code> that applies to the
|
||||||
|
* specified <code>MethodInvocation</code>
|
||||||
|
*/
|
||||||
|
protected abstract ConfigAttributeDefinition lookupAttributes(
|
||||||
|
MethodInvocation mi);
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
/* 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.method;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.ConfigAttribute;
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
|
import org.springframework.metadata.Attributes;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a {@link ConfigAttributeDefinition} for each method signature defined
|
||||||
|
* by Commons Attributes.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* This class will only detect those attributes which are defined for:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>
|
||||||
|
* The class-wide attributes defined for the intercepted class.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* The class-wide attributes defined for interfaces explicitly implemented by
|
||||||
|
* the intercepted class.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* The method-specific attributes defined for the intercepted method of the
|
||||||
|
* intercepted class.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* The method-specific attributes defined by any explicitly implemented
|
||||||
|
* interface if that interface contains a method signature matching that of
|
||||||
|
* the intercepted method.
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Note that attributes defined against parent classes (either for their
|
||||||
|
* methods or interfaces) are not detected. The attributes must be defined
|
||||||
|
* against an explicit method or interface on the intercepted class.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Attributes detected that do not implement {@link ConfigAttribute} will be
|
||||||
|
* ignored.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Cameron Braid
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class MethodDefinitionAttributes extends AbstractMethodDefinitionSource {
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private Attributes attributes;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void setAttributes(Attributes attributes) {
|
||||||
|
this.attributes = attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator getConfigAttributeDefinitions() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ConfigAttributeDefinition lookupAttributes(
|
||||||
|
MethodInvocation invocation) {
|
||||||
|
ConfigAttributeDefinition definition = new ConfigAttributeDefinition();
|
||||||
|
|
||||||
|
Class interceptedClass = invocation.getMethod().getDeclaringClass();
|
||||||
|
|
||||||
|
// add the class level attributes for the implementing class
|
||||||
|
addClassAttributes(definition, interceptedClass);
|
||||||
|
|
||||||
|
// add the class level attributes for the implemented interfaces
|
||||||
|
addClassAttributes(definition, interceptedClass.getInterfaces());
|
||||||
|
|
||||||
|
// add the method level attributes for the implemented method
|
||||||
|
addMethodAttributes(definition, invocation.getMethod());
|
||||||
|
|
||||||
|
// add the method level attributes for the implemented intreface methods
|
||||||
|
addInterfaceMethodAttributes(definition, invocation.getMethod());
|
||||||
|
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void add(ConfigAttributeDefinition definition, Collection attribs) {
|
||||||
|
for (Iterator iter = attribs.iterator(); iter.hasNext();) {
|
||||||
|
Object o = (Object) iter.next();
|
||||||
|
|
||||||
|
if (o instanceof ConfigAttribute) {
|
||||||
|
definition.addConfigAttribute((ConfigAttribute) o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addClassAttributes(ConfigAttributeDefinition definition,
|
||||||
|
Class clazz) {
|
||||||
|
addClassAttributes(definition, new Class[] {clazz});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addClassAttributes(ConfigAttributeDefinition definition,
|
||||||
|
Class[] clazz) {
|
||||||
|
for (int i = 0; i < clazz.length; i++) {
|
||||||
|
Collection classAttributes = attributes.getAttributes(clazz[i]);
|
||||||
|
|
||||||
|
if (classAttributes != null) {
|
||||||
|
add(definition, classAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addInterfaceMethodAttributes(
|
||||||
|
ConfigAttributeDefinition definition, Method method) {
|
||||||
|
Class[] interfaces = method.getDeclaringClass().getInterfaces();
|
||||||
|
|
||||||
|
for (int i = 0; i < interfaces.length; i++) {
|
||||||
|
Class clazz = interfaces[i];
|
||||||
|
|
||||||
|
try {
|
||||||
|
Method m = clazz.getDeclaredMethod(method.getName(),
|
||||||
|
method.getParameterTypes());
|
||||||
|
addMethodAttributes(definition, m);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// this won't happen since we are getting a method from an interface that
|
||||||
|
// the declaring class implements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMethodAttributes(ConfigAttributeDefinition definition,
|
||||||
|
Method method) {
|
||||||
|
// add the method level attributes
|
||||||
|
Collection methodAttributes = attributes.getAttributes(method);
|
||||||
|
|
||||||
|
if (methodAttributes != null) {
|
||||||
|
add(definition, methodAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
/* 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.method;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a {@link ConfigAttributeDefinition} for each method signature defined
|
||||||
|
* in a bean context.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(MethodDefinitionMap.class);
|
||||||
|
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
/** Map from Method to ApplicationDefinition */
|
||||||
|
protected Map methodMap = new HashMap();
|
||||||
|
|
||||||
|
/** Map from Method to name pattern used for registration */
|
||||||
|
private Map nameMap = new HashMap();
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public Iterator getConfigAttributeDefinitions() {
|
||||||
|
return methodMap.values().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMethodMapSize() {
|
||||||
|
return this.methodMap.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add configuration attributes for a secure method. Method names can end
|
||||||
|
* or start with <code>*</code> for matching multiple methods.
|
||||||
|
*
|
||||||
|
* @param method the method to be secured
|
||||||
|
* @param attr required authorities associated with the method
|
||||||
|
*/
|
||||||
|
public void addSecureMethod(Method method, ConfigAttributeDefinition attr) {
|
||||||
|
logger.info("Adding secure method [" + method + "] with attributes ["
|
||||||
|
+ attr + "]");
|
||||||
|
this.methodMap.put(method, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add configuration attributes for a secure method. Method names can end
|
||||||
|
* or start with <code>*</code> for matching multiple methods.
|
||||||
|
*
|
||||||
|
* @param name class and method name, separated by a dot
|
||||||
|
* @param attr required authorities associated with the method
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException DOCUMENT ME!
|
||||||
|
*/
|
||||||
|
public void addSecureMethod(String name, ConfigAttributeDefinition attr) {
|
||||||
|
int lastDotIndex = name.lastIndexOf(".");
|
||||||
|
|
||||||
|
if (lastDotIndex == -1) {
|
||||||
|
throw new IllegalArgumentException("'" + name
|
||||||
|
+ "' is not a valid method name: format is FQN.methodName");
|
||||||
|
}
|
||||||
|
|
||||||
|
String className = name.substring(0, lastDotIndex);
|
||||||
|
String methodName = name.substring(lastDotIndex + 1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class clazz = Class.forName(className, true,
|
||||||
|
Thread.currentThread().getContextClassLoader());
|
||||||
|
addSecureMethod(clazz, methodName, attr);
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
throw new IllegalArgumentException("Class '" + className
|
||||||
|
+ "' not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add configuration attributes for a secure method. Method names can end
|
||||||
|
* or start with <code>*</code> for matching multiple methods.
|
||||||
|
*
|
||||||
|
* @param clazz target interface or class
|
||||||
|
* @param mappedName mapped method name
|
||||||
|
* @param attr required authorities associated with the method
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException DOCUMENT ME!
|
||||||
|
*/
|
||||||
|
public void addSecureMethod(Class clazz, String mappedName,
|
||||||
|
ConfigAttributeDefinition attr) {
|
||||||
|
String name = clazz.getName() + '.' + mappedName;
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Adding secure method [" + name
|
||||||
|
+ "] with attributes [" + attr + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
Method[] methods = clazz.getDeclaredMethods();
|
||||||
|
List matchingMethods = new ArrayList();
|
||||||
|
|
||||||
|
for (int i = 0; i < methods.length; i++) {
|
||||||
|
if (methods[i].getName().equals(mappedName)
|
||||||
|
|| isMatch(methods[i].getName(), mappedName)) {
|
||||||
|
matchingMethods.add(methods[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchingMethods.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Couldn't find method '"
|
||||||
|
+ mappedName + "' on " + clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
// register all matching methods
|
||||||
|
for (Iterator it = matchingMethods.iterator(); it.hasNext();) {
|
||||||
|
Method method = (Method) it.next();
|
||||||
|
String regMethodName = (String) this.nameMap.get(method);
|
||||||
|
|
||||||
|
if ((regMethodName == null)
|
||||||
|
|| (!regMethodName.equals(name)
|
||||||
|
&& (regMethodName.length() <= name.length()))) {
|
||||||
|
// no already registered method name, or more specific
|
||||||
|
// method name specification now -> (re-)register method
|
||||||
|
if (regMethodName != null) {
|
||||||
|
logger.debug("Replacing attributes for secure method ["
|
||||||
|
+ method + "]: current name [" + name
|
||||||
|
+ "] is more specific than [" + regMethodName + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.nameMap.put(method, name);
|
||||||
|
addSecureMethod(method, attr);
|
||||||
|
} else {
|
||||||
|
logger.debug("Keeping attributes for secure method [" + method
|
||||||
|
+ "]: current name [" + name
|
||||||
|
+ "] is not more specific than [" + regMethodName + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ConfigAttributeDefinition lookupAttributes(MethodInvocation mi) {
|
||||||
|
return (ConfigAttributeDefinition) this.methodMap.get(mi.getMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return if the given method name matches the mapped name. The default
|
||||||
|
* implementation checks for "xxx" and "xxx" matches.
|
||||||
|
*
|
||||||
|
* @param methodName the method name of the class
|
||||||
|
* @param mappedName the name in the descriptor
|
||||||
|
*
|
||||||
|
* @return if the names match
|
||||||
|
*/
|
||||||
|
private boolean isMatch(String methodName, String mappedName) {
|
||||||
|
return (mappedName.endsWith("*")
|
||||||
|
&& methodName.startsWith(mappedName.substring(0, mappedName.length()
|
||||||
|
- 1)))
|
||||||
|
|| (mappedName.startsWith("*")
|
||||||
|
&& methodName.endsWith(mappedName.substring(1, mappedName.length())));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/* 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.method;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.intercept.ObjectDefinitionSource;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker interface for <code>ObjectDefinitionSource</code> implementations
|
||||||
|
* that are designed to perform lookups keyed on
|
||||||
|
* <code>MethodInvocation</code>s.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public interface MethodDefinitionSource extends ObjectDefinitionSource {}
|
@ -0,0 +1,82 @@
|
|||||||
|
/* 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.method;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeEditor;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.beans.propertyeditors.PropertiesEditor;
|
||||||
|
|
||||||
|
import java.beans.PropertyEditorSupport;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property editor to assist with the setup of a {@link
|
||||||
|
* MethodDefinitionSource}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The class creates and populates a {@link MethodDefinitionMap}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class MethodDefinitionSourceEditor extends PropertyEditorSupport {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(MethodDefinitionSourceEditor.class);
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void setAsText(String s) throws IllegalArgumentException {
|
||||||
|
MethodDefinitionMap source = new MethodDefinitionMap();
|
||||||
|
|
||||||
|
if ((s == null) || "".equals(s)) {
|
||||||
|
// Leave value in property editor null
|
||||||
|
} else {
|
||||||
|
// Use properties editor to tokenize the string
|
||||||
|
PropertiesEditor propertiesEditor = new PropertiesEditor();
|
||||||
|
propertiesEditor.setAsText(s);
|
||||||
|
|
||||||
|
Properties props = (Properties) propertiesEditor.getValue();
|
||||||
|
|
||||||
|
// Now we have properties, process each one individually
|
||||||
|
ConfigAttributeEditor configAttribEd = new ConfigAttributeEditor();
|
||||||
|
|
||||||
|
for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
|
||||||
|
String name = (String) iter.next();
|
||||||
|
String value = props.getProperty(name);
|
||||||
|
|
||||||
|
// Convert value to series of security configuration attributes
|
||||||
|
configAttribEd.setAsText(value);
|
||||||
|
|
||||||
|
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) configAttribEd
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
// Register name and attribute
|
||||||
|
source.addSecureMethod(name, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(source);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/* 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.method;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.intercept.AbstractSecurityInterceptor;
|
||||||
|
import net.sf.acegisecurity.intercept.ObjectDefinitionSource;
|
||||||
|
import net.sf.acegisecurity.intercept.SecurityInterceptorCallback;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides security interception of method invocations.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The <code>ObjectDefinitionSource</code> required by this security
|
||||||
|
* interceptor is of type {@link MethodDefinitionSource}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class MethodSecurityInterceptor extends AbstractSecurityInterceptor
|
||||||
|
implements MethodInterceptor, SecurityInterceptorCallback {
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private MethodDefinitionSource objectDefinitionSource;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void setObjectDefinitionSource(MethodDefinitionSource newSource) {
|
||||||
|
this.objectDefinitionSource = newSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodDefinitionSource getObjectDefinitionSource() {
|
||||||
|
return this.objectDefinitionSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
super.afterPropertiesSet();
|
||||||
|
|
||||||
|
if (!this.getAccessDecisionManager().supports(MethodInvocation.class)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"AccessDecisionManager does not support MethodInvocation");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.getRunAsManager().supports(MethodInvocation.class)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"RunAsManager does not support MethodInvocation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should be used to enforce security on a
|
||||||
|
* <code>MethodInvocation</code>.
|
||||||
|
*
|
||||||
|
* @param mi The method being invoked which requires a security decision
|
||||||
|
*
|
||||||
|
* @return The returned value from the method invocation
|
||||||
|
*
|
||||||
|
* @throws Throwable if any error occurs
|
||||||
|
*/
|
||||||
|
public Object invoke(MethodInvocation mi) throws Throwable {
|
||||||
|
return super.interceptor(mi, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectDefinitionSource obtainObjectDefinitionSource() {
|
||||||
|
return this.objectDefinitionSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object proceedWithObject(Object object) throws Throwable {
|
||||||
|
return ((MethodInvocation) object).proceed();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Enforces security for <code>MethodInvocation</code>s, such as via
|
||||||
|
Spring AOP.
|
||||||
|
</body>
|
||||||
|
</html>
|
31
core/src/main/java/org/acegisecurity/intercept/package.html
Normal file
31
core/src/main/java/org/acegisecurity/intercept/package.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Actually enforces the security and ties the whole security system together.
|
||||||
|
<P>
|
||||||
|
A <i>secure object</i> is a term frequently used throughout the security
|
||||||
|
system. It does <b>not</b> refer to a business object that is being
|
||||||
|
secured, but instead refers to some infrastructure object that can have
|
||||||
|
security facilities provided for it by the Acegi Security System for
|
||||||
|
Spring. For example, one secure object would be
|
||||||
|
<code>MethodInvocation</code>, whilst another would be HTTP {@link
|
||||||
|
net.sf.acegisecurity.intercept.web.FilterInvocation}. Note these are
|
||||||
|
infrastructure objects and their design allows them to represent a large
|
||||||
|
variety of actual resources that might need to be secured, such as business
|
||||||
|
objects or HTTP request URLs.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<P>Each secure object typically has its
|
||||||
|
own <code>net.sf.acegisecurity.intercept</code> package.
|
||||||
|
Each package usually includes a concrete security interceptor (which
|
||||||
|
subclasses {@link net.sf.acegisecurity.intercept.AbstractSecurityInterceptor},
|
||||||
|
an appropriate {@link net.sf.acegisecurity.intercept.ObjectDefinitionSource}
|
||||||
|
for the type of resources the secure object represents, and a property editor
|
||||||
|
to populate the <code>ObjectDefinitionSource</code>.
|
||||||
|
|
||||||
|
<P>It is simple to create new secure object types, given the
|
||||||
|
<code>AbstractSecurityInterceptor</code> provides the majority of the logic
|
||||||
|
and other specialised packages provide the authentication, authorization,
|
||||||
|
run-as replacement management and <code>ContextHolder</code> population.
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -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.web;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract implementation of <Code>FilterInvocationDefinitionSource</code>.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public abstract class AbstractFilterInvocationDefinitionSource
|
||||||
|
implements FilterInvocationDefinitionSource {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AbstractFilterInvocationDefinitionSource.class);
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public ConfigAttributeDefinition getAttributes(Object object)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
if ((object == null) || !this.supports(object.getClass())) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Object must be a FilterInvocation");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.lookupAttributes((FilterInvocation) object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supports(Class clazz) {
|
||||||
|
if (FilterInvocation.class.isAssignableFrom(clazz)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the actual lookup of the relevant
|
||||||
|
* <code>ConfigAttributeDefinition</code> for the specified
|
||||||
|
* <code>FilterInvocation</code>.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Provided so subclasses need only to provide one basic method to properly
|
||||||
|
* interface with the <code>FilterInvocationDefinitionSource</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return the <code>ConfigAttributeDefinition</code> that applies to the
|
||||||
|
* specified <code>FilterInvocation</code>
|
||||||
|
*/
|
||||||
|
protected abstract ConfigAttributeDefinition lookupAttributes(
|
||||||
|
FilterInvocation filterInvocation);
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
/* 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.web;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds objects associated with a HTTP filter.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Guarantees the request and response are instances of
|
||||||
|
* <code>HttpServletRequest</code> and <code>HttpServletResponse</code>, and
|
||||||
|
* that there are no <code>null</code> objects.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Required so that security system classes can obtain access to the filter
|
||||||
|
* environment, as well as the request and response.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class FilterInvocation {
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private FilterChain chain;
|
||||||
|
private ServletRequest request;
|
||||||
|
private ServletResponse response;
|
||||||
|
|
||||||
|
//~ Constructors ===========================================================
|
||||||
|
|
||||||
|
public FilterInvocation(ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain chain) {
|
||||||
|
if ((request == null) || (response == null) || (chain == null)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Cannot pass null values to constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(request instanceof HttpServletRequest)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Can only process HttpServletRequest");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(response instanceof HttpServletResponse)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Can only process HttpServletResponse");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.request = request;
|
||||||
|
this.response = response;
|
||||||
|
this.chain = chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FilterInvocation() {
|
||||||
|
throw new IllegalArgumentException("Cannot use default constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public FilterChain getChain() {
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpServletRequest getHttpRequest() {
|
||||||
|
return (HttpServletRequest) request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpServletResponse getHttpResponse() {
|
||||||
|
return (HttpServletResponse) response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServletRequest getRequest() {
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRequestUrl() {
|
||||||
|
return getHttpRequest().getServletPath()
|
||||||
|
+ ((getHttpRequest().getQueryString() == null) ? ""
|
||||||
|
: ("?"
|
||||||
|
+ getHttpRequest().getQueryString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServletResponse getResponse() {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "FilterInvocation: URL: " + getRequestUrl();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,180 @@
|
|||||||
|
/* 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.web;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.apache.oro.text.regex.MalformedPatternException;
|
||||||
|
import org.apache.oro.text.regex.Pattern;
|
||||||
|
import org.apache.oro.text.regex.PatternMatcher;
|
||||||
|
import org.apache.oro.text.regex.Perl5Compiler;
|
||||||
|
import org.apache.oro.text.regex.Perl5Matcher;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maintains a <Code>List</code> of <code>ConfigAttributeDefinition</code>s
|
||||||
|
* associated with different HTTP request URL patterns.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Regular expressions are used to match a HTTP request URL against a
|
||||||
|
* <code>ConfigAttributeDefinition</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The order of registering the regular expressions using the {@link
|
||||||
|
* #addSecureUrl(String, ConfigAttributeDefinition)} is very important. The
|
||||||
|
* system will identify the <B>first</B> matching regular expression for a
|
||||||
|
* given HTTP URL. It will not proceed to evaluate later regular expressions
|
||||||
|
* if a match has already been found. Accordingly, the most specific regular
|
||||||
|
* expressions should be registered first, with the most general regular
|
||||||
|
* expressions registered last.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* If no registered regular expressions match the HTTP URL, <code>null</code>
|
||||||
|
* is returned.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class FilterInvocationDefinitionMap
|
||||||
|
extends AbstractFilterInvocationDefinitionSource {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(FilterInvocationDefinitionMap.class);
|
||||||
|
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private List requestMap = new Vector();
|
||||||
|
private boolean convertUrlToLowercaseBeforeComparison = false;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public Iterator getConfigAttributeDefinitions() {
|
||||||
|
Set set = new HashSet();
|
||||||
|
Iterator iter = requestMap.iterator();
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
EntryHolder entryHolder = (EntryHolder) iter.next();
|
||||||
|
set.add(entryHolder.getConfigAttributeDefinition());
|
||||||
|
}
|
||||||
|
|
||||||
|
return set.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConvertUrlToLowercaseBeforeComparison(
|
||||||
|
boolean convertUrlToLowercaseBeforeComparison) {
|
||||||
|
this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConvertUrlToLowercaseBeforeComparison() {
|
||||||
|
return convertUrlToLowercaseBeforeComparison;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMapSize() {
|
||||||
|
return this.requestMap.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSecureUrl(String perl5RegExp, ConfigAttributeDefinition attr) {
|
||||||
|
Pattern compiledPattern;
|
||||||
|
Perl5Compiler compiler = new Perl5Compiler();
|
||||||
|
|
||||||
|
try {
|
||||||
|
compiledPattern = compiler.compile(perl5RegExp,
|
||||||
|
Perl5Compiler.READ_ONLY_MASK);
|
||||||
|
} catch (MalformedPatternException mpe) {
|
||||||
|
throw new IllegalArgumentException("Malformed regular expression: "
|
||||||
|
+ perl5RegExp);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestMap.add(new EntryHolder(compiledPattern, attr));
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Added regular expression: "
|
||||||
|
+ compiledPattern.getPattern().toString() + "; attributes: "
|
||||||
|
+ attr.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ConfigAttributeDefinition lookupAttributes(
|
||||||
|
FilterInvocation filterInvocation) {
|
||||||
|
PatternMatcher matcher = new Perl5Matcher();
|
||||||
|
|
||||||
|
Iterator iter = requestMap.iterator();
|
||||||
|
|
||||||
|
String url = filterInvocation.getRequestUrl();
|
||||||
|
|
||||||
|
if (convertUrlToLowercaseBeforeComparison) {
|
||||||
|
url = url.toLowerCase();
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Converted URL to lowercase, from: '"
|
||||||
|
+ filterInvocation.getRequest() + "'; to: '" + url + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
EntryHolder entryHolder = (EntryHolder) iter.next();
|
||||||
|
|
||||||
|
boolean matched = matcher.matches(url,
|
||||||
|
entryHolder.getCompiledPattern());
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Candidate is: '" + url + "'; pattern is "
|
||||||
|
+ entryHolder.getCompiledPattern().getPattern()
|
||||||
|
+ "; matched=" + matched);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
return entryHolder.getConfigAttributeDefinition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ Inner Classes ==========================================================
|
||||||
|
|
||||||
|
protected class EntryHolder {
|
||||||
|
private ConfigAttributeDefinition configAttributeDefinition;
|
||||||
|
private Pattern compiledPattern;
|
||||||
|
|
||||||
|
public EntryHolder(Pattern compiledPattern,
|
||||||
|
ConfigAttributeDefinition attr) {
|
||||||
|
this.compiledPattern = compiledPattern;
|
||||||
|
this.configAttributeDefinition = attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EntryHolder() {
|
||||||
|
throw new IllegalArgumentException("Cannot use default constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pattern getCompiledPattern() {
|
||||||
|
return compiledPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigAttributeDefinition getConfigAttributeDefinition() {
|
||||||
|
return configAttributeDefinition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/* 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.web;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.intercept.ObjectDefinitionSource;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker interface for <code>ObjectDefinitionSource</code> implementations
|
||||||
|
* that are designed to perform lookups keyed on {@link FilterInvocation}s.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public interface FilterInvocationDefinitionSource extends ObjectDefinitionSource {}
|
@ -0,0 +1,120 @@
|
|||||||
|
/* 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.web;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||||
|
import net.sf.acegisecurity.ConfigAttributeEditor;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.beans.PropertyEditorSupport;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property editor to assist with the setup of {@link
|
||||||
|
* FilterInvocationDefinitionSource}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The class creates and populates a {@link FilterInvocationDefinitionMap}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class FilterInvocationDefinitionSourceEditor
|
||||||
|
extends PropertyEditorSupport {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(FilterInvocationDefinitionSourceEditor.class);
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void setAsText(String s) throws IllegalArgumentException {
|
||||||
|
FilterInvocationDefinitionMap source = new FilterInvocationDefinitionMap();
|
||||||
|
|
||||||
|
if ((s == null) || "".equals(s)) {
|
||||||
|
// Leave value in property editor null
|
||||||
|
} else {
|
||||||
|
BufferedReader br = new BufferedReader(new StringReader(s));
|
||||||
|
int counter = 0;
|
||||||
|
String line;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
try {
|
||||||
|
line = br.readLine();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new IllegalArgumentException(ioe.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
line = line.trim();
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Line " + counter + ": " + line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith("//")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.equals("CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON")) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Line " + counter
|
||||||
|
+ ": Instructing mapper to convert URLs to lowercase before comparison");
|
||||||
|
}
|
||||||
|
|
||||||
|
source.setConvertUrlToLowercaseBeforeComparison(true);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.lastIndexOf('=') == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tokenize the line into its name/value tokens
|
||||||
|
String[] nameValue = StringUtils.delimitedListToStringArray(line,
|
||||||
|
"=");
|
||||||
|
String name = nameValue[0];
|
||||||
|
String value = nameValue[1];
|
||||||
|
|
||||||
|
// Convert value to series of security configuration attributes
|
||||||
|
ConfigAttributeEditor configAttribEd = new ConfigAttributeEditor();
|
||||||
|
configAttribEd.setAsText(value);
|
||||||
|
|
||||||
|
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) configAttribEd
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
// Register the regular expression and its attribute
|
||||||
|
source.addSecureUrl(name, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(source);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
/* 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.web;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.intercept.AbstractSecurityInterceptor;
|
||||||
|
import net.sf.acegisecurity.intercept.ObjectDefinitionSource;
|
||||||
|
import net.sf.acegisecurity.intercept.SecurityInterceptorCallback;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs security handling of HTTP resources via a filter implementation.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* End users should <B>only</B> use this class to configure their HTTP security
|
||||||
|
* configuration in an application context. They should <B>not</B> attempt to
|
||||||
|
* invoke the <code>FilterSecurityInterceptor</code> except as a standard bean
|
||||||
|
* registration in an application context. At runtime, this class will provide
|
||||||
|
* services to web applications via the {@link SecurityEnforcementFilter}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The <code>ObjectDefinitionSource</code> required by this security
|
||||||
|
* interceptor is of type {@link FilterInvocationDefinitionSource}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor
|
||||||
|
implements SecurityInterceptorCallback {
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private FilterInvocationDefinitionSource objectDefinitionSource;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void setObjectDefinitionSource(
|
||||||
|
FilterInvocationDefinitionSource newSource) {
|
||||||
|
this.objectDefinitionSource = newSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilterInvocationDefinitionSource getObjectDefinitionSource() {
|
||||||
|
return this.objectDefinitionSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
super.afterPropertiesSet();
|
||||||
|
|
||||||
|
if (!this.getAccessDecisionManager().supports(FilterInvocation.class)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"AccessDecisionManager does not support FilterInvocation");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.getRunAsManager().supports(FilterInvocation.class)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"RunAsManager does not support FilterInvocation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invoke(FilterInvocation fi) throws Throwable {
|
||||||
|
super.interceptor(fi, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectDefinitionSource obtainObjectDefinitionSource() {
|
||||||
|
return this.objectDefinitionSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object proceedWithObject(Object object) throws Throwable {
|
||||||
|
FilterInvocation fi = (FilterInvocation) object;
|
||||||
|
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,178 @@
|
|||||||
|
/* 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.web;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.AccessDeniedException;
|
||||||
|
import net.sf.acegisecurity.AuthenticationException;
|
||||||
|
import net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps requests to the {@link FilterSecurityInterceptor}.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* This filter is necessary because it provides an application context
|
||||||
|
* environment for the <code>FilterSecurityInterceptor</code> instance.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* If a {@link AuthenticationException} is detected, the filter will redirect
|
||||||
|
* to the <code>loginFormUrl</code>. This allows common handling of
|
||||||
|
* authentication failures originating from any subclass of {@link
|
||||||
|
* net.sf.acegisecurity.intercept.AbstractSecurityInterceptor}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If an {@link AccessDeniedException} is detected, the filter will response
|
||||||
|
* with a <code>HttpServletResponse.SC_FORBIDDEN</code> (403 error). Again,
|
||||||
|
* this allows common access denied handling irrespective of the originating
|
||||||
|
* security interceptor.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* To use this filter, it is necessary to specify the following filter
|
||||||
|
* initialization parameters:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>
|
||||||
|
* <code>appContextLocation</code> indicates the path to an application context
|
||||||
|
* that contains the <code>FilterSecurityInterceptor</code>.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* <code>loginFormUrl</code> indicates the URL that should be used for
|
||||||
|
* redirection if an <code>AuthenticationException</code> is detected.
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class SecurityEnforcementFilter implements Filter {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(SecurityEnforcementFilter.class);
|
||||||
|
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
protected ClassPathXmlApplicationContext ctx;
|
||||||
|
protected FilterSecurityInterceptor securityInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL that should be used for redirection if an
|
||||||
|
* <code>AuthenticationException</code> is detected.
|
||||||
|
*/
|
||||||
|
protected String loginFormUrl;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain chain) throws IOException, ServletException {
|
||||||
|
if (!(request instanceof HttpServletRequest)) {
|
||||||
|
throw new ServletException("HttpServletRequest required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(response instanceof HttpServletResponse)) {
|
||||||
|
throw new ServletException("HttpServletResponse required");
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterInvocation fi = new FilterInvocation(request, response, chain);
|
||||||
|
|
||||||
|
try {
|
||||||
|
securityInterceptor.invoke(fi);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Chain processed normally");
|
||||||
|
}
|
||||||
|
} catch (AuthenticationException authentication) {
|
||||||
|
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"Authentication failed - adding target URL to Session: "
|
||||||
|
+ fi.getRequestUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
((HttpServletRequest) request).getSession().setAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY,
|
||||||
|
fi.getRequestUrl());
|
||||||
|
((HttpServletResponse) response).sendRedirect(((HttpServletRequest) request)
|
||||||
|
.getContextPath() + loginFormUrl);
|
||||||
|
} catch (AccessDeniedException accessDenied) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"Access is denied - sending back forbidden response");
|
||||||
|
}
|
||||||
|
|
||||||
|
((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN); // 403
|
||||||
|
} catch (Throwable otherException) {
|
||||||
|
throw new ServletException(otherException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
String appContextLocation = filterConfig.getInitParameter(
|
||||||
|
"appContextLocation");
|
||||||
|
|
||||||
|
if ((appContextLocation == null) || "".equals(appContextLocation)) {
|
||||||
|
throw new ServletException("appContextLocation must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
|
||||||
|
throw new ServletException("Cannot locate " + appContextLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
loginFormUrl = filterConfig.getInitParameter("loginFormUrl");
|
||||||
|
|
||||||
|
if ((loginFormUrl == null) || "".equals(loginFormUrl)) {
|
||||||
|
throw new ServletException("loginFormUrl must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = new ClassPathXmlApplicationContext(appContextLocation);
|
||||||
|
|
||||||
|
Map beans = ctx.getBeansOfType(FilterSecurityInterceptor.class, true,
|
||||||
|
true);
|
||||||
|
|
||||||
|
if (beans.size() == 0) {
|
||||||
|
throw new ServletException(
|
||||||
|
"Bean context must contain at least one bean of type FilterSecurityInterceptor");
|
||||||
|
}
|
||||||
|
|
||||||
|
String beanName = (String) beans.keySet().iterator().next();
|
||||||
|
securityInterceptor = (FilterSecurityInterceptor) beans.get(beanName);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Enforces security for HTTP requests, typically by the URL requested.
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,161 @@
|
|||||||
|
/* 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.ui;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.context.Context;
|
||||||
|
import net.sf.acegisecurity.context.ContextHolder;
|
||||||
|
import net.sf.acegisecurity.context.SecureContext;
|
||||||
|
import net.sf.acegisecurity.context.SecureContextImpl;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically populates a {@link net.sf.acegisecurity.context.SecureContext}
|
||||||
|
* from a subclass-provided <code>Authentication</code> object.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The container hosting the Acegi Security System for Spring secured
|
||||||
|
* application is expected to expose an {@link Authentication} object in a
|
||||||
|
* well-known location. The <code>Authentication</code> object will have been
|
||||||
|
* created by the Acegi Security System for Spring and placed into the
|
||||||
|
* well-known location via approaches such as container adapters or container
|
||||||
|
* sessions.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Once the <code>Authentication</code> object has been extracted from the
|
||||||
|
* well-known location, the <code>AbstractIntegrationFilter</code> handles
|
||||||
|
* putting it into the {@link ContextHolder}. It then removes it once the
|
||||||
|
* filter chain has completed.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This filter will not abort if an <code>Authentication</code> object cannot
|
||||||
|
* be obtained from the well-known location. It will simply continue the
|
||||||
|
* filter chain as normal.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public abstract class AbstractIntegrationFilter implements Filter {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
protected static final Log logger = LogFactory.getLog(AbstractIntegrationFilter.class);
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void destroy() {}
|
||||||
|
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain chain) throws IOException, ServletException {
|
||||||
|
// Populate authentication information
|
||||||
|
Object extracted = this.extractFromContainer(request);
|
||||||
|
|
||||||
|
if (extracted instanceof Authentication) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"Authentication added to ContextHolder from container");
|
||||||
|
}
|
||||||
|
|
||||||
|
Authentication auth = (Authentication) extracted;
|
||||||
|
|
||||||
|
// Get or create existing SecureContext
|
||||||
|
SecureContext secureContext = null;
|
||||||
|
|
||||||
|
if ((ContextHolder.getContext() == null)
|
||||||
|
|| !(ContextHolder.getContext() instanceof SecureContext)) {
|
||||||
|
secureContext = new SecureContextImpl();
|
||||||
|
} else {
|
||||||
|
secureContext = (SecureContext) ContextHolder.getContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Authentication to SecureContext, and save
|
||||||
|
secureContext.setAuthentication(auth);
|
||||||
|
ContextHolder.setContext((Context) secureContext);
|
||||||
|
} else {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"Authentication not added to ContextHolder (could not extract an authentication object from the container which is an instance of Authentication)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proceed with chain
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
|
||||||
|
// Remove authentication information
|
||||||
|
if ((ContextHolder.getContext() != null)
|
||||||
|
&& ContextHolder.getContext() instanceof SecureContext) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Removing Authentication from ContextHolder");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get context holder and remove authentication information
|
||||||
|
SecureContext secureContext = (SecureContext) ContextHolder
|
||||||
|
.getContext();
|
||||||
|
secureContext.setAuthentication(null);
|
||||||
|
ContextHolder.setContext((Context) secureContext);
|
||||||
|
} else {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"ContextHolder does not contain any authentication information");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses must override this method to provide the <code>Object</code>
|
||||||
|
* that contains the <code>Authentication</code> interface.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For convenience we have allowed any <code>Object</code> to be returned
|
||||||
|
* by subclasses, as the abstract class will ensure class casting safety
|
||||||
|
* and ignore objects that do not implement <code>Authentication</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If no <code>Authentication</code> object is available, subclasses should
|
||||||
|
* return <code>null</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If the subclass can locate multiple authentication objects, they should
|
||||||
|
* return the object that was created by the Acegi Security System for
|
||||||
|
* Spring (ie the object that implements <code>Authentication</code>).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param request the request, which may be of use in extracting the
|
||||||
|
* authentication object
|
||||||
|
*
|
||||||
|
* @return <code>null</code> or an object that implements
|
||||||
|
* <code>Authentication</code>
|
||||||
|
*/
|
||||||
|
public abstract Object extractFromContainer(ServletRequest request);
|
||||||
|
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
/* 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.ui;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.adapters.HttpRequestIntegrationFilter;
|
||||||
|
import net.sf.acegisecurity.adapters.jboss.JbossIntegrationFilter;
|
||||||
|
import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter;
|
||||||
|
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects the container and delegates to the appropriate {@link
|
||||||
|
* AbstractIntegrationFilter}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This eases the creation of portable, secure applications, as the
|
||||||
|
* <code>web.xml</code> will not need to refer to a specific integration
|
||||||
|
* filter.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* The filter automatically delegates to {@link HttpRequestIntegrationFilter}
|
||||||
|
* if any <code>Authentication</code> object is detected in the
|
||||||
|
* <code>ServletRequest</code>. Failing this, it will delegate to {@link
|
||||||
|
* HttpSessionIntegrationFilter} if the session object contains an
|
||||||
|
* <code>Authentication</code> object. Finally, this filter will delegate to
|
||||||
|
* {@link JbossIntegrationFilter} if the <code>ServletRequest</code> contains
|
||||||
|
* an instance of JBoss' <code>SimplePrincipal</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* If no location can be found containing the <code>Authentication</code>
|
||||||
|
* object, it will return <code>null</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*
|
||||||
|
* @see AbstractIntegrationFilter
|
||||||
|
*/
|
||||||
|
public class AutoIntegrationFilter extends AbstractIntegrationFilter {
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public Object extractFromContainer(ServletRequest request) {
|
||||||
|
if (request instanceof HttpServletRequest) {
|
||||||
|
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||||
|
|
||||||
|
if (httpRequest.getUserPrincipal() instanceof Authentication) {
|
||||||
|
return getHttpServletRequest().extractFromContainer(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getHttpSessionIntegrationFilter().extractFromContainer(request) != null) {
|
||||||
|
return getHttpSessionIntegrationFilter().extractFromContainer(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class simplePrincipalClass = Class.forName(
|
||||||
|
"org.jboss.security.SimplePrincipal");
|
||||||
|
|
||||||
|
if (null != httpRequest.getUserPrincipal()) {
|
||||||
|
if (simplePrincipalClass.isAssignableFrom(
|
||||||
|
httpRequest.getUserPrincipal().getClass())) {
|
||||||
|
return getJbossIntegrationFilter().extractFromContainer(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
// Can't be JBoss principal
|
||||||
|
// Expected, and normal - fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows test case to override the source of
|
||||||
|
* <code>HttpRequestIntegrationFilter</code>.
|
||||||
|
*
|
||||||
|
* @return the <code>HttpRequestIntegrationFilter</code> to use
|
||||||
|
*/
|
||||||
|
protected HttpRequestIntegrationFilter getHttpServletRequest() {
|
||||||
|
return new HttpRequestIntegrationFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows test case to override the source of
|
||||||
|
* <code>HttpSessionIntegrationFilter</code>.
|
||||||
|
*
|
||||||
|
* @return the <code>HttpRequestIntegrationFilter</code> to use
|
||||||
|
*/
|
||||||
|
protected HttpSessionIntegrationFilter getHttpSessionIntegrationFilter() {
|
||||||
|
return new HttpSessionIntegrationFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows test case to override the source of
|
||||||
|
* <code>JbossIntegrationFilter</code>.
|
||||||
|
*
|
||||||
|
* @return the <code>JbossIntegrationFilter</code> to use
|
||||||
|
*/
|
||||||
|
protected JbossIntegrationFilter getJbossIntegrationFilter() {
|
||||||
|
return new JbossIntegrationFilter();
|
||||||
|
}
|
||||||
|
}
|
6
core/src/main/java/org/acegisecurity/ui/package.html
Normal file
6
core/src/main/java/org/acegisecurity/ui/package.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Interfaces the system with various end-user authentication approaches, such
|
||||||
|
as container adapters and web applications.
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,263 @@
|
|||||||
|
/* 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.ui.webapp;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.AuthenticationException;
|
||||||
|
import net.sf.acegisecurity.AuthenticationManager;
|
||||||
|
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes an authentication form, putting the result into the
|
||||||
|
* <code>HttpSession</code>.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This filter is responsible for processing authentication requests. A user
|
||||||
|
* will typically authenticate once using a login form, and this filter
|
||||||
|
* processes that form. If authentication is successful, the resulting {@link
|
||||||
|
* Authentication} object will be placed into the <code>HttpSession</code>
|
||||||
|
* with the attribute defined by {@link
|
||||||
|
* HttpSessionIntegrationFilter#ACEGI_SECURITY_AUTHENTICATION_KEY}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Login forms must present two parameters to this filter: a username and
|
||||||
|
* password. The filter will process the login against the authentication
|
||||||
|
* environment that was configured from a Spring application context defined
|
||||||
|
* in the filter initialization.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* If authentication fails, the <code>AuthenticationException</code> will be
|
||||||
|
* placed into the <code>HttpSession</code> with the attribute defined by
|
||||||
|
* {@link #ACEGI_SECURITY_LAST_EXCEPTION_KEY}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* To use this filter, it is necessary to specify the following filter
|
||||||
|
* initialization parameters:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>
|
||||||
|
* <code>appContextLocation</code> indicates the path to an application context
|
||||||
|
* that contains an {@link AuthenticationManager} that should be used to
|
||||||
|
* process each authentication request.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* <code>defaultTargetUrl</code> indicates the URL that should be used for
|
||||||
|
* redirection if the <code>HttpSession</code> attribute named {@link
|
||||||
|
* #ACEGI_SECURITY_TARGET_URL_KEY} does not indicate the target URL once
|
||||||
|
* authentication is completed successfully. eg: <code>/</code>.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* <code>authenticationFailureUrl</code> indicates the URL that should be used
|
||||||
|
* for redirection if the authentication request fails. eg:
|
||||||
|
* <code>/login.jsp?login_error=1</code>.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* <code>filterProcessesUrl</code> indicates the URL that this filter will
|
||||||
|
* respond to. This parameter is optional, and defaults to
|
||||||
|
* <code>/j_acegi_security_check</code>.
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AuthenticationProcessingFilter implements Filter {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
public static final String ACEGI_SECURITY_TARGET_URL_KEY = "ACEGI_SECURITY_TARGET_URL";
|
||||||
|
public static final String ACEGI_SECURITY_FORM_USERNAME_KEY = "j_username";
|
||||||
|
public static final String ACEGI_SECURITY_FORM_PASSWORD_KEY = "j_password";
|
||||||
|
public static final String ACEGI_SECURITY_LAST_EXCEPTION_KEY = "ACEGI_SECURITY_LAST_EXCEPTION";
|
||||||
|
private static final Log logger = LogFactory.getLog(AuthenticationProcessingFilter.class);
|
||||||
|
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private AuthenticationManager authenticationManager;
|
||||||
|
private ClassPathXmlApplicationContext ctx;
|
||||||
|
|
||||||
|
/** Where to redirect the browser to if authentication fails */
|
||||||
|
private String authenticationFailureUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where to redirect the browser to if authentication is successful but
|
||||||
|
* ACEGI_SECURITY_TARGET_URL_KEY is <code>null</code>
|
||||||
|
*/
|
||||||
|
private String defaultTargetUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL destination that this filter intercepts and processes (usually
|
||||||
|
* <code>/j_acegi_security_check</code>)
|
||||||
|
*/
|
||||||
|
private String filterProcessesUrl;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain chain) throws IOException, ServletException {
|
||||||
|
if (!(request instanceof HttpServletRequest)) {
|
||||||
|
throw new ServletException("Can only process HttpServletRequest");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(response instanceof HttpServletResponse)) {
|
||||||
|
throw new ServletException("Can only process HttpServletResponse");
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||||
|
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||||
|
|
||||||
|
if (filterProcessesUrl.equals(httpRequest.getServletPath())) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Request is to process Acegi login form");
|
||||||
|
}
|
||||||
|
|
||||||
|
String username = httpRequest.getParameter(ACEGI_SECURITY_FORM_USERNAME_KEY);
|
||||||
|
String password = httpRequest.getParameter(ACEGI_SECURITY_FORM_PASSWORD_KEY);
|
||||||
|
|
||||||
|
if (username == null) {
|
||||||
|
username = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password == null) {
|
||||||
|
password = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,
|
||||||
|
password);
|
||||||
|
|
||||||
|
Authentication authResult;
|
||||||
|
|
||||||
|
try {
|
||||||
|
authResult = authenticationManager.authenticate(authRequest);
|
||||||
|
} catch (AuthenticationException failed) {
|
||||||
|
// Authentication failed
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Authentication request for user: " + username
|
||||||
|
+ " failed: " + failed.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRequest.getSession().setAttribute(ACEGI_SECURITY_LAST_EXCEPTION_KEY,
|
||||||
|
failed);
|
||||||
|
httpRequest.getSession().setAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY,
|
||||||
|
null);
|
||||||
|
httpResponse.sendRedirect(httpRequest.getContextPath()
|
||||||
|
+ authenticationFailureUrl);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authentication success
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Authentication success: " + authResult.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
httpRequest.getSession().setAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY,
|
||||||
|
authResult);
|
||||||
|
|
||||||
|
String targetUrl = (String) httpRequest.getSession().getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY);
|
||||||
|
httpRequest.getSession().setAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY,
|
||||||
|
null);
|
||||||
|
|
||||||
|
if (targetUrl == null) {
|
||||||
|
targetUrl = defaultTargetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"Redirecting to target URL from HTTP Session (or default): "
|
||||||
|
+ targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
httpResponse.sendRedirect(httpRequest.getContextPath() + targetUrl);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
String appContextLocation = filterConfig.getInitParameter(
|
||||||
|
"appContextLocation");
|
||||||
|
|
||||||
|
if ((appContextLocation == null) || "".equals(appContextLocation)) {
|
||||||
|
throw new ServletException("appContextLocation must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
|
||||||
|
throw new ServletException("Cannot locate " + appContextLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultTargetUrl = filterConfig.getInitParameter("defaultTargetUrl");
|
||||||
|
|
||||||
|
if ((defaultTargetUrl == null) || "".equals(defaultTargetUrl)) {
|
||||||
|
throw new ServletException("defaultTargetUrl must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticationFailureUrl = filterConfig.getInitParameter(
|
||||||
|
"authenticationFailureUrl");
|
||||||
|
|
||||||
|
if ((authenticationFailureUrl == null)
|
||||||
|
|| "".equals(authenticationFailureUrl)) {
|
||||||
|
throw new ServletException(
|
||||||
|
"authenticationFailureUrl must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
filterProcessesUrl = filterConfig.getInitParameter("filterProcessesUrl");
|
||||||
|
|
||||||
|
if ((filterProcessesUrl == null) || "".equals(filterProcessesUrl)) {
|
||||||
|
filterProcessesUrl = "/j_acegi_security_check";
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = new ClassPathXmlApplicationContext(appContextLocation);
|
||||||
|
|
||||||
|
Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
|
||||||
|
|
||||||
|
if (beans.size() == 0) {
|
||||||
|
throw new ServletException(
|
||||||
|
"Bean context must contain at least one bean of type AuthenticationManager");
|
||||||
|
}
|
||||||
|
|
||||||
|
String beanName = (String) beans.keySet().iterator().next();
|
||||||
|
authenticationManager = (AuthenticationManager) beans.get(beanName);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/* 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.ui.webapp;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.ui.AbstractIntegrationFilter;
|
||||||
|
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates a {@link net.sf.acegisecurity.context.SecureContext} from the
|
||||||
|
* <code>HttpSession</code>.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* The filter will inspect the <code>HttpSession</code> for an attribute with
|
||||||
|
* the name indicated by {@link #ACEGI_SECURITY_AUTHENTICATION_KEY}. If that
|
||||||
|
* attribute contains an instance of {@link Authentication}, it will be placed
|
||||||
|
* into the <code>ContextHolder</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* This filter is normally used in conjunction with {@link
|
||||||
|
* AuthenticationProcessingFilter}, which populates the
|
||||||
|
* <code>HttpSession</code> with an <code>Authentication</code> object based
|
||||||
|
* on a form login. Alternatively, users may elect to use their own approach
|
||||||
|
* for populating the <code>HttpSession</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* As with other <code>AbstractIntegrationFilter</code>s, this filter will
|
||||||
|
* ensure the <code>ContextHolder</code> is populated with the
|
||||||
|
* <code>Authentication</code> object for the duration of the HTTP request,
|
||||||
|
* and is unbound from the <code>ContextHolder</code> at the completion of the
|
||||||
|
* request.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* See {@link AbstractIntegrationFilter} for further information.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class HttpSessionIntegrationFilter extends AbstractIntegrationFilter {
|
||||||
|
//~ Static fields/initializers =============================================
|
||||||
|
|
||||||
|
public static final String ACEGI_SECURITY_AUTHENTICATION_KEY = "ACEGI_SECURITY_AUTHENTICATION";
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public Object extractFromContainer(ServletRequest request) {
|
||||||
|
if (request instanceof HttpServletRequest) {
|
||||||
|
HttpSession httpSession = ((HttpServletRequest) request).getSession();
|
||||||
|
|
||||||
|
if (httpSession != null) {
|
||||||
|
Object authObject = httpSession.getAttribute(ACEGI_SECURITY_AUTHENTICATION_KEY);
|
||||||
|
|
||||||
|
if (authObject instanceof Authentication) {
|
||||||
|
return authObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
Authenticates users via a standard web form and <code>HttpSession</code>.
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
x
Reference in New Issue
Block a user