Prechádzať zdrojové kódy

SEC-1232: Added the aspect library needed for <global-method-security mode="aspectj"/> and a small sample

Mike Wiesner 16 rokov pred
rodič
commit
a1751aec2c

+ 66 - 0
aspects/pom.xml

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.security</groupId>
+        <artifactId>spring-security-parent</artifactId>
+        <version>3.0.0.CI-SNAPSHOT</version>
+    </parent>
+    <packaging>jar</packaging>
+    <artifactId>spring-security-aspects</artifactId>
+    <name>Spring Security - Aspects</name>
+    <dependencies>
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-core</artifactId>
+            <version>3.0.0.CI-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>aspectj-maven-plugin</artifactId>
+                <version>1.0</version>
+                <dependencies>
+                    <!--
+                        NB: You must use Maven 2.0.9 or above or these
+                        are ignored (see MNG-2972)
+                    -->
+                    <dependency>
+                        <groupId>org.aspectj</groupId>
+                        <artifactId>com.springsource.org.aspectj.runtime</artifactId>
+                        <version>1.6.3.RELEASE</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.aspectj</groupId>
+                        <artifactId>com.springsource.org.aspectj.tools</artifactId>
+                        <version>1.6.3.RELEASE</version>
+                    </dependency>
+                </dependencies>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>compile</goal>
+                            <goal>test-compile</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 66 - 0
aspects/src/main/java/org/springframework/security/access/intercept/aspectj/aspect/AnnotationSecurityAspect.aj

@@ -0,0 +1,66 @@
+package org.springframework.security.access.intercept.aspectj.aspect;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.access.intercept.aspectj.AspectJCallback;
+import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
+
+/**
+ * Concrete AspectJ transaction aspect using Spring Security @Secured annotation
+ * for JDK 1.5+.
+ *
+ * <p>
+ * When using this aspect, you <i>must</i> annotate the implementation class
+ * (and/or methods within that class), <i>not</i> the interface (if any) that
+ * the class implements. AspectJ follows Java's rule that annotations on
+ * interfaces are <i>not</i> inherited. This will vary from Spring AOP.
+ *
+ * @author Mike Wiesner
+ * @since 1.0
+ * @version $Id$
+ */
+public aspect AnnotationSecurityAspect implements InitializingBean {
+
+    /**
+     * Matches the execution of any public method in a type with the Secured
+     * annotation, or any subtype of a type with the Secured annotation.
+     */
+    private pointcut executionOfAnyPublicMethodInAtSecuredType() :
+        execution(public * ((@Secured *)+).*(..)) && @this(Secured);
+
+    /**
+     * Matches the execution of any method with the Secured annotation.
+     */
+    private pointcut executionOfSecuredMethod() :
+        execution(* *(..)) && @annotation(Secured);
+
+    private pointcut securedMethodExecution() :
+        executionOfAnyPublicMethodInAtSecuredType() ||
+        executionOfSecuredMethod();
+
+    private AspectJSecurityInterceptor securityInterceptor;
+
+    Object around(): securedMethodExecution() {
+        if (this.securityInterceptor == null) {
+            return proceed();
+        }
+
+        AspectJCallback callback = new AspectJCallback() {
+            public Object proceedWithObject() {
+                return proceed();
+            }
+        };
+
+        return this.securityInterceptor.invoke(thisJoinPoint, callback);
+    }
+
+    public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
+        this.securityInterceptor = securityInterceptor;
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        if (this.securityInterceptor == null)
+            throw new IllegalArgumentException("securityInterceptor required");
+    }
+
+}

+ 18 - 0
aspects/src/main/resources/META-INF/aop.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+
+    <!--
+        AspectJ load-time weaving config file to install common Spring
+        aspects.
+    -->
+<aspectj>
+
+    <!--
+  <weaver options="-showWeaveInfo"/>
+  -->
+
+    <aspects>
+        <aspect
+            name="org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect" />
+    </aspects>
+
+</aspectj>

+ 1 - 0
pom.xml

@@ -18,6 +18,7 @@
         <module>ntlm</module>
         <module>taglibs</module>
         <module>portlet</module>
+		<module>aspects</module>
         <module>samples</module>
         <!--module>itest</module-->
   </modules>

+ 89 - 0
samples/aspectj/pom.xml

@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.springframework.security</groupId>
+		<artifactId>spring-security-parent</artifactId>
+		<version>3.0.0.CI-SNAPSHOT</version>
+	</parent>
+	<artifactId>spring-security-samples-aspectj</artifactId>
+	<packaging>jar</packaging>
+	<name>Spring Security Sample AspectJ</name>
+	<dependencies>
+
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.6</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.security</groupId>
+			<artifactId>spring-security-core</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.security</groupId>
+			<artifactId>spring-security-aspects</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-test</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.0.2</version>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>aspectj-maven-plugin</artifactId>
+				<version>1.0</version>
+				<dependencies>
+					<!--
+						NB: You must use Maven 2.0.9 or above or these are ignored (see
+						MNG-2972)
+					-->
+					<dependency>
+						<groupId>org.aspectj</groupId>
+						<artifactId>com.springsource.org.aspectj.runtime</artifactId>
+						<version>1.6.3.RELEASE</version>
+					</dependency>
+					<dependency>
+						<groupId>org.aspectj</groupId>
+						<artifactId>com.springsource.org.aspectj.tools</artifactId>
+						<version>1.6.3.RELEASE</version>
+					</dependency>
+				</dependencies>
+				<executions>
+					<execution>
+						<goals>
+							<goal>compile</goal>
+							<goal>test-compile</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<aspectLibraries>
+						<aspectLibrary>
+							<groupId>org.springframework.security</groupId>
+							<artifactId>spring-security-aspects</artifactId>
+						</aspectLibrary>
+					</aspectLibraries>
+					<source>1.6</source>
+					<target>1.6</target>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>

+ 19 - 0
samples/aspectj/src/main/java/sample/aspectj/SecuredService.java

@@ -0,0 +1,19 @@
+package sample.aspectj;
+
+import org.springframework.security.access.annotation.Secured;
+
+/**
+ * Service which is secured on the class level
+ *
+ * @author Mike Wiesner
+ * @since 3.0
+ * @version $Id$
+ */
+@Secured("ROLE_USER")
+public class SecuredService {
+
+    public void secureMethod() {
+        // nothing
+    }
+
+}

+ 23 - 0
samples/aspectj/src/main/java/sample/aspectj/Service.java

@@ -0,0 +1,23 @@
+package sample.aspectj;
+
+import org.springframework.security.access.annotation.Secured;
+
+/**
+ * Service which is secured on method level
+ *
+ * @author Mike Wiesner
+ * @since 1.0
+ * @version $Id$
+ */
+public class Service {
+
+    @Secured("ROLE_USER")
+    public void secureMethod() {
+        // nothing
+    }
+
+    public void publicMethod() {
+        // nothing
+    }
+
+}

+ 44 - 0
samples/aspectj/src/main/resources/aspectj-context.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
+
+    <bean id="aspectJSecurityInterceptor"
+        class="org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor">
+        <property name="authenticationManager" ref="authenticationManager" />
+        <property name="accessDecisionManager" ref="accessDecisionManager" />
+        <property name="securityMetadataSource">
+            <bean
+                class="org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource" />
+        </property>
+    </bean>
+
+    <bean id="authenticationManager"
+        class="org.springframework.security.authentication.ProviderManager">
+        <property name="providers">
+            <bean
+                class="org.springframework.security.authentication.TestingAuthenticationProvider" />
+        </property>
+    </bean>
+
+    <bean id="accessDecisionManager"
+        class="org.springframework.security.access.vote.AffirmativeBased">
+        <property name="decisionVoters">
+            <list>
+                <bean
+                    class="org.springframework.security.access.vote.RoleVoter" />
+            </list>
+        </property>
+    </bean>
+
+    <bean
+        class="org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"
+        factory-method="aspectOf">
+        <property name="securityInterceptor" ref="aspectJSecurityInterceptor" />
+    </bean>
+
+    <bean class="sample.aspectj.Service" />
+
+    <bean class="sample.aspectj.SecuredService" />
+
+</beans>

+ 78 - 0
samples/aspectj/src/test/java/sample/aspectj/AspectJInterceptorTests.java

@@ -0,0 +1,78 @@
+package sample.aspectj;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = "classpath:aspectj-context.xml")
+public class AspectJInterceptorTests {
+
+    @Autowired
+    private Service service;
+
+    @Autowired
+    private SecuredService securedService;
+
+    @Test
+    public void testPublicMethod() throws Exception {
+        service.publicMethod();
+    }
+
+    @Test(expected = AuthenticationCredentialsNotFoundException.class)
+    public void testSecuredMethodNotAuthenticated() throws Exception {
+        service.secureMethod();
+    }
+
+    @Test(expected = AccessDeniedException.class)
+    public void testSecuredMethodWrongRole() throws Exception {
+        Authentication token = new UsernamePasswordAuthenticationToken("test", "xxx", AuthorityUtils
+                .createAuthorityList("ROLE_ADMIN"));
+        SecurityContextHolder.getContext().setAuthentication(token);
+        service.secureMethod();
+    }
+
+    @Test
+    public void testSecuredMethodEverythingOk() throws Exception {
+        Authentication token = new UsernamePasswordAuthenticationToken("test", "xxx", AuthorityUtils
+                .createAuthorityList("ROLE_USER"));
+        SecurityContextHolder.getContext().setAuthentication(token);
+        service.secureMethod();
+    }
+
+    @Test(expected = AuthenticationCredentialsNotFoundException.class)
+    public void testSecuredClassNotAuthenticated() throws Exception {
+        securedService.secureMethod();
+    }
+
+    @Test(expected = AccessDeniedException.class)
+    public void testSecuredClassWrongRole() throws Exception {
+        Authentication token = new UsernamePasswordAuthenticationToken("test", "xxx", AuthorityUtils
+                .createAuthorityList("ROLE_ADMIN"));
+        SecurityContextHolder.getContext().setAuthentication(token);
+        securedService.secureMethod();
+    }
+
+    @Test
+    public void testSecuredClassEverythingOk() throws Exception {
+        Authentication token = new UsernamePasswordAuthenticationToken("test", "xxx", AuthorityUtils
+                .createAuthorityList("ROLE_USER"));
+        SecurityContextHolder.getContext().setAuthentication(token);
+        securedService.secureMethod();
+    }
+
+    @After
+    public void tearDown() {
+        SecurityContextHolder.clearContext();
+    }
+
+}

+ 2 - 1
samples/pom.xml

@@ -17,7 +17,8 @@
         <module>openid</module>
         <module>ldap</module>
         <module>portlet</module>
-        <module>cas</module>        
+        <module>cas</module>   
+     	<module>aspectj</module>
     </modules>
     <dependencies>
         <dependency>