Browse Source

Initial checkin of Security Java 5 Annotation support
(see http://opensource.atlassian.com/projects/spring/browse/SEC-4)

Note: I have created a new source dir "core-tiger" for Java 5 related core security classes, as well as test dir.

Note: project.properties should compile this project using 1.5.

WAR test application using Spring 1.2 Transaction Annotations and Security to follow

Mark St. Godard 20 năm trước cách đây
mục cha
commit
0a8699003f

+ 4 - 0
.classpath

@@ -55,5 +55,9 @@
 	<classpathentry kind="var" path="MAVEN_REPO/commons-lang/jars/commons-lang-2.0.jar"/>
 	<classpathentry sourcepath="DIST_BASE/commons-beanutils-1.6.1-src/src/java" kind="var" path="MAVEN_REPO/commons-beanutils/jars/commons-beanutils-1.6.1.jar"/>
 	<classpathentry kind="var" path="MAVEN_REPO/directory/jars/apacheds-main-0.9-SNAPSHOT.jar"/>
+	<classpathentry kind="src" path="core-tiger/src/main/java"/>
+	<classpathentry kind="src" path="core-tiger/src/test/java"/>
+	<classpathentry kind="src" path="core-tiger/src/main/resources"/>
+	<classpathentry kind="src" path="core-tiger/src/test/resources"/>
 	<classpathentry kind="output" path="target/eclipseclasses"/>
 </classpath>

+ 39 - 0
core-tiger/maven.xml

@@ -0,0 +1,39 @@
+<!--
+ * ========================================================================
+ * 
+ * Copyright 2004, 2005 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.
+ * 
+ * ========================================================================
+-->
+
+<project
+   xmlns:j="jelly:core"
+   xmlns:ant="jelly:ant"
+   xmlns:util="jelly:util"
+   xmlns:maven="jelly:maven"
+  >
+
+    <postGoal name="jar:jar">
+        <j:if test="${context.getVariable('signature.alias') != null}">
+        	<echo>signature.alias defined; signing JAR(s)...</echo>
+			<ant:signjar lazy="true" alias="${signature.alias}" storepass="${signature.storepass}" keystore="${signature.keystore}">
+				<fileset dir="${maven.build.dir}">
+					<include name="*.jar"/>
+				</fileset>
+			</ant:signjar>
+        </j:if>
+    </postGoal>
+
+</project>

+ 12 - 0
core-tiger/project.properties

@@ -0,0 +1,12 @@
+# $Id$
+
+# Values in this file will be overriden by any values with the same name
+# in the user-created build.properties file.
+
+# Compile settings
+#
+# Java 1.5 is required due to the use of annotations for metadata.
+# (main Acegi Security project / parent) is Java 1.3 compatible
+#
+maven.compile.target=1.5
+maven.compile.source=1.5

+ 43 - 0
core-tiger/project.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+  <extend>${basedir}/../project.xml</extend>
+  <pomVersion>3</pomVersion>
+  <artifactId>acegi-security-core-tiger</artifactId>
+  <name>Acegi Security System for Spring - Java 5 (Tiger)</name>
+  <groupId>acegisecurity</groupId>
+  <siteDirectory>/home/groups/a/ac/acegisecurity/htdocs/multiproject/acegi-security-core-tiger</siteDirectory>
+  <repository>
+    <connection>scm:cvs:pserver:anonymous@cvs.sourceforge.net:/cvsroot/acegisecurity:acegisecurity</connection>
+    <developerConnection>scm:cvs:ext:${maven.username}@cvs.sourceforge.net:/cvsroot/acegisecurity:acegisecurity</developerConnection>
+    <url>http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/acegisecurity/acegisecurity/domain/</url>
+  </repository>
+  <dependencies>
+    <dependency>
+      <groupId>acegisecurity</groupId>
+      <artifactId>acegi-security</artifactId>
+      <version>0.9.0-SNAPSHOT</version>
+      <type>jar</type>
+    </dependency>
+  </dependencies>
+  <build>
+    <resources>
+      <resource>
+        <directory>${basedir}/src/main/resources/</directory>
+        <targetPath>/</targetPath>
+        <includes>
+          <include>*.xsl</include>
+        </includes>
+        <filtering>false</filtering>
+      </resource>    
+      <resource>
+        <directory>${basedir}/../</directory>
+        <targetPath>META-INF</targetPath>
+        <includes>
+          <include>notice.txt</include>
+        </includes>
+        <filtering>false</filtering>
+      </resource>
+    </resources>
+  </build>
+</project>
+

+ 54 - 0
core-tiger/src/main/java/org/acegisecurity/annotation/Secured.java

@@ -0,0 +1,54 @@
+/* Copyright 2004, 2005 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.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Java 5 annotation for describing service layer security attributes.
+ * 
+ * <p>The <code>Secured</code> annotation is used to define a list of security 
+ * configuration attributes for business methods.  This annotation can be used 
+ * as a Java 5 alternative to XML configuration.
+ * <p>For example:
+ * <pre>
+ *     &#64;Secured ({"ROLE_USER"})
+ *     public void create(Contact contact);
+ *     
+ *     &#64;Secured ({"ROLE_USER", "ROLE_ADMIN"})
+ *     public void update(Contact contact);
+ *     
+ *     &#64;Secured ({"ROLE_ADMIN"})
+ *     public void delete(Contact contact);
+ * </pre> 
+ * @author Mark St.Godard
+ * @version $Id$
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Secured {
+    //~ Methods ================================================================
+
+    /**
+     * Returns the list of security configuration attributes. 
+     *   (i.e. ROLE_USER, ROLE_ADMIN etc.)
+     * @return String[] The secure method attributes 
+     */
+    public String[] value();
+}

+ 132 - 0
core-tiger/src/main/java/org/acegisecurity/annotation/SecurityAnnotationAttributes.java

@@ -0,0 +1,132 @@
+/* Copyright 2004, 2005 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.annotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import net.sf.acegisecurity.SecurityConfig;
+
+import org.springframework.metadata.Attributes;
+
+/**
+ * Java 5 Annotation <code>Attributes</code> metadata implementation used for 
+ * secure method interception. 
+ * 
+ * <p>This <code>Attributes</code> implementation will return security 
+ * configuration for classes described using the <code>Secured</code> Java 5
+ * annotation. 
+ * 
+ * <p>The <code>SecurityAnnotationAttributes</code> implementation can be used
+ * to configure a <code>MethodDefinitionAttributes</code> and 
+ * <code>MethodSecurityInterceptor</code> bean definition (see below).
+ * 
+ * <p>For example: 
+ * <pre>
+ * &lt;bean id="attributes" 
+ *     class="net.sf.acegisecurity.annotation.SecurityAnnotationAttributes"/>
+ * 
+ * &lt;bean id="objectDefinitionSource" 
+ *     class="net.sf.acegisecurity.intercept.method.MethodDefinitionAttributes">
+ *     &lt;property name="attributes">
+ *         &lt;ref local="attributes"/>
+ *     &lt;/property>
+ * &lt;/bean>
+ * 
+ * &lt;bean id="securityInterceptor" 
+ *     class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
+ *      . . .
+ *      &lt;property name="objectDefinitionSource">
+ *          &lt;ref local="objectDefinitionSource"/>
+ *      &lt;/property>
+ * &lt;/bean>
+ * </pre>
+ * 
+ * <p>These security annotations are similiar to the Commons Attributes
+ * approach, however they are using Java 5 language-level metadata support.
+ *
+ * @author Mark St.Godard
+ * @version $Id$
+ *
+ * @see net.sf.acegisecurity.annotation.Secured
+ */
+public class SecurityAnnotationAttributes implements Attributes {
+
+	/**
+	 * Get the <code>Secured</code> attributes for a given target class.
+	 * @param method The target method
+	 * @return Collection of <code>SecurityConfig</code>
+	 * @see Attributes#getAttributes
+	 */
+	public Collection getAttributes(Class target) {
+
+		Set<SecurityConfig> attributes = new HashSet<SecurityConfig>();
+
+		for (Annotation annotation : target.getAnnotations()) {
+			// check for Secured annotations
+			if (annotation instanceof Secured) {
+				Secured attr = (Secured) annotation;
+				for (String auth : attr.value()) {
+					attributes.add(new SecurityConfig(auth));
+				}
+				break;
+			}
+		}
+		return attributes;
+	}
+
+	public Collection getAttributes(Class clazz, Class filter) {
+		throw new UnsupportedOperationException("Unsupported operation");
+	}
+
+	/**
+	 * Get the <code>Secured</code> attributes for a given target method.
+	 * @param method The target method
+	 * @return Collection of <code>SecurityConfig</code>
+	 * @see Attributes#getAttributes
+	 */	
+	public Collection getAttributes(Method method) {
+		Set<SecurityConfig> attributes = new HashSet<SecurityConfig>();
+
+		for (Annotation annotation : method.getAnnotations()) {
+			// check for Secured annotations
+			if (annotation instanceof Secured) {
+				Secured attr = (Secured) annotation;
+				for (String auth : attr.value()) {
+					attributes.add(new SecurityConfig(auth));
+				}
+				break;
+			}
+		}
+		return attributes;
+	}
+
+	public Collection getAttributes(Method method, Class clazz) {
+		throw new UnsupportedOperationException("Unsupported operation");
+	}
+
+	public Collection getAttributes(Field field) {
+		throw new UnsupportedOperationException("Unsupported operation");
+	}
+
+	public Collection getAttributes(Field field, Class clazz) {
+		throw new UnsupportedOperationException("Unsupported operation");
+	}
+
+}

+ 18 - 0
core-tiger/src/test/java/org/acegisecurity/annotation/BusinessService.java

@@ -0,0 +1,18 @@
+package net.sf.acegisecurity.annotation;
+
+@Secured ({"ROLE_USER"})
+public interface BusinessService {
+	
+	@Secured ({"ROLE_USER"})
+	public void someUserMethod1();
+
+	@Secured ({"ROLE_USER"})
+	public void someUserMethod2();	
+	
+	@Secured ({"ROLE_USER","ROLE_ADMIN"})
+	public void someUserAndAdminMethod();
+	
+	@Secured ({"ROLE_ADMIN"})
+	public void someAdminMethod();
+	
+}

+ 142 - 0
core-tiger/src/test/java/org/acegisecurity/annotation/SecurityAnnotationAttributesTests.java

@@ -0,0 +1,142 @@
+/* Copyright 2004, 2005 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.annotation;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+
+import junit.framework.TestCase;
+import net.sf.acegisecurity.SecurityConfig;
+
+import org.springframework.metadata.Attributes;
+
+
+/**
+ * Tests for {@link net.sf.acegisecurity.annotation.SecurityAnnotationAttributes}
+ *
+ * @author Mark St.Godard
+ * @version $Revision$
+ */
+public class SecurityAnnotationAttributesTests extends TestCase {
+    //~ Instance fields ========================================================
+
+    private Attributes attributes;
+
+    //~ Methods ================================================================
+
+    public void testGetAttributesClass() {
+        Collection attrs = this.attributes.getAttributes(BusinessService.class);
+
+        assertNotNull(attrs);
+        
+        // expect 1 annotation
+        assertTrue(attrs.size() == 1);
+
+        // should have 1 SecurityConfig 
+        SecurityConfig sc = (SecurityConfig) attrs.iterator().next();
+
+        assertTrue(sc.getAttribute().equals("ROLE_USER"));
+    }
+
+    public void testGetAttributesClassClass() {
+    	try{
+    		this.attributes.getAttributes(BusinessService.class, null);
+    		fail("Unsupported method should have thrown an exception!");
+    		
+    	}catch(UnsupportedOperationException expected){
+    	}
+    }
+
+    public void testGetAttributesField() {
+    	try{
+    		Field field = null;
+    		this.attributes.getAttributes(field);
+    		fail("Unsupported method should have thrown an exception!");
+    		
+    	}catch(UnsupportedOperationException expected){
+    		
+    	}
+    	
+    }
+
+    public void testGetAttributesFieldClass() {
+    	try{
+    		Field field = null;
+    		this.attributes.getAttributes(field, null);
+    		fail("Unsupported method should have thrown an exception!");
+    		
+    	}catch(UnsupportedOperationException expected){
+    		
+    	}
+    	
+    }
+
+    public void testGetAttributesMethod() {
+    	
+    	Method method = null;
+    	try{
+    		method = BusinessService.class.getMethod("someUserAndAdminMethod",new Class[] {});
+    	}catch(NoSuchMethodException unexpected){
+    		fail("Should be a method called 'someUserAndAdminMethod' on class!");
+    	}
+        Collection attrs = this.attributes.getAttributes(method);
+
+        assertNotNull(attrs);
+        
+        // expect 2 attributes
+        assertTrue(attrs.size() == 2);
+
+        boolean user = false;
+        boolean admin = false;
+        // should have 2 SecurityConfigs 
+        for(Object obj: attrs){
+        	assertTrue(obj instanceof SecurityConfig);
+        	SecurityConfig sc = (SecurityConfig)obj;
+        	if(sc.getAttribute().equals("ROLE_USER")){
+        		user = true;
+        	}else if(sc.getAttribute().equals("ROLE_ADMIN")){
+        		admin = true;
+        	}
+        }
+        // expect to have ROLE_USER and ROLE_ADMIN
+        assertTrue(user && admin);
+    }
+
+    public void testGetAttributesMethodClass() {
+    	
+    	Method method = null;
+    	try{
+    		method = BusinessService.class.getMethod("someUserAndAdminMethod",new Class[] {});
+    	}catch(NoSuchMethodException unexpected){
+    		fail("Should be a method called 'someUserAndAdminMethod' on class!");
+    	}
+    	
+    	try{
+    		this.attributes.getAttributes(method,null);
+    		fail("Unsupported method should have thrown an exception!");
+    		
+    	}catch(UnsupportedOperationException expected){
+    		
+    	}
+    	
+    }
+
+    protected void setUp() throws Exception {
+        // create the Annotations impl
+        this.attributes = new SecurityAnnotationAttributes();
+    }
+}