diff --git a/.classpath b/.classpath
index 0194f48102..204d6b1551 100644
--- a/.classpath
+++ b/.classpath
@@ -28,5 +28,6 @@
+
diff --git a/changelog.txt b/changelog.txt
index b51e64f483..e589e82262 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,8 +1,12 @@
Changes in version 0.7 (2004-xx-xx)
-----------------------------------
+* Added AspectJ support (especially useful for instance-level security)
* Added MethodDefinitionSourceAdvisor for performance and autoproxying
* Added MethodDefinitionMap querying of interfaces defined by secure objects
+* Refactored MethodDefinitionSource to work with Method, not MethodInvocation
+* Refactored AbstractSecurityInterceptor to better support other AOP libraries
+* Moved MethodSecurityInterceptor to ...intercept.method.aopalliance package
* Documentation improvements
Changes in version 0.6.1 (2004-09-25)
diff --git a/core/src/main/java/org/acegisecurity/intercept/method/aspectj/AspectJCallback.java b/core/src/main/java/org/acegisecurity/intercept/method/aspectj/AspectJCallback.java
new file mode 100644
index 0000000000..cf82edcfb4
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/intercept/method/aspectj/AspectJCallback.java
@@ -0,0 +1,31 @@
+/* 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.aspectj;
+
+/**
+ * Called by the {@link AspectJSecurityInterceptor} when it wishes for the
+ * AspectJ processing to continue. Typically implemented in the
+ * around() advice as a simple return proceed();
+ * statement.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface AspectJCallback {
+ //~ Methods ================================================================
+
+ public Object proceedWithObject();
+}
diff --git a/core/src/main/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptor.java b/core/src/main/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptor.java
new file mode 100644
index 0000000000..c325de320f
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptor.java
@@ -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.method.aspectj;
+
+import net.sf.acegisecurity.intercept.AbstractSecurityInterceptor;
+import net.sf.acegisecurity.intercept.InterceptorStatusToken;
+import net.sf.acegisecurity.intercept.ObjectDefinitionSource;
+import net.sf.acegisecurity.intercept.method.MethodDefinitionSource;
+
+import org.aspectj.lang.JoinPoint;
+
+
+/**
+ * Provides security interception of AspectJ method invocations.
+ *
+ *
+ * The ObjectDefinitionSource required by this security
+ * interceptor is of type {@link MethodDefinitionSource}. This is shared with
+ * the AOP Alliance based security interceptor
+ * (MethodSecurityInterceptor), since both work with Java
+ * Methods.
+ *
+ *
+ *
+ * The secure object type is org.aspectj.lang.JointPoint, which is
+ * passed from the relevant around() advice. The
+ * around() advice also passes an anonymous implementation of
+ * {@link AspectJCallback} which contains the call for AspectJ to continue
+ * processing: return proceed();.
+ *
+ *
+ *
+ * Refer to {@link AbstractSecurityInterceptor} for details on the workflow.
+ *
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class AspectJSecurityInterceptor extends AbstractSecurityInterceptor {
+ //~ 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(JoinPoint.class)) {
+ throw new IllegalArgumentException(
+ "AccessDecisionManager does not support JointPoint");
+ }
+
+ if (!this.getRunAsManager().supports(JoinPoint.class)) {
+ throw new IllegalArgumentException(
+ "RunAsManager does not support JointPoint");
+ }
+ }
+
+ /**
+ * This method should be used to enforce security on a
+ * JoinPoint.
+ *
+ * @param jp The AspectJ joint point being invoked which requires a
+ * security decision
+ * @param advisorProceed the advice-defined anonymous class that implements
+ * AspectJCallback containing a simple return
+ * proceed(); statement
+ *
+ * @return The returned value from the method invocation
+ */
+ public Object invoke(JoinPoint jp, AspectJCallback advisorProceed) {
+ Object result;
+ InterceptorStatusToken token = super.beforeInvocation(jp);
+
+ try {
+ result = advisorProceed.proceedWithObject();
+ } finally {
+ super.afterInvocation(token);
+ }
+
+ return result;
+ }
+
+ public ObjectDefinitionSource obtainObjectDefinitionSource() {
+ return this.objectDefinitionSource;
+ }
+}
diff --git a/core/src/main/java/org/acegisecurity/intercept/method/aspectj/package.html b/core/src/main/java/org/acegisecurity/intercept/method/aspectj/package.html
new file mode 100644
index 0000000000..ea0a671118
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/intercept/method/aspectj/package.html
@@ -0,0 +1,8 @@
+
+
+Enforces security for AspectJ JointPoints, delegating secure
+object callbacks to the calling aspect.
+
+Refer to the reference guide for information on usage.
+
+
diff --git a/docs/reference/src/index.xml b/docs/reference/src/index.xml
index 4ee72eb0a9..e00c770019 100644
--- a/docs/reference/src/index.xml
+++ b/docs/reference/src/index.xml
@@ -7,7 +7,7 @@
Reference Documentation
- 0.6.1
+ 0.7
@@ -202,8 +202,8 @@
directly. For example, it would be possible to build a new secure
object to secure calls to a messaging system that does not use
MethodInvocations. Most Spring applications will
- simply use the two currently supported secure object types
- (MethodInvocation and
+ simply use the three currently supported secure object types
+ (MethodInvocation, JoinPoint and
FilterInterceptor) with complete
transparency.
@@ -214,7 +214,7 @@
Supported Secure Objects
- The Acegi Security System for Spring currently supports two
+ The Acegi Security System for Spring currently supports three
secure objects.
The first handles an AOP Alliance
@@ -224,12 +224,24 @@
standard Spring-hosted bean available as a
MethodInvocation, the bean is simply published
through a ProxyFactoryBean or
- BeanNameAutoProxyCreator. Most Spring developers
- would already be familiar with these due to their use in transactions
- and other areas of Spring.
+ BeanNameAutoProxyCreator or
+ DefaultAdvisorAutoProxyCreator. Most Spring
+ developers would already be familiar with these due to their use in
+ transactions and other areas of Spring.
- The second type is a FilterInvocation. This
- is an object included with the Acegi Security System for Spring. It is
+ The second type is an AspectJ JoinPoint.
+ AspectJ has a particular use in securing domain object instances, as
+ these are most often managed outside the Spring bean container. By
+ using AspectJ, standard constructs such as new
+ Person(); can be used and full security will be applied to
+ them by Acegi Security. The
+ AspectJSecurityInterceptor is still managed by
+ Spring, which creates the aspect singleton and wires it with the
+ appropriate authentication managers, access decision managers and so
+ on.
+
+ The third type is a FilterInvocation. This is
+ an object included with the Acegi Security System for Spring. It is
created by an included filter and simply wraps the HTTP
ServletRequest, ServletResponse
and FilterChain. The
@@ -410,9 +422,8 @@
- Call a secure object-specific
- SecurityInterceptorCallback so that the request
- execution can proceed.
+ Proceed with the request execution of the secure
+ object.
@@ -424,8 +435,8 @@
- Return any result received from the
- SecurityInterceptorCallback.
+ Return any result received from the secure object
+ execution.
@@ -441,8 +452,8 @@
object-specific security interceptors are discussed below.
-
- MethodInvocation Security Interceptor
+
+ AOP Alliance (MethodInvocation) Security Interceptor
To secure MethodInvocations, developers
simply add a properly configured
@@ -452,10 +463,15 @@
ProxyFactoryBean or
BeanNameAutoProxyCreator, as commonly used by many
other parts of Spring (refer to the sample application for examples).
- The MethodSecurityInterceptor is configured as
+ Alternatively, Acegi Security provides a
+ MethodDefinitionSourceAdvisor which may be used
+ with Spring's DefaultAdvisorAutoProxyCreator to
+ automatically chain the security interceptor in front of any beans
+ defined against the MethodSecurityInterceptor. The
+ MethodSecurityInterceptor itself is configured as
follows:
- <bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
+ <bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="validateConfigAttributes"><value>true</value></property>
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
@@ -572,6 +588,124 @@
false.
+
+ AspectJ (JoinPoint) Security Interceptor
+
+ The AspectJ security interceptor is very similar to the AOP
+ Alliance security interceptor discussed in the previous section.
+ Indeed we will only discuss the differences in this section.
+
+ The AspectJ interceptor is named
+ AspectJSecurityInterceptor. Unlike the AOP Alliance
+ security interceptor, which relies on the Spring application context
+ to weave in the security interceptor via proxying, the
+ AspectJSecurityInterceptor is weaved in via the
+ AspectJ compiler. It would not be uncommon to use both types of
+ security interceptors in the same application, with
+ AspectJSecurityInterceptor being used for domain
+ object instance security and the AOP Alliance
+ MethodSecurityInterceptor being used for services
+ layer security.
+
+ Let's first consider how the
+ AspectJSecurityInterceptor is configured in the
+ Spring application context:
+
+ <bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor">
+ <property name="validateConfigAttributes"><value>true</value></property>
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+ <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
+ <property name="runAsManager"><ref bean="runAsManager"/></property>
+ <property name="objectDefinitionSource">
+ <value>
+ net.sf.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER
+ net.sf.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER
+ </value>
+ </property>
+</bean>
+
+ As you can see, aside from the class name, the
+ AspectJSecurityInterceptor is exactly the same as
+ the AOP Alliance security interceptor. Indeed the two interceptors can
+ share the same objectDefinitionSource, as the
+ ObjectDefinitionSource works with
+ java.lang.reflect.Methods rather than an AOP
+ library-specific class. Of course, your access decisions have access
+ to the relevant AOP library-specific invocation (ie
+ MethodInvocation or JoinPoint)
+ and as such can consider a range of addition criteria when making
+ access decisions (such as method arguments).
+
+ Next you'll need to define an AspectJ aspect.
+ For example:
+
+ package net.sf.acegisecurity.samples.aspectj;
+
+import net.sf.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor;
+import net.sf.acegisecurity.intercept.method.aspectj.AspectJCallback;
+import org.springframework.beans.factory.InitializingBean;
+
+public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
+
+ private AspectJSecurityInterceptor securityInterceptor;
+
+ pointcut domainObjectInstanceExecution(): target(PersistableEntity)
+ && execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect);
+
+ Object around(): domainObjectInstanceExecution() {
+ if (this.securityInterceptor != null) {
+ AspectJCallback callback = new AspectJCallback() {
+ public Object proceedWithObject() {
+ return proceed();
+ }
+ };
+ return this.securityInterceptor.invoke(thisJoinPoint, callback);
+ } else {
+ return proceed();
+ }
+ }
+
+ public AspectJSecurityInterceptor getSecurityInterceptor() {
+ return securityInterceptor;
+ }
+
+ public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
+ this.securityInterceptor = securityInterceptor;
+ }
+
+ public void afterPropertiesSet() throws Exception {
+ if (this.securityInterceptor == null)
+ throw new IllegalArgumentException("securityInterceptor required");
+ }
+}
+
+ In the above example, the security interceptor will be applied
+ to every instance of PersistableEntity, which is an
+ abstract class not shown (you can use any other class or
+ pointcut expression you like). For those curious,
+ AspectJCallback is needed because the
+ proceed(); statement has special meaning only
+ within an around() body. The
+ AspectJSecurityInterceptor calls this anonymous
+ AspectJCallback class when it wants the target
+ object to continue.
+
+ You will need to configure Spring to load the aspect and wire it
+ with the AspectJSecurityInterceptor. A bean
+ declaration which achieves this is shown below:
+
+ <bean id="domainObjectInstanceSecurityAspect"
+ class="net.sf.acegisecurity.samples.aspectj.DomainObjectInstanceSecurityAspect"
+ factory-method="aspectOf">
+ <property name="securityInterceptor"><ref bean="aspectJSecurityInterceptor"/></property>
+</bean>
+
+ That's it! Now you can create your beans from anywhere within
+ your application, using whatever means you think fit (eg new
+ Person();) and they will have the security interceptor
+ applied.
+
+
FilterInvocation Security Interceptor
diff --git a/project.xml b/project.xml
index 99938e8414..4cde0b656b 100644
--- a/project.xml
+++ b/project.xml
@@ -1,8 +1,8 @@
3
+ acegi-security
Acegi Security System for Spring
acegi
- acegi-security
0.7-SNAPSHOT
net.sf.acegisecurity
Acegi Security System for Spring
@@ -306,9 +306,18 @@
acegi
resin-extracted
unknown
+ ${basedir}/lib/extracted/resin/resin-extracted.jar
jar
+
+ aspectj
+ aspectjrt
+ 1.2
+ jar
+ http://eclipse.org/aspectj/
+
+
${basedir}/src
@@ -359,4 +368,4 @@
maven-clover-plugin
-
+
\ No newline at end of file
diff --git a/upgrade-06-07.txt b/upgrade-06-07.txt
index c9e9e9a2ba..5175f99501 100644
--- a/upgrade-06-07.txt
+++ b/upgrade-06-07.txt
@@ -26,4 +26,9 @@ applications:
providing a performance benefit as MethodSecurityInterceptor is not called
for public (non-secure) objects. It also simplifies configuration.
+- MethodSecurityInterceptor has moved from
+ net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor to
+ net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor.
+ A simple find and replace will suffice to update your application contexts.
+
$Id$