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 years ago
parent
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();
+    }
+}