Skip to content
This repository was archived by the owner on Feb 23, 2023. It is now read-only.

Commit 38c80f3

Browse files
eleftheriassdeleuze
authored andcommitted
Support Pre and Post method security annotations
See gh-289
1 parent cb1dd0e commit 38c80f3

File tree

17 files changed

+494
-2
lines changed

17 files changed

+494
-2
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2020 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+
* http://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;
17+
18+
import org.springframework.graalvm.extension.ComponentProcessor;
19+
import org.springframework.graalvm.extension.NativeImageContext;
20+
import org.springframework.graalvm.type.Type;
21+
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
25+
/**
26+
* Recognize spring.components that use any of @PostAuthorize, @PostFilter, @PreAuthorize or @PreFilter
27+
* annotation and register proxies for them.
28+
*
29+
* @author Eleftheria Stein
30+
*/
31+
public class PrePostSecuredComponentProcessor implements ComponentProcessor {
32+
33+
@Override
34+
public boolean handle(NativeImageContext imageContext, String componentType, List<String> classifiers) {
35+
Type type = imageContext.getTypeSystem().resolveName(componentType);
36+
return (type != null && (type.isAtPrePostSecured()));
37+
}
38+
39+
@Override
40+
public void process(NativeImageContext imageContext, String componentType, List<String> classifiers) {
41+
Type type = imageContext.getTypeSystem().resolveName(componentType);
42+
List<String> prePostSecuredInterfaces = new ArrayList<>();
43+
for (Type intface: type.getInterfaces()) {
44+
prePostSecuredInterfaces.add(intface.getDottedName());
45+
}
46+
if (prePostSecuredInterfaces.size()==0) {
47+
imageContext.log("PrePostSecuredComponentProcessor: unable to find interfaces to proxy on "+componentType);
48+
return;
49+
}
50+
prePostSecuredInterfaces.add("org.springframework.aop.SpringProxy");
51+
prePostSecuredInterfaces.add("org.springframework.aop.framework.Advised");
52+
prePostSecuredInterfaces.add("org.springframework.core.DecoratingProxy");
53+
imageContext.addProxy(prePostSecuredInterfaces);
54+
imageContext.log("PrePostSecuredComponentProcessor: creating proxy for these interfaces: "+prePostSecuredInterfaces);
55+
}
56+
}

spring-graalvm-native-configuration/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityHints.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@
2626
@TypeInfo(types= {EnableGlobalMethodSecurity.class,GlobalMethodSecurityConfiguration.class,
2727
AutoProxyRegistrar.class,GlobalMethodSecurityAspectJAutoProxyRegistrar.class,
2828
MethodSecurityMetadataSourceAdvisorRegistrar.class,Jsr250MetadataSourceConfiguration.class,
29-
})
30-
,@TypeInfo(types= MethodSecurityMetadataSourceAdvisor.class, access=AccessBits.CLASS|AccessBits.PUBLIC_METHODS|AccessBits.DECLARED_CONSTRUCTORS)
29+
}),
30+
@TypeInfo(types= MethodSecurityMetadataSourceAdvisor.class, access=AccessBits.CLASS|AccessBits.PUBLIC_METHODS|AccessBits.DECLARED_CONSTRUCTORS),
31+
@TypeInfo(typeNames= "org.springframework.security.access.expression.method.MethodSecurityExpressionRoot", access=AccessBits.DECLARED_CONSTRUCTORS),
3132
})
3233
@NativeImageHint(trigger=ReactiveMethodSecuritySelector.class, typeInfos = {
3334
@TypeInfo(types= {AutoProxyRegistrar.class,ReactiveMethodSecurityConfiguration.class})})

spring-graalvm-native-configuration/src/main/resources/META-INF/services/org.springframework.graalvm.extension.ComponentProcessor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ org.springframework.data.SpringDataComponentProcessor
33
org.springframework.web.WebComponentProcessor
44
org.springframework.SynthesizerComputationComponentProcessor
55
org.springframework.TransactionalComponentProcessor
6+
org.springframework.PrePostSecuredComponentProcessor

spring-graalvm-native-feature/src/main/java/org/springframework/graalvm/type/Type.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ public class Type {
9898
public final static String AtAliasFor = "Lorg/springframework/core/annotation/AliasFor;";
9999
public final static String Condition = "Lorg/springframework/context/annotation/Condition;";
100100
public final static String EnvironmentPostProcessor = "Lorg/springframework/boot/env/EnvironmentPostProcessor";
101+
public final static String AtPostAuthorize = "Lorg/springframework/security/access/prepost/PostAuthorize;";
102+
public final static String AtPostFilter = "Lorg/springframework/security/access/prepost/PostFilter;";
103+
public final static String AtPreAuthorize = "Lorg/springframework/security/access/prepost/PreAuthorize;";
104+
public final static String AtPreFilter = "Lorg/springframework/security/access/prepost/PreFilter;";
101105

102106
public final static Type MISSING = new Type(null, null, 0);
103107

@@ -2558,6 +2562,14 @@ public boolean isConditional() {
25582562
}
25592563
}
25602564

2565+
/**
2566+
* @return true if type or a method inside is marked @PostAuthorize, @PostFilter, @PreAuthorize or @PreFilter
2567+
*/
2568+
public boolean isAtPrePostSecured() {
2569+
return isAnnotatedInHierarchy(AtPostAuthorize) || isAnnotatedInHierarchy(AtPostFilter)
2570+
|| isAnnotatedInHierarchy(AtPreAuthorize) || isAnnotatedInHierarchy(AtPreFilter);
2571+
}
2572+
25612573
public void collectAnnotations(List<Type> collector, Predicate<Type> filter) {
25622574
if (!this.isAnnotation()) {
25632575
throw new IllegalStateException(this.getDottedName() + " is not an annotation");
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Spring Boot project with Spring MVC, Tomcat and Jackson.
2+
3+
To build and run the native application packaged in a lightweight container:
4+
```
5+
mvn spring-boot:build-image
6+
docker-compose up
7+
```
8+
9+
And then request the "/hello" or "/admin/hello" endpoints.
10+
11+
```
12+
curl user:password@localhost:8080/hello
13+
```
14+
15+
As an alternative, you can use `build.sh` (with a local GraalVM installation or combined with
16+
`run-dev-container.sh` at the root of `spring-graalvm-native` project). See also the related issue
17+
[Take advantage of Paketo dev-oriented images](https://github.com/spring-projects-experimental/spring-graalvm-native/issues/227).
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env bash
2+
3+
BLUE='\033[0;34m'
4+
NC='\033[0m'
5+
6+
printf "=== ${BLUE}Building %s sample${NC} ===\n" "${PWD##*/}"
7+
./compile.sh && ${PWD%/*samples/*}/scripts/test.sh
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env bash
2+
3+
ARTIFACT=security-method
4+
MAINCLASS=com.example.securingweb.SecuringWebApplication
5+
VERSION=0.0.1-SNAPSHOT
6+
7+
GREEN='\033[0;32m'
8+
RED='\033[0;31m'
9+
NC='\033[0m'
10+
11+
rm -rf target
12+
mkdir -p target/native-image
13+
14+
echo "Packaging $ARTIFACT with Maven"
15+
mvn -ntp package > target/native-image/output.txt
16+
17+
JAR="$ARTIFACT-$VERSION.jar"
18+
rm -f $ARTIFACT
19+
echo "Unpacking $JAR"
20+
cd target/native-image
21+
jar -xvf ../$JAR >/dev/null 2>&1
22+
cp -R META-INF BOOT-INF/classes
23+
24+
LIBPATH=`find BOOT-INF/lib | tr '\n' ':'`
25+
CP=BOOT-INF/classes:$LIBPATH
26+
27+
GRAALVM_VERSION=`native-image --version`
28+
echo "Compiling $ARTIFACT with $GRAALVM_VERSION"
29+
{ time native-image \
30+
--verbose \
31+
-H:Name=$ARTIFACT \
32+
--enable-all-security-services \
33+
-cp $CP $MAINCLASS >> output.txt ; } 2>> output.txt
34+
35+
if [[ -f $ARTIFACT ]]
36+
then
37+
cat output.txt
38+
printf "${GREEN}SUCCESS${NC}\n"
39+
mv ./$ARTIFACT ..
40+
exit 0
41+
else
42+
cat output.txt
43+
printf "${RED}FAILURE${NC}: an error occurred when compiling the native-image.\n"
44+
exit 1
45+
fi
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: '3.1'
2+
services:
3+
security:
4+
image: security:0.0.1-SNAPSHOT
5+
ports:
6+
- "8080:8080"
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-starter-parent</artifactId>
8+
<version>2.4.0</version>
9+
<relativePath/> <!-- lookup parent from repository -->
10+
</parent>
11+
<groupId>com.example</groupId>
12+
<artifactId>security-method</artifactId>
13+
<version>0.0.1-SNAPSHOT</version>
14+
15+
<properties>
16+
<java.version>1.8</java.version>
17+
</properties>
18+
19+
<build>
20+
<plugins>
21+
<plugin>
22+
<groupId>org.springframework.boot</groupId>
23+
<artifactId>spring-boot-maven-plugin</artifactId>
24+
<configuration>
25+
<image>
26+
<builder>paketobuildpacks/builder:tiny</builder>
27+
<env>
28+
<BP_BOOT_NATIVE_IMAGE>1</BP_BOOT_NATIVE_IMAGE>
29+
<!-- See https://github.com/spring-projects/spring-boot/issues/23132 -->
30+
<BP_BOOT_NATIVE_IMAGE_BUILD_ARGUMENTS>
31+
--enable-all-security-services
32+
</BP_BOOT_NATIVE_IMAGE_BUILD_ARGUMENTS>
33+
</env>
34+
</image>
35+
</configuration>
36+
</plugin>
37+
</plugins>
38+
</build>
39+
40+
<dependencies>
41+
<dependency>
42+
<groupId>org.springframework.experimental</groupId>
43+
<artifactId>spring-graalvm-native</artifactId>
44+
<version>0.8.3-SNAPSHOT</version>
45+
</dependency>
46+
<dependency>
47+
<groupId>org.springframework</groupId>
48+
<artifactId>spring-context-indexer</artifactId>
49+
</dependency>
50+
<dependency>
51+
<groupId>org.springframework.boot</groupId>
52+
<artifactId>spring-boot-starter-thymeleaf</artifactId>
53+
</dependency>
54+
<dependency>
55+
<groupId>org.springframework.boot</groupId>
56+
<artifactId>spring-boot-starter-web</artifactId>
57+
<exclusions>
58+
<exclusion>
59+
<groupId>org.apache.tomcat.embed</groupId>
60+
<artifactId>tomcat-embed-core</artifactId>
61+
</exclusion>
62+
<exclusion>
63+
<groupId>org.apache.tomcat.embed</groupId>
64+
<artifactId>tomcat-embed-websocket</artifactId>
65+
</exclusion>
66+
</exclusions>
67+
</dependency>
68+
<dependency>
69+
<groupId>org.apache.tomcat.experimental</groupId>
70+
<artifactId>tomcat-embed-programmatic</artifactId>
71+
<version>${tomcat.version}</version>
72+
</dependency>
73+
<dependency>
74+
<groupId>org.springframework.boot</groupId>
75+
<artifactId>spring-boot-starter-security</artifactId>
76+
</dependency>
77+
<dependency>
78+
<groupId>org.springframework.security</groupId>
79+
<artifactId>spring-security-test</artifactId>
80+
<scope>test</scope>
81+
</dependency>
82+
83+
<dependency>
84+
<groupId>org.springframework.boot</groupId>
85+
<artifactId>spring-boot-starter-test</artifactId>
86+
<scope>test</scope>
87+
<exclusions>
88+
<exclusion>
89+
<groupId>org.junit.vintage</groupId>
90+
<artifactId>junit-vintage-engine</artifactId>
91+
</exclusion>
92+
</exclusions>
93+
</dependency>
94+
</dependencies>
95+
96+
<pluginRepositories>
97+
<pluginRepository>
98+
<id>central</id>
99+
<url>https://repo.maven.apache.org/maven2</url>
100+
<snapshots>
101+
<enabled>false</enabled>
102+
</snapshots>
103+
</pluginRepository>
104+
<pluginRepository>
105+
<id>spring-release</id>
106+
<name>Spring release</name>
107+
<url>https://repo.spring.io/release</url>
108+
<snapshots>
109+
<enabled>false</enabled>
110+
</snapshots>
111+
</pluginRepository>
112+
<pluginRepository>
113+
<id>spring-snapshot</id>
114+
<name>Spring Snapshots</name>
115+
<url>https://repo.spring.io/snapshot</url>
116+
<snapshots>
117+
<enabled>true</enabled>
118+
</snapshots>
119+
</pluginRepository>
120+
<pluginRepository>
121+
<id>spring-milestone</id>
122+
<name>Spring Milestone</name>
123+
<url>https://repo.spring.io/milestone</url>
124+
<snapshots>
125+
<enabled>false</enabled>
126+
</snapshots>
127+
</pluginRepository>
128+
</pluginRepositories>
129+
<repositories>
130+
<repository>
131+
<id>central</id>
132+
<url>https://repo.maven.apache.org/maven2</url>
133+
<snapshots>
134+
<enabled>false</enabled>
135+
</snapshots>
136+
</repository>
137+
<repository>
138+
<id>spring-release</id>
139+
<name>Spring release</name>
140+
<url>https://repo.spring.io/release</url>
141+
<snapshots>
142+
<enabled>false</enabled>
143+
</snapshots>
144+
</repository>
145+
<repository>
146+
<id>spring-snapshot</id>
147+
<name>Spring Snapshots</name>
148+
<url>https://repo.spring.io/snapshot</url>
149+
<snapshots>
150+
<enabled>true</enabled>
151+
</snapshots>
152+
</repository>
153+
<repository>
154+
<id>spring-milestone</id>
155+
<name>Spring Milestone</name>
156+
<url>https://repo.spring.io/milestone</url>
157+
<snapshots>
158+
<enabled>false</enabled>
159+
</snapshots>
160+
</repository>
161+
</repositories>
162+
163+
<profiles>
164+
<profile>
165+
<id>agent</id>
166+
<build>
167+
<plugins>
168+
<plugin>
169+
<groupId>org.graalvm.nativeimage</groupId>
170+
<artifactId>native-image-maven-plugin</artifactId>
171+
<version>20.2.0</version>
172+
<configuration>
173+
<mainClass>com.example.methodsecurity.MethodSecurityApplication</mainClass>
174+
<imageName>security-method</imageName>
175+
<buildArgs>-Dspring.native.remove-yaml-support=true</buildArgs>
176+
</configuration>
177+
<executions>
178+
<execution>
179+
<goals>
180+
<goal>native-image</goal>
181+
</goals>
182+
<phase>package</phase>
183+
</execution>
184+
</executions>
185+
</plugin>
186+
<plugin>
187+
<groupId>org.springframework.boot</groupId>
188+
<artifactId>spring-boot-maven-plugin</artifactId>
189+
</plugin>
190+
</plugins>
191+
</build>
192+
</profile>
193+
</profiles>
194+
195+
</project>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
java -agentlib:native-image-agent=experimental-class-loader-support,config-output-dir=src/main/resources/META-INF/native-image -jar target/security-method-0.0.1-SNAPSHOT.jar

0 commit comments

Comments
 (0)