Skip to content

Commit 0f58620

Browse files
committed
Add AspectJ AuthorizationManager Support
Closes gh-11326
1 parent a5351f3 commit 0f58620

File tree

24 files changed

+1223
-13
lines changed

24 files changed

+1223
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.security.authorization.method.aspectj;
17+
18+
import org.aopalliance.intercept.MethodInterceptor;
19+
import org.aopalliance.intercept.MethodInvocation;
20+
21+
import org.springframework.beans.factory.InitializingBean;
22+
import org.springframework.security.access.prepost.PostAuthorize;
23+
24+
/**
25+
* Abstract AspectJ aspect for adapting a {@link MethodInvocation}
26+
*
27+
* @author Josh Cummings
28+
* @since 5.8
29+
*/
30+
abstract aspect AbstractMethodInterceptorAspect {
31+
32+
protected abstract pointcut executionOfAnnotatedMethod();
33+
34+
private MethodInterceptor securityInterceptor;
35+
36+
Object around(): executionOfAnnotatedMethod() {
37+
if (this.securityInterceptor == null) {
38+
return proceed();
39+
}
40+
MethodInvocation invocation = new JoinPointMethodInvocation(thisJoinPoint, () -> proceed());
41+
try {
42+
return this.securityInterceptor.invoke(invocation);
43+
} catch (Throwable t) {
44+
throwUnchecked(t);
45+
throw new IllegalStateException("Code unexpectedly reached", t);
46+
}
47+
}
48+
49+
public void setSecurityInterceptor(MethodInterceptor securityInterceptor) {
50+
this.securityInterceptor = securityInterceptor;
51+
}
52+
53+
private static void throwUnchecked(Throwable ex) {
54+
AbstractMethodInterceptorAspect.<RuntimeException>throwAny(ex);
55+
}
56+
57+
@SuppressWarnings("unchecked")
58+
private static <E extends Throwable> void throwAny(Throwable ex) throws E {
59+
throw (E) ex;
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.authorization.method.aspectj;
18+
19+
import java.lang.reflect.AccessibleObject;
20+
import java.lang.reflect.Method;
21+
import java.util.function.Supplier;
22+
23+
import org.aopalliance.intercept.MethodInvocation;
24+
import org.aspectj.lang.JoinPoint;
25+
import org.aspectj.lang.reflect.CodeSignature;
26+
27+
import org.springframework.util.Assert;
28+
29+
class JoinPointMethodInvocation implements MethodInvocation {
30+
31+
private final JoinPoint jp;
32+
33+
private final Method method;
34+
35+
private final Object target;
36+
37+
private final Supplier<Object> proceed;
38+
39+
JoinPointMethodInvocation(JoinPoint jp, Supplier<Object> proceed) {
40+
this.jp = jp;
41+
if (jp.getTarget() != null) {
42+
this.target = jp.getTarget();
43+
}
44+
else {
45+
// SEC-1295: target may be null if an ITD is in use
46+
this.target = jp.getSignature().getDeclaringType();
47+
}
48+
String targetMethodName = jp.getStaticPart().getSignature().getName();
49+
Class<?>[] types = ((CodeSignature) jp.getStaticPart().getSignature()).getParameterTypes();
50+
Class<?> declaringType = jp.getStaticPart().getSignature().getDeclaringType();
51+
this.method = findMethod(targetMethodName, declaringType, types);
52+
Assert.notNull(this.method, () -> "Could not obtain target method from JoinPoint: '" + jp + "'");
53+
this.proceed = proceed;
54+
}
55+
56+
private Method findMethod(String name, Class<?> declaringType, Class<?>[] params) {
57+
Method method = null;
58+
try {
59+
method = declaringType.getMethod(name, params);
60+
}
61+
catch (NoSuchMethodException ignored) {
62+
}
63+
if (method == null) {
64+
try {
65+
method = declaringType.getDeclaredMethod(name, params);
66+
}
67+
catch (NoSuchMethodException ignored) {
68+
}
69+
}
70+
return method;
71+
}
72+
73+
@Override
74+
public Method getMethod() {
75+
return this.method;
76+
}
77+
78+
@Override
79+
public Object[] getArguments() {
80+
return this.jp.getArgs();
81+
}
82+
83+
@Override
84+
public AccessibleObject getStaticPart() {
85+
return this.method;
86+
}
87+
88+
@Override
89+
public Object getThis() {
90+
return this.target;
91+
}
92+
93+
@Override
94+
public Object proceed() throws Throwable {
95+
return this.proceed.get();
96+
}
97+
98+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.security.authorization.method.aspectj;
17+
18+
import org.aopalliance.intercept.MethodInterceptor;
19+
import org.aopalliance.intercept.MethodInvocation;
20+
21+
import org.springframework.beans.factory.InitializingBean;
22+
import org.springframework.security.access.prepost.PostAuthorize;
23+
24+
/**
25+
* Concrete AspectJ aspect using Spring Security @PostAuthorize annotation.
26+
*
27+
* <p>
28+
* When using this aspect, you <i>must</i> annotate the implementation class
29+
* (and/or methods within that class), <i>not</i> the interface (if any) that
30+
* the class implements. AspectJ follows Java's rule that annotations on
31+
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
32+
*
33+
* @author Mike Wiesner
34+
* @author Luke Taylor
35+
* @author Josh Cummings
36+
* @since 5.8
37+
*/
38+
public aspect PostAuthorizeAspect extends AbstractMethodInterceptorAspect {
39+
40+
/**
41+
* Matches the execution of any method with a PostAuthorize annotation.
42+
*/
43+
protected pointcut executionOfAnnotatedMethod() : execution(* *(..)) && @annotation(PostAuthorize);
44+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.security.authorization.method.aspectj;
17+
18+
import org.aopalliance.intercept.MethodInterceptor;
19+
import org.aopalliance.intercept.MethodInvocation;
20+
21+
import org.springframework.beans.factory.InitializingBean;
22+
import org.springframework.security.access.prepost.PostFilter;
23+
24+
/**
25+
* Concrete AspectJ aspect using Spring Security @PostFilter annotation.
26+
*
27+
* <p>
28+
* When using this aspect, you <i>must</i> annotate the implementation class
29+
* (and/or methods within that class), <i>not</i> the interface (if any) that
30+
* the class implements. AspectJ follows Java's rule that annotations on
31+
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
32+
*
33+
* @author Mike Wiesner
34+
* @author Luke Taylor
35+
* @author Josh Cummings
36+
* @since 5.8
37+
*/
38+
public aspect PostFilterAspect extends AbstractMethodInterceptorAspect {
39+
40+
/**
41+
* Matches the execution of any method with a PostFilter annotation.
42+
*/
43+
protected pointcut executionOfAnnotatedMethod() : execution(* *(..)) && @annotation(PostFilter);
44+
45+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.security.authorization.method.aspectj;
17+
18+
import org.aopalliance.intercept.MethodInterceptor;
19+
import org.aopalliance.intercept.MethodInvocation;
20+
21+
import org.springframework.beans.factory.InitializingBean;
22+
import org.springframework.security.access.prepost.PreAuthorize;
23+
24+
/**
25+
* Concrete AspectJ aspect using Spring Security @PreAuthorize annotation.
26+
*
27+
* <p>
28+
* When using this aspect, you <i>must</i> annotate the implementation class
29+
* (and/or methods within that class), <i>not</i> the interface (if any) that
30+
* the class implements. AspectJ follows Java's rule that annotations on
31+
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
32+
*
33+
* @author Mike Wiesner
34+
* @author Luke Taylor
35+
* @author Josh Cummings
36+
* @since 5.8
37+
*/
38+
public aspect PreAuthorizeAspect extends AbstractMethodInterceptorAspect {
39+
40+
/**
41+
* Matches the execution of any method with a PreAuthorize annotation.
42+
*/
43+
protected pointcut executionOfAnnotatedMethod() : execution(* *(..)) && @annotation(PreAuthorize);
44+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.security.authorization.method.aspectj;
17+
18+
import org.aopalliance.intercept.MethodInterceptor;
19+
import org.aopalliance.intercept.MethodInvocation;
20+
21+
import org.springframework.beans.factory.InitializingBean;
22+
import org.springframework.security.access.prepost.PreFilter;
23+
24+
/**
25+
* Concrete AspectJ aspect using Spring Security @PreFilter annotation.
26+
*
27+
* <p>
28+
* When using this aspect, you <i>must</i> annotate the implementation class
29+
* (and/or methods within that class), <i>not</i> the interface (if any) that
30+
* the class implements. AspectJ follows Java's rule that annotations on
31+
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
32+
*
33+
* @author Mike Wiesner
34+
* @author Luke Taylor
35+
* @author Josh Cummings
36+
* @since 5.8
37+
*/
38+
public aspect PreFilterAspect extends AbstractMethodInterceptorAspect {
39+
40+
/**
41+
* Matches the execution of any method with a PreFilter annotation.
42+
*/
43+
protected pointcut executionOfAnnotatedMethod() : execution(* *(..)) && @annotation(PreFilter);
44+
45+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.security.authorization.method.aspectj;
17+
18+
import org.aopalliance.intercept.MethodInterceptor;
19+
import org.aopalliance.intercept.MethodInvocation;
20+
21+
import org.springframework.beans.factory.InitializingBean;
22+
import org.springframework.security.access.annotation.Secured;
23+
24+
/**
25+
* Concrete AspectJ aspect using Spring Security @Secured annotation.
26+
*
27+
* <p>
28+
* When using this aspect, you <i>must</i> annotate the implementation class
29+
* (and/or methods within that class), <i>not</i> the interface (if any) that
30+
* the class implements. AspectJ follows Java's rule that annotations on
31+
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
32+
*
33+
* @author Mike Wiesner
34+
* @author Luke Taylor
35+
* @author Josh Cummings
36+
* @since 5.8
37+
*/
38+
public aspect SecuredAspect extends AbstractMethodInterceptorAspect {
39+
40+
/**
41+
* Matches the execution of any public method in a type with the Secured
42+
* annotation, or any subtype of a type with the Secured annotation.
43+
*/
44+
private pointcut executionOfAnyPublicMethodInAtSecuredType() :
45+
execution(public * ((@Secured *)+).*(..)) && @this(Secured);
46+
47+
/**
48+
* Matches the execution of any method with the Secured annotation.
49+
*/
50+
private pointcut executionOfSecuredMethod() :
51+
execution(* *(..)) && @annotation(Secured);
52+
53+
protected pointcut executionOfAnnotatedMethod() :
54+
executionOfAnyPublicMethodInAtSecuredType() ||
55+
executionOfSecuredMethod();
56+
}

0 commit comments

Comments
 (0)