<classpathentry kind="src" path="support/src/test/java"/>
<classpathentry excluding="**" kind="src" output="support/src/main/resources" path="support/src/main/resources"/>
<classpathentry excluding="**" kind="src" output="support/src/test/resources" path="support/src/test/resources"/>
+ <classpathentry kind="src" path="security/src/main/java"/>
+ <classpathentry kind="src" path="security/src/test/java"/>
+ <classpathentry excluding="**" kind="src" output="security/src/test/resources" path="security/src/test/resources"/>
<classpathentry kind="src" path="socketproxy/src/main/java"/>
<classpathentry kind="src" path="socketproxy/src/test/java"/>
<classpathentry excluding="**" kind="src" output="socketproxy/src/test/resources" path="socketproxy/src/test/resources"/>
<classpathentry excluding="**" kind="src" output="mythtv/war/src/main/resources" path="mythtv/war/src/main/resources"/>
<classpathentry kind="src" path="mythtv/timer/src/main/java"/>
<classpathentry excluding="**" kind="src" output="mythtv/timer/src/main/resources" path="mythtv/timer/src/main/resources"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.6.0"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER/modules"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
<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>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-utils</artifactId>
- <packaging>pom</packaging>
- <version>0.2-SNAPSHOT</version>
- <name>wamblee.org utility libraries</name>
- <url>http://wamblee.org</url>
- <modules>
- <module>support</module>
- <module>hibernate-jpa</module>
- <module>socketproxy</module>
- <module>crawler</module>
- <module>gps</module>
- <module>mythtv</module>
- </modules>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.4</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>dbunit</groupId>
- <artifactId>dbunit</artifactId>
- <version>2.1</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>jmock</groupId>
- <artifactId>jmock-cglib</artifactId>
- <version>1.1.0</version>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <groupId>cglib</groupId>
- <artifactId>cglib-full</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- </dependencies>
-
- <dependencyManagement>
+ 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>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-utils</artifactId>
+ <packaging>pom</packaging>
+ <version>0.2-SNAPSHOT</version>
+ <name>wamblee.org utility libraries</name>
+ <url>http://wamblee.org</url>
+ <modules>
+ <module>support</module>
+ <module>hibernate-jpa</module>
+ <module>security</module>
+ <module>socketproxy</module>
+ <module>crawler</module>
+ <module>gps</module>
+ <module>mythtv</module>
+ </modules>
<dependencies>
- <dependency>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-support</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-support</artifactId>
- <type>test-jar</type>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-hibernate-jpa</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-hibernate-jpa</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- </dependency>
- <dependency>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-socketproxy</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-socketproxy</artifactId>
- <type>test-jar</type>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-crawler</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-crawler</artifactId>
- <type>test-jar</type>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-crawler-basic</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.wamblee</groupId>
- <artifactId>wamblee-crawler-basic</artifactId>
- <type>test-jar</type>
- <version>${project.version}</version>
- </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.dbunit</groupId>
+ <artifactId>dbunit</artifactId>
+ <version>2.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>jmock</groupId>
+ <artifactId>jmock-cglib</artifactId>
+ <version>1.1.0</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>cglib</groupId>
+ <artifactId>cglib-full</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
- <dependency>
- <groupId>javax.persistence</groupId>
- <artifactId>persistence-api</artifactId>
- <version>1.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.activation</groupId>
- <artifactId>activation</artifactId>
- <version>1.1</version>
- </dependency>
- <dependency>
- <groupId>javax.mail</groupId>
- <artifactId>mail</artifactId>
- <version>1.4.1</version>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.3</version>
- <type>jar</type>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- <version>10.3.2.1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derbyclient</artifactId>
- <version>10.3.2.1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derbynet</artifactId>
- <version>10.3.2.1</version>
- </dependency>
- <dependency>
- <groupId>quartz</groupId>
- <artifactId>quartz</artifactId>
- <version>1.5.1</version>
- </dependency>
- <dependency>
- <groupId>jtidy</groupId>
- <artifactId>jtidy</artifactId>
- <version>4aug2000r7-dev</version>
- </dependency>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-support</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-support</artifactId>
+ <type>test-jar</type>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-hibernate-jpa</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-hibernate-jpa</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-socketproxy</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-socketproxy</artifactId>
+ <type>test-jar</type>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-crawler</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-crawler</artifactId>
+ <type>test-jar</type>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-crawler-basic</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-crawler-basic</artifactId>
+ <type>test-jar</type>
+ <version>${project.version}</version>
+ </dependency>
-
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <version>1.0.2</version>
- </dependency>
- <dependency>
- <groupId>commons-httpclient</groupId>
- <artifactId>commons-httpclient</artifactId>
- <version>3.0</version>
- </dependency>
- <dependency>
- <groupId>commons-beanutils</groupId>
- <artifactId>commons-beanutils</artifactId>
- <version>1.7.0</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-beans</artifactId>
- <version>${springversion}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-web</artifactId>
- <version>${springversion}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jms</artifactId>
- <version>${springversion}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>${springversion}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-hibernate3</artifactId>
- <version>${springversion}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jpa</artifactId>
- <version>${springversion}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-aop</artifactId>
- <version>${springversion}</version>
- </dependency>
+ <dependency>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.activation</groupId>
+ <artifactId>activation</artifactId>
+ <version>1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ <version>1.4.1</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.3</version>
+ <type>jar</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>3.1.14</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <version>10.3.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derbyclient</artifactId>
+ <version>10.3.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derbynet</artifactId>
+ <version>10.3.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>quartz</groupId>
+ <artifactId>quartz</artifactId>
+ <version>1.5.1</version>
+ </dependency>
+ <dependency>
+ <groupId>jtidy</groupId>
+ <artifactId>jtidy</artifactId>
+ <version>4aug2000r7-dev</version>
+ </dependency>
- <!-- should be possible to remove the dependence on log4j -->
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.8</version>
- </dependency>
- <dependency>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- <version>1.6</version>
- <exclusions>
- <exclusion>
- <groupId>xml-apis</groupId>
- <artifactId>xml-apis</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>net.sf.ehcache</groupId>
- <artifactId>ehcache</artifactId>
- <version>1.2.3</version>
- </dependency>
- <dependency>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- <version>2.8.1</version>
- </dependency>
-
-
- <dependency>
- <groupId>commons-email</groupId>
- <artifactId>commons-email</artifactId>
- <version>1.0</version>
- </dependency>
- <dependency>
- <groupId>jaxen</groupId>
- <artifactId>jaxen</artifactId>
- <version>1.1-beta-9</version>
- <exclusions>
- <exclusion>
- <groupId>xom</groupId>
- <artifactId>xom</artifactId>
- </exclusion>
- <exclusion>
- <groupId>xerces</groupId>
- <artifactId>xmlParserAPIs</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>jstl</groupId>
- <artifactId>jstl</artifactId>
- <version>1.1.2</version>
- </dependency>
- <dependency>
- <groupId>taglibs</groupId>
- <artifactId>standard</artifactId>
- <version>1.1.2</version>
- </dependency>
- <dependency>
- <groupId>jfree</groupId>
- <artifactId>jfreechart</artifactId>
- <version>1.0.1</version>
- </dependency>
- <dependency>
- <groupId>jfree</groupId>
- <artifactId>jcommon</artifactId>
- <version>1.0.2</version>
- </dependency>
-
- <dependency>
- <groupId>javaee</groupId>
- <artifactId>javaee-api</artifactId>
- <version>5</version>
- <scope>provided</scope>
- </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.0.2</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-httpclient</groupId>
+ <artifactId>commons-httpclient</artifactId>
+ <version>3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-beanutils</groupId>
+ <artifactId>commons-beanutils</artifactId>
+ <version>1.7.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ <version>${springversion}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-web</artifactId>
+ <version>${springversion}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-jms</artifactId>
+ <version>${springversion}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>${springversion}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-hibernate3</artifactId>
+ <version>${springversion}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-jpa</artifactId>
+ <version>${springversion}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-aop</artifactId>
+ <version>${springversion}</version>
+ </dependency>
- </dependencies>
- </dependencyManagement>
+ <!-- should be possible to remove the dependence on log4j -->
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.8</version>
+ </dependency>
+ <dependency>
+ <groupId>dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <version>1.6</version>
+ <exclusions>
+ <exclusion>
+ <groupId>xml-apis</groupId>
+ <artifactId>xml-apis</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.ehcache</groupId>
+ <artifactId>ehcache</artifactId>
+ <version>1.2.3</version>
+ </dependency>
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.8.1</version>
+ </dependency>
+
+
+ <dependency>
+ <groupId>commons-email</groupId>
+ <artifactId>commons-email</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>jaxen</groupId>
+ <artifactId>jaxen</artifactId>
+ <version>1.1-beta-9</version>
+ <exclusions>
+ <exclusion>
+ <groupId>xom</groupId>
+ <artifactId>xom</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>xerces</groupId>
+ <artifactId>xmlParserAPIs</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>jstl</groupId>
+ <artifactId>jstl</artifactId>
+ <version>1.1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>taglibs</groupId>
+ <artifactId>standard</artifactId>
+ <version>1.1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>jfree</groupId>
+ <artifactId>jfreechart</artifactId>
+ <version>1.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>jfree</groupId>
+ <artifactId>jcommon</artifactId>
+ <version>1.0.2</version>
+ </dependency>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.6</source>
- <target>1.6</target>
- </configuration>
- </plugin>
+ <dependency>
+ <groupId>javaee</groupId>
+ <artifactId>javaee-api</artifactId>
+ <version>5</version>
+ <scope>provided</scope>
+ </dependency>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <includes>
- <include>**/*Test.java</include>
- </includes>
- </configuration>
- </plugin>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.3</version>
+ </dependency>
- <!-- Make sure other projects can use (or the test support
+
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+
+ <!-- Make sure other projects can use (or the test support
and test classes from the projects it uses. To use
a dependence on a test library of a project, an additinoal
dependence must be added with <type>test-jar</type>
-->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>test-jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>clean</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>cobertura-maven-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>clean</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
+ </plugins>
- </plugins>
+ </build>
- </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-project-info-reports-plugin</artifactId>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>checkstyle</report>
+ <report>javadoc</report>
+ <report>dependencies</report>
+ <report>project-team</report>
+ <report>mailing-list</report>
+ <report>issue-tracking</report>
+ <report>license</report>
+ <report>scm</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>changes-maven-plugin</artifactId>
+ <version>2.0-beta-1</version>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>changes-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>surefire-report-maven-plugin</artifactId>
+ </plugin>
+ <!-- Test coverage reporting -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ </plugin>
- <reporting>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-project-info-reports-plugin</artifactId>
- <reportSets>
- <reportSet>
- <reports>
- <report>checkstyle</report>
- <report>javadoc</report>
- <report>dependencies</report>
- <report>project-team</report>
- <report>mailing-list</report>
- <report>issue-tracking</report>
- <report>license</report>
- <report>scm</report>
- </reports>
- </reportSet>
- </reportSets>
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>changes-maven-plugin</artifactId>
- <version>2.0-beta-1</version>
- <reportSets>
- <reportSet>
- <reports>
- <report>changes-report</report>
- </reports>
- </reportSet>
- </reportSets>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>surefire-report-maven-plugin</artifactId>
- </plugin>
- <!-- Test coverage reporting -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>cobertura-maven-plugin</artifactId>
- </plugin>
+ <!-- checkstyle -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <configLocation>config/sun_checks.xml</configLocation>
+ </configuration>
+ </plugin>
- <!-- checkstyle -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-checkstyle-plugin</artifactId>
- <configuration>
- <configLocation>config/sun_checks.xml</configLocation>
- </configuration>
- </plugin>
+ <!-- taglist -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>taglist-maven-plugin</artifactId>
+ <configuration>
+ <tags>
+ <tag>TODO</tag>
+ <tag>@todo</tag>
+ <tag>FIXME</tag>
+ </tags>
+ </configuration>
+ </plugin>
- <!-- taglist -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>taglist-maven-plugin</artifactId>
- <configuration>
- <tags>
- <tag>TODO</tag>
- <tag>@todo</tag>
- <tag>FIXME</tag>
- </tags>
- </configuration>
- </plugin>
+ </plugins>
+ </reporting>
- </plugins>
- </reporting>
-
- <repositories>
- <repository>
- <id>javaee</id>
- <name>Java EE repo at SUN</name>
- <url>http://download.java.net/maven/1</url>
- <layout>legacy</layout>
- </repository>
- </repositories>
+ <repositories>
+ <repository>
+ <id>javaee</id>
+ <name>Java EE repo at SUN</name>
+ <url>http://download.java.net/maven/1</url>
+ <layout>legacy</layout>
+ </repository>
+ </repositories>
- <properties>
- <springversion>2.0.8</springversion>
- </properties>
+ <properties>
+ <springversion>2.0.8</springversion>
+ </properties>
</project>
--- /dev/null
+<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">
+
+ <parent>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-utils</artifactId>
+ <version>0.2-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-security</artifactId>
+ <packaging>jar</packaging>
+ <name>wamblee.org security</name>
+ <url>http://wamblee.org</url>
+ <dependencies>
+
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-support</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-support</artifactId>
+ <type>test-jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.wamblee</groupId>
+ <artifactId>wamblee-hibernate-jpa</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-hibernate3</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-aop</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.transaction</groupId>
+ <artifactId>transaction-api</artifactId>
+ <version>1.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+/**
+ * An superclass of all other operations.
+ */
+public class AllOperation implements Operation {
+
+ private static final String OPERATION = "all";
+
+ /**
+ * Operation name.
+ */
+ private String _name;
+
+ /**
+ * Constructs an all operation.
+ *
+ */
+ public AllOperation() {
+ _name = OPERATION;
+ }
+
+ /**
+ * Constructs the operation, this constructor is the one that must be used
+ * by subclasses.
+ * @param aName Name of the operation. This name must be unique among all operations.
+ */
+ protected AllOperation(String aName) {
+ _name = aName;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.Operation#getName()
+ */
+ public String getName() {
+ return _name;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import org.wamblee.persistence.AbstractPersistent;
+import org.wamblee.usermgt.User;
+
+/**
+ * Matches any user.
+ */
+public class AnyUserCondition extends AbstractPersistent implements UserCondition {
+
+ /**
+ * Constructs the condition.
+ *
+ */
+ public AnyUserCondition() {
+ // Empty.
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.UserCondition#matches(org.wamblee.usermgt.User)
+ */
+ public boolean matches(User aUser) {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "AnyUserCondition()";
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+/**
+ * Authorization exception to be thrown when
+ * a resouce may not be accessed.
+ */
+public class AuthorizationException extends RuntimeException {
+
+ private Object _resource;
+ private Operation _operation;
+
+ public AuthorizationException(Object aResource, Operation aOperation) {
+ super("Operation '" + aOperation + "' not allowed on '" + aResource + "'");
+ _resource = aResource;
+ _operation = aOperation;
+ }
+
+ public Object getResource() {
+ return _resource;
+ }
+
+ public Operation getOperation() {
+ return _operation;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * Inititializer class for authorization rules. This class initializes the
+ * authorization rules in case none are present.
+ */
+public class AuthorizationInitializer {
+
+ private static final Logger LOGGER = Logger.getLogger(AuthorizationInitializer.class);
+
+ /**
+ * Initializes authorization rules in case none are present.
+ * @param aService Authorization service.
+ * @param aRules Default rules for initialization.
+ */
+ public AuthorizationInitializer(AuthorizationService aService, AuthorizationRule[] aRules) {
+ if ( aService.getRules().length == 0 ) {
+ for (AuthorizationRule rule: aRules) {
+ LOGGER.info("Appending authorization rule " + rule);
+ aService.appendRule(rule);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+/**
+ * Represents the result of an authorization decision.
+ */
+public enum AuthorizationResult {
+ /**
+ * Access is granted.
+ */
+ GRANTED,
+
+ /**
+ * Access is denied.
+ */
+ DENIED,
+
+ /**
+ * Access is undecided.
+ */
+ UNDECIDED,
+
+ /**
+ * Unsupported resource.
+ */
+ UNSUPPORTED_RESOURCE
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import org.wamblee.persistence.Persistent;
+import org.wamblee.usermgt.User;
+
+/**
+ * Represents an authorization rule to determine whether an operation is allowed on a resource.
+ */
+public interface AuthorizationRule extends Persistent {
+
+ /**
+ * Returns the supported object types for which this authorization rule applies.
+ * This can be used by the authorization service for optimization.
+ * @return Array of supported types.
+ */
+ Class[] getSupportedTypes();
+
+ /**
+ * Determines whether an operation is allowed on a certain resource.
+ * The rule implementation must be prepared to deal with resources for which it does
+ * not apply. In those cases it should return {@link AuthorizationResult#UNSUPPORTED_RESOURCE}.
+ * @param aResource Resource.
+ * @param anOperation Operation.
+ * @param aUser Current user.
+ * @return Authorization result.
+ */
+ AuthorizationResult isAllowed(Object aResource, Operation anOperation, User aUser);
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import org.wamblee.persistence.Persistent;
+
+/**
+ * Service to determine if access to a certain resource is allowed.
+ */
+public interface AuthorizationService extends Persistent {
+
+ /**
+ * Checks whether an operation is allowed on a resource.
+ * @param aResource Resource.
+ * @param aOperation Operation.
+ * @return Checks whether the operation is allowed on a resource.
+ */
+ boolean isAllowed(Object aResource, Operation aOperation);
+
+ /**
+ * Same as {@link #isAllowed(Object, Operation)} but throws a
+ * <code>RuntimeException</code> in case access is not allowed.
+ * @param aResource Resource to check.
+ * @param aOperation Operation to perform.
+ * @return Resource that was checked.
+ */
+ <T> T check(T aResource, Operation aOperation);
+
+ /**
+ * Gets the authorization rules.
+ * @return Rules.
+ */
+ AuthorizationRule[] getRules();
+
+ /**
+ * Appends a new authorization rule to the end.
+ * @param aRule Rule to append.
+ */
+ void appendRule(AuthorizationRule aRule);
+
+ /**
+ * Removes a rule.
+ * @param aRule Index of the rule to remove.
+ */
+ void removeRule(int aIndex);
+
+ /**
+ * Inserts a rule.
+ * @param aIndex Index of the position of the rule after insertion.
+ * @param aRule Rule to insert.
+ */
+ void insertRuleAfter(int aIndex, AuthorizationRule aRule);
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+/**
+ * Represents an operation to create something.
+ */
+public class CreateOperation extends AllOperation {
+
+ private static final String OPERATION = "create";
+
+ /**
+ * Constructs the operation.
+ *
+ */
+ public CreateOperation() {
+ super(OPERATION);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.wamblee.persistence.AbstractPersistent;
+import org.wamblee.usermgt.User;
+import org.wamblee.usermgt.UserAccessor;
+
+/**
+ * Default implementation of an authorization service.
+ * To determine whether access to a resource is allowed, the service consults a number
+ * of authorization rules in a fixed order. The first rule that gives a result GRANTED or
+ * DENIED determines the result of the evaluation. Rules that return any other result are
+ * ignoed. If none of the rules match, than access is denied.
+ */
+public class DefaultAuthorizationService extends AbstractPersistent implements AuthorizationService {
+
+ /**
+ * List of ordered authorization rules.
+ */
+ private List<AuthorizationRule> _rules;
+
+ /**
+ * User accessor used to obtain the current user.
+ */
+ private UserAccessor _userAccessor;
+
+ /**
+ * Name for this instance of the authorization service.
+ */
+ private String _name;
+
+ /**
+ * Constructs the service.
+ * @param aAccessor User accessor.
+ * @param aName Name of this instance of the service.
+ */
+ public DefaultAuthorizationService(UserAccessor aAccessor, String aName) {
+ _rules = new ArrayList<AuthorizationRule>();
+ _userAccessor = aAccessor;
+ _name = aName;
+ }
+
+ /**
+ * Constructs the authorization service.
+ */
+ public DefaultAuthorizationService() {
+ _rules = new ArrayList<AuthorizationRule>();
+ _userAccessor = null;
+ _name = null;
+ }
+
+ /**
+ * Sets the user accessor.
+ * @param aUserAccessor User accessor.
+ */
+ public void setUserAccessor(UserAccessor aUserAccessor) {
+ _userAccessor = aUserAccessor;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.AuthorizationService#isAllowed(java.lang.Object, org.wamblee.security.authorization.Operation)
+ */
+ public boolean isAllowed(Object aResource, Operation aOperation) {
+ User user = _userAccessor.getCurrentUser();
+ for (AuthorizationRule rule: _rules) {
+ switch ( rule.isAllowed(aResource, aOperation, user)) {
+ case DENIED: { return false; }
+ case GRANTED: { return true; }
+ }
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.AuthorizationService#check(T, org.wamblee.security.authorization.Operation)
+ */
+ public <T> T check(T aResource, Operation aOperation) {
+ if ( !isAllowed(aResource, aOperation)) {
+ throw new AuthorizationException(aResource, aOperation);
+ }
+ return aResource;
+ }
+
+ protected String getName() {
+ return _name;
+ }
+
+ public void setName(String aName) {
+ _name = aName;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.AuthorizationService#getRules()
+ */
+ public AuthorizationRule[] getRules() {
+ return _rules.toArray(new AuthorizationRule[0]);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.AuthorizationService#appendRule(org.wamblee.security.authorization.AuthorizationRule)
+ */
+ public void appendRule(AuthorizationRule aRule) {
+ _rules.add(aRule);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.AuthorizationService#insertRuleAfter(int, org.wamblee.security.authorization.AuthorizationRule)
+ */
+ public void insertRuleAfter(int aIndex, AuthorizationRule aRule) {
+ _rules.add(aIndex, aRule);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.AuthorizationService#removeRule(int)
+ */
+ public void removeRule(int aIndex) {
+ _rules.remove(aIndex);
+ }
+
+ /**
+ * For OR mapping.
+ * @return The rules.
+ */
+ protected List<AuthorizationRule> getMappedRules() {
+ return _rules;
+ }
+
+ /**
+ * For OR mapping.
+ * @param aRules The rules.
+ */
+ protected void setMappedRules(List<AuthorizationRule> aRules) {
+ _rules = aRules;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Operation registry implementation.
+ * This implementation ignores the distinction between different types of resources
+ * and simply assumes that every operation is applicable to every type of resource.
+ */
+public class DefaultOperationRegistry implements OperationRegistry {
+
+ private Map<String,Operation> _operations;
+
+ public DefaultOperationRegistry(Operation[] aOperations) {
+ _operations = new TreeMap<String, Operation>();
+ for (Operation operation: aOperations) {
+ _operations.put(operation.getName(), operation);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.OperationRegistry#getOperations(java.lang.Class)
+ */
+ public Operation[] getOperations(Class aResourceClass) {
+ return _operations.values().toArray(new Operation[0]);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.OperationRegistry#encode(org.wamblee.security.authorization.Operation[])
+ */
+ public String encode(Operation[] aOperations) {
+ StringBuffer buffer = new StringBuffer();
+ for (Operation operation: aOperations) {
+ if ( buffer.length() > 0 ) {
+ buffer.append(',');
+ }
+ buffer.append(operation.getName());
+ }
+ return buffer.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.OperationRegistry#decode(java.lang.Class, java.lang.String)
+ */
+ public Operation[] decode(Class aResourceClass, String aOperationsString) {
+ return decode(aOperationsString);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.OperationRegistry#decode(java.lang.String)
+ */
+ public Operation[] decode(String aOperationsString) {
+ if ( aOperationsString.length() == 0 ) {
+ return new Operation[0];
+ }
+ String[] names = aOperationsString.split(",");
+ ArrayList<Operation> result = new ArrayList<Operation>();
+ for (String name: names) {
+ Operation operation = _operations.get(name);
+ if ( operation == null ) {
+ throw new IllegalArgumentException("Unknown operation '" + name + "'");
+ }
+ result.add(operation);
+ }
+ return result.toArray(new Operation[0]);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+/**
+ * Deletes the operation.
+ */
+public class DeleteOperation extends AllOperation {
+
+ private static final String OPERATION = "delete";
+
+ /**
+ * Constructs the operation.
+ *
+ */
+ public DeleteOperation() {
+ super(OPERATION);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import org.wamblee.persistence.AbstractPersistent;
+import org.wamblee.usermgt.User;
+
+/**
+ * Checks if a user against a specific group.
+ */
+public class GroupUserCondition extends AbstractPersistent implements UserCondition {
+
+ /**
+ * Group the user must be in.
+ */
+ private String _group;
+
+ /**
+ * Constructs the condition.
+ * @param aGroup Group the user must be in.
+ */
+ public GroupUserCondition(String aGroup) {
+ _group = aGroup;
+ }
+
+ /**
+ * For OR mapping.
+ *
+ */
+ protected GroupUserCondition() {
+ _group = null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.UserCondition#matches(org.wamblee.usermgt.UserAccessor)
+ */
+ public boolean matches(User aUser) {
+ return aUser.isInGroup(_group);
+ }
+
+ /**
+ * @return Returns the _group.
+ */
+ protected String getGroup() {
+ return _group;
+ }
+
+ /**
+ * @param _group The _group to set.
+ */
+ protected void setGroup(String aGroup) {
+ _group = aGroup;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "GroupUserCondition(group=" + _group + ")";
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import org.wamblee.persistence.AbstractPersistent;
+
+/**
+ * Determiens if an operation is a subclass of a specified operation.
+ */
+public class IsaOperationCondition extends AbstractPersistent implements
+ OperationCondition {
+
+ /**
+ * Operation that the other operation must be a subclass of.
+ */
+ private Class<? extends Operation> _operation;
+
+ /**
+ * Constructs the condition.
+ *
+ * @param aOperation
+ * Operation that an operation must be an instance of.
+ */
+ public IsaOperationCondition(Class<? extends Operation> aOperation) {
+ _operation = aOperation;
+ }
+
+ /**
+ * For OR mapping.
+ *
+ */
+ public IsaOperationCondition() {
+ _operation = null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.authorization.OperationCondition#matches(org.wamblee.security.authorization.Operation)
+ */
+ public boolean matches(Operation aOperation) {
+ return _operation.isInstance(aOperation);
+ }
+
+ /**
+ * Gets the operation as a string. For OR mapping only.
+ *
+ * @return Operation string.
+ */
+ protected String getOperationString() {
+ if (_operation == null) {
+ return null;
+ }
+ return _operation.getName();
+ }
+
+ /**
+ * Sets the operation as a string. For OR mapping only.
+ *
+ * @param aOperation
+ * Operation string.
+ */
+ protected void setOperationString(String aOperation) {
+ if (aOperation == null ) {
+ return;
+ }
+ try {
+ _operation = (Class<? extends Operation>)Class.forName(aOperation);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Unknown class '" + aOperation + "'");
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "IsaOperationCondition(operation=" + _operation.getName() + ")";
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+/**
+ * Represents an operation on a resource.
+ * An operation should contain no state to be persisted since only the name of the
+ * operation is persisted.
+ */
+public interface Operation {
+
+ /**
+ * Gets the name of the operation.
+ * @return Operation.
+ */
+ String getName();
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import org.wamblee.persistence.Persistent;
+
+/**
+ * Checks if an operation matches a condition.
+ */
+public interface OperationCondition extends Persistent {
+
+
+ /**
+ * Determines if the operation matches.
+ * @param aOperation Operation.
+ * @return True iff the operation matches.
+ */
+ boolean matches(Operation aOperation);
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+
+/**
+ * Utility to map between a list of operations and a string based
+ * on the names of the operations.
+ */
+public interface OperationRegistry {
+
+ /**
+ * Gets the supported operations for a given resource class.
+ * @param aResourceClass Resource class.
+ * @return Supported operations for that class.
+ */
+ Operation[] getOperations(Class aResourceClass);
+
+ /**
+ * Converts a number of operations to a string.
+ * @param aOperations Operations to convert.
+ * @return String representation of the allowed operations.
+ */
+ String encode(Operation[] aOperations);
+
+ /**
+ * Converts an operations string to an array of operations.
+ * @param aResourceClass Resource class.
+ * @param aOperationsString Operations string as returned by {@link #encode(Operation[])}.
+ * @return Operations array.
+ */
+ Operation[] decode(Class aResourceClass, String aOperationsString);
+
+ /**
+ * Converts an operations string to an array of operations.
+ * @param aOperationsString Operations string as returned by {@link #encode(Operation[])}.
+ * @return Operations array.
+ */
+ Operation[] decode(String aOperationsString);
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import org.wamblee.persistence.Persistent;
+
+/**
+ * Checks if a path satisfies a condition.
+ */
+public interface PathCondition extends Persistent {
+
+ /**
+ * Checks if the path matches the condition.
+ * @param aPath Path to match.
+ * @return True iff the path matches.
+ */
+ boolean matches(String aPath);
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+/**
+ * Represents a read operation on a resource.
+ */
+public class ReadOperation extends AllOperation {
+
+ private static final String OPERATION = "read";
+
+ /**
+ * Constructs the operation.
+ *
+ */
+ public ReadOperation() {
+ super(OPERATION);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import org.wamblee.persistence.AbstractPersistent;
+
+/**
+ * Condition to check whether a path matches a given regula expression.
+ */
+public class RegexpPathCondition extends AbstractPersistent implements PathCondition {
+
+ /**
+ * String the path must start with.
+ */
+ private String _pattern;
+
+ /**
+ * Constructs the condition.
+ * @param aPattern String the path must start with.
+ */
+ public RegexpPathCondition(String aPattern) {
+ _pattern = aPattern;
+ }
+
+ /**
+ * For OR mapping.
+ *
+ */
+ protected RegexpPathCondition() {
+ _pattern = null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.PathCondition#matches(java.lang.String)
+ */
+ public boolean matches(String aPath) {
+ return aPath.matches(_pattern);
+ }
+
+ /**
+ * @return Returns the _path.
+ */
+ protected String getPattern() {
+ return _pattern;
+ }
+
+ /**
+ * @param aPattern The _path to set.
+ */
+ protected void setPattern(String aPattern) {
+ _pattern = aPattern;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "RegexpCondition(pattern = '" + _pattern + "')";
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+
+/**
+ * Condition to check whether a path starts with a given string.
+ */
+public class StartsWithPathCondition extends RegexpPathCondition {
+
+ /**
+ * Constructs the condition.
+ * @param aPath String the path must start with.
+ */
+ public StartsWithPathCondition(String aPath) {
+ super( aPath + ".*");
+ }
+
+ /**
+ * For OR mapping.
+ *
+ */
+ protected StartsWithPathCondition() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "StartsWithPathCondition(pattern = '" + getPattern() + "')";
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import static org.wamblee.security.authorization.AuthorizationResult.DENIED;
+import static org.wamblee.security.authorization.AuthorizationResult.GRANTED;
+import static org.wamblee.security.authorization.AuthorizationResult.UNDECIDED;
+import static org.wamblee.security.authorization.AuthorizationResult.UNSUPPORTED_RESOURCE;
+
+import org.apache.log4j.Logger;
+import org.wamblee.persistence.AbstractPersistent;
+import org.wamblee.usermgt.User;
+
+/**
+ * Utility base class for implementation of authentication rules based on the
+ * <ul>
+ * <li> The path of the resource. To obtain the path of a resource, subclasses
+ * must implement {@link #getResourcePath(Object)}.
+ * Whether a path is appropriate is determined by a
+ * {@link org.wamblee.security.authorization.PathCondition}.
+ * </li>
+ * <li> The user identity with which the resource is accessed.
+ * Whether a user is appropriate is determined by
+ * a {@link org.wamblee.security.authorization.UserCondition}.
+ * </li>
+ * <li> The operation that is requested.
+ * Whether the operation is appropriate is determined by a
+ * {@link org.wamblee.security.authorization.OperationCondition}.
+ * </li>
+ * </ul>
+ *
+ * In case all three conditions match, the condition returns the configured
+ * result passed at construction (GRANTED or DENIED). If the resource is not
+ * of the specified type, the result is UNSUPPORTED_RESOURCE, otherwise, the
+ * result is UNDECIDED.
+ */
+public abstract class UrlAuthorizationRule extends AbstractPersistent implements AuthorizationRule {
+
+ private static final Logger LOGGER = Logger.getLogger(UrlAuthorizationRule.class);
+
+ /**
+ * Result that the rule will return in case there is a match.
+ */
+ private AuthorizationResult _result;
+
+ /**
+ * A condition which specifies which users the rule is for.
+ */
+ private UserCondition _userCondition;
+
+ /**
+ * Path the rule applies for.
+ */
+ private PathCondition _pathCondition;
+
+ /**
+ * Resource class that the rule applies for.
+ */
+ private Class _resourceClass;
+
+ /**
+ * Operation that this rule is for.
+ */
+ private OperationCondition _operationCondition;
+
+ /**
+ * Constructs an authorization rule.
+ * IF the group and path match, then the provided result will be returned.
+ * @param aResult Result of the authorization when the path and group match.
+ * @param aUserCondition Condition to match users.
+ * @param aPathCondition Condition to match paths with.
+ * @param aResourceClass Supported resource class this is for.
+ * @param aOperationCondition Condition to match the operation with.
+ */
+ protected UrlAuthorizationRule(AuthorizationResult aResult, UserCondition aUserCondition,
+ PathCondition aPathCondition, Class aResourceClass, OperationCondition aOperationCondition) {
+ if ( !aResult.equals(GRANTED) && !aResult.equals(DENIED)) {
+ throw new IllegalArgumentException("Only GRANTED or DENIED may be used: " + aResult);
+ }
+ _result = aResult;
+ _userCondition = aUserCondition;
+ _pathCondition = aPathCondition;
+ _resourceClass = aResourceClass;
+ _operationCondition = aOperationCondition;
+ }
+
+ /**
+ * For OR mapping.
+ *
+ */
+ protected UrlAuthorizationRule(Class aResourceClass) {
+ _result = null;
+ _userCondition = null;
+ _pathCondition = null;
+ _resourceClass = aResourceClass;
+ _operationCondition = null;
+ }
+
+ /**
+ * For OR mapping.
+ *
+ */
+ protected UrlAuthorizationRule() {
+ _result = null;
+ _userCondition = null;
+ _pathCondition = null;
+ _resourceClass = null;
+ _operationCondition = null;
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.authorization.AuthorizationRule#getSupportedTypes()
+ */
+ public Class[] getSupportedTypes() {
+ return new Class[] { _resourceClass };
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.authorization.AuthorizationRule#isAllowed(java.lang.Object,
+ * org.wamblee.security.authorization.Operation)
+ */
+ public AuthorizationResult isAllowed(Object aResource, Operation anOperation, User aUser) {
+ if ( ! _resourceClass.isInstance(aResource)) {
+ return UNSUPPORTED_RESOURCE;
+ }
+ String path = getResourcePath(aResource);
+ return isAllowed(path, anOperation, aUser);
+ }
+
+ /**
+ * Determines if the operation is allowed on the resource.
+ * @param aPath Path of the resource.
+ * @param aOperation Operation to be done.
+ * @param aUser Currently logged in user or null if no user is logged in.
+ * @return Authorization result,
+ */
+ protected AuthorizationResult isAllowed(String aPath, Operation aOperation, User aUser) {
+ if ( ! _pathCondition.matches(aPath) ) {
+ return UNDECIDED;
+ }
+ if ( !_operationCondition.matches(aOperation) ) {
+ return UNDECIDED;
+ }
+ if ( !_userCondition.matches(aUser)) {
+ return UNDECIDED;
+ }
+ return _result;
+ }
+
+ /**
+ * Gets the path of the resource.
+ * @param aResource Resource, guaranteed to be an instance of
+ * {@link #_resourceClass}.
+ * @return Path of the resource.
+ */
+ protected abstract String getResourcePath(Object aResource);
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "UrlAUthorizationRule(result = " + _result +
+ ", pathCondition = " + _pathCondition +
+ ", userCondition = " + _userCondition +
+ ", resourceClass = " + _resourceClass + ")";
+ }
+
+ /**
+ * Gets the authorization result for OR mapping.
+ * @return Result.
+ */
+ protected String getAuthorizationResultString() {
+ if ( _result == null ) {
+ return null;
+ }
+ return _result.toString();
+ }
+
+ /**
+ * Sets the authorization result, for OR mapping.
+ * @param aResult Result.
+ */
+ protected void setAuthorizationResultString(String aResult) {
+ _result = AuthorizationResult.valueOf(aResult);
+ }
+
+ protected String getResourceClassName() {
+ if ( _resourceClass == null ) {
+ return "";
+ }
+ return _resourceClass.getName();
+ }
+
+ protected void setResourceClassName(String aResourceClass) {
+ try {
+ _resourceClass = Class.forName(aResourceClass);
+ } catch (ClassNotFoundException e) {
+ LOGGER.error("Cannot find resource class '" + aResourceClass + "'", e);
+ throw new IllegalArgumentException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * @return Returns the _operationCondition.
+ */
+ public OperationCondition getOperationCondition() {
+ return _operationCondition;
+ }
+
+ /**
+ * @param aOperationCondition The _operationCondition to set.
+ */
+ protected void setOperationCondition(OperationCondition aOperationCondition) {
+ _operationCondition = aOperationCondition;
+ }
+
+ /**
+ * @return Returns the _pathCondition.
+ */
+ public PathCondition getPathCondition() {
+ return _pathCondition;
+ }
+
+ /**
+ * @param aPathCondition The _pathCondition to set.
+ */
+ protected void setPathCondition(PathCondition aPathCondition) {
+ _pathCondition = aPathCondition;
+ }
+
+ /**
+ * @return Returns the _userCondition.
+ */
+ public UserCondition getUserCondition() {
+ return _userCondition;
+ }
+
+ /**
+ * @param aUserCondition The _userCondition to set.
+ */
+ protected void setUserCondition(UserCondition aUserCondition) {
+ _userCondition = aUserCondition;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import org.wamblee.persistence.Persistent;
+import org.wamblee.usermgt.User;
+
+/**
+ * Condition used to match a user against a specified set of users.
+ */
+public interface UserCondition extends Persistent {
+
+ /**
+ * Determines if the condition matches.
+ * @param aUser user to check.
+ * @return True if the condition matches, false otherwise.
+ */
+ boolean matches(User aUser);
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+/**
+ * Represents a write operation on a resource.
+ */
+public class WriteOperation extends AllOperation {
+
+ private static final String OPERATION = "write";
+
+ /**
+ * Constructs the operation.
+ *
+ */
+ public WriteOperation() {
+ super(OPERATION);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization.hibernate;
+
+import java.util.List;
+
+import org.springframework.orm.hibernate3.HibernateTemplate;
+import org.wamblee.persistence.AbstractPersistent;
+import org.wamblee.persistence.hibernate.HibernateSupport;
+import org.wamblee.security.authorization.AuthorizationRule;
+import org.wamblee.security.authorization.AuthorizationService;
+import org.wamblee.security.authorization.DefaultAuthorizationService;
+import org.wamblee.security.authorization.Operation;
+import org.wamblee.usermgt.UserAccessor;
+
+/**
+ * Authorization service with persistent storage.
+ * This is a wrapper for {@link org.wamblee.security.authorization.DefaultAuthorizationService}
+ * which refreshes the state of the service at certain time intervals.
+ */
+public class PersistentAuthorizationService extends AbstractPersistent
+ implements AuthorizationService {
+
+ /**
+ * Name of query to find the service by name.
+ */
+ private static final String FIND_QUERY = "findAuthorizationServiceByName";
+
+ /**
+ * Name of the query parameter for the service name.
+ */
+ private static final String NAME_PARAM = "name";
+
+ /**
+ * Authorization service to use.
+ */
+ private DefaultAuthorizationService _service;
+
+ /**
+ * Hibernate template to use.
+ */
+ private HibernateTemplate _template;
+
+ /**
+ * User accessor.
+ */
+ private UserAccessor _userAccessor;
+
+ /**
+ * Name of the service.
+ */
+ private String _name;
+
+ /**
+ * Refresh interval in milliseconds.
+ */
+ private final long _refreshInterval;
+
+ /**
+ * Last refresh time.
+ */
+ private long _lastRefreshTime;
+
+ /**
+ * Constructs the persistent service.
+ *
+ * @param aName
+ * Name of the service.
+ * @param aTemplate
+ * Hibernate template for hibernate usage.
+ * @param aAccessor
+ * User accessor.
+ * @param aRefresh
+ * Whether or not to refresh the state of the service at the
+ * start of every operation.
+ */
+ public PersistentAuthorizationService(String aName,
+ HibernateTemplate aTemplate, UserAccessor aAccessor,
+ long aRefreshInterval) {
+ _template = aTemplate;
+ _refreshInterval = aRefreshInterval;
+ _lastRefreshTime = System.currentTimeMillis();
+ _userAccessor = aAccessor;
+ _name = aName;
+ }
+
+ /**
+ * Initialize service if needed.
+ */
+ private void initialize() {
+ if (_service == null) {
+ List<DefaultAuthorizationService> result = _template
+ .findByNamedQueryAndNamedParam(FIND_QUERY, NAME_PARAM,
+ _name);
+
+ if (result.size() > 1) {
+ throw new IllegalArgumentException(
+ "Returned more than one service for name '" + _name
+ + "' (" + result.size() + ")");
+ }
+
+ if (result.size() == 0) {
+ _service = new DefaultAuthorizationService(_userAccessor, _name);
+ _template.persist(_service);
+ } else {
+ _service = result.get(0);
+ _service.setUserAccessor(_userAccessor);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.authorization.AuthorizationService#isAllowed(java.lang.Object,
+ * org.wamblee.security.authorization.Operation)
+ */
+ public boolean isAllowed(Object aResource, Operation aOperation) {
+ initialize();
+ refresh();
+ return _service.isAllowed(aResource, aOperation);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.AuthorizationService#check(T, org.wamblee.security.authorization.Operation)
+ */
+ public <T> T check(T aResource, Operation aOperation) {
+ initialize();
+ refresh();
+ return _service.check(aResource, aOperation);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.authorization.AuthorizationService#getRules()
+ */
+ public AuthorizationRule[] getRules() {
+ initialize();
+ refresh();
+ return _service.getRules();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.authorization.AuthorizationService#appendRule(org.wamblee.security.authorization.AuthorizationRule)
+ */
+ public void appendRule(AuthorizationRule aRule) {
+ initialize();
+ refresh();
+ _service.appendRule(aRule);
+ save();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.authorization.AuthorizationService#removeRule(int)
+ */
+ public void removeRule(int aIndex) {
+ initialize();
+ refresh();
+ _service.removeRule(aIndex);
+ save();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.authorization.AuthorizationService#insertRuleAfter(int,
+ * org.wamblee.security.authorization.AuthorizationRule)
+ */
+ public void insertRuleAfter(int aIndex, AuthorizationRule aRule) {
+ initialize();
+ refresh();
+ _service.insertRuleAfter(aIndex, aRule);
+ save();
+ }
+
+ /**
+ * Refreshes the state of the service through hibernate.
+ *
+ */
+ private synchronized void refresh() {
+ long time = System.currentTimeMillis();
+ if ( time - _lastRefreshTime > _refreshInterval ) {
+ _template.refresh(_service);
+ _lastRefreshTime = time;
+ }
+ }
+
+ /**
+ * Saves any changes to the service state if necessary.
+ */
+ private void save() {
+ HibernateSupport.merge(_template, _service);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.encryption;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import org.apache.commons.codec.binary.Hex;
+
+/**
+ * MD5 Hex encoder.
+ */
+public class Md5HexMessageDigester implements MessageDigester {
+
+ /**
+ * Constructs the message digester.
+ *
+ */
+ public Md5HexMessageDigester() {
+ // Empty
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.security.MessageDigester#hash(java.lang.String)
+ */
+ public String hash(String aValue) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ byte[] result = digest.digest(aValue.getBytes());
+ char[] charResult = new Hex().encodeHex(result);
+ return new String(charResult);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException("MD5 not supported????");
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.encryption;
+
+/**
+ * Utility class that encapsulates a message digest method.
+ */
+public interface MessageDigester {
+
+ /**
+ * Computes a message digest for a value and encodes it in some way.
+ * @param aValue Value to compute digest for.
+ * @return Encoded digest.
+ */
+ String hash(String aValue);
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import static org.wamblee.usermgt.UserMgtException.Reason.DUPLICATE_USER;
+
+import org.wamblee.security.encryption.MessageDigester;
+
+/**
+ * User set base class.
+ */
+public abstract class AbstractUserSet implements UserSet {
+
+ /**
+ * Password validator.
+ */
+ private NameValidator _passwordValidator;
+
+ /**
+ * Password encoder.
+ */
+ private MessageDigester _passwordEncoder;
+
+
+ protected AbstractUserSet(NameValidator aPasswordValidator,
+ MessageDigester aPasswordEncoder) {
+ _passwordValidator = aPasswordValidator;
+ _passwordEncoder = aPasswordEncoder;
+ }
+
+ /**
+ * Sets the password validtor and encoder in the user.
+ * @param aUser User.
+ */
+ protected void setPasswordInfo(User aUser) {
+ aUser.setPasswordValidator(_passwordValidator);
+ aUser.setPasswordEncoder(_passwordEncoder);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.UserSet#createUser(java.lang.String, java.lang.String, org.wamblee.usermgt.Group)
+ */
+ public User createUser(String aUsername, String aPassword, Group aGroup) throws UserMgtException {
+ User user = new User(aUsername, aPassword, aGroup, _passwordValidator, _passwordEncoder);
+ if (contains(user)) {
+ throw new UserMgtException(DUPLICATE_USER, user);
+ }
+ add(user);
+ return user;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.io.Serializable;
+
+import org.wamblee.persistence.AbstractPersistent;
+
+/**
+ * Represents a group.
+ */
+public class Group extends AbstractPersistent implements Serializable, Comparable {
+
+ /**
+ * Group name.
+ */
+ private String _name;
+
+ /**
+ * Constructs the group.
+ * @param aName
+ */
+ Group(String aName) {
+ super();
+ _name = aName;
+ }
+
+ public Group(Group aGroup) {
+ super(aGroup);
+ _name = aGroup._name;
+ }
+
+ protected Group() {
+ super();
+ _name = null;
+ }
+
+ /**
+ * Gets the name of the group.
+ * @return Group name.
+ */
+ public String getName() {
+ return _name;
+ }
+
+ /**
+ * Sets the group name.
+ * @param aName Group name.
+ */
+ void setName(String aName) {
+ _name = aName;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object aGroup) {
+ if ( !( aGroup instanceof Group )) {
+ return false;
+ }
+ return _name.equals(((Group)aGroup)._name);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return _name.hashCode();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(T)
+ */
+ public int compareTo(Object aGroup) {
+ return _name.compareTo(((Group)aGroup)._name);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "Group(pk = " + getPrimaryKey() + ", name=" + _name + ")";
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.util.Set;
+
+/**
+ * Represents a set of groups. A typical implemnetation would be, a readonly implementation
+ * defined in a configuration file or a list of groups defined in a database.
+ */
+public interface GroupSet {
+
+ /**
+ * Must be called when the group has been modified to notify the group set.
+ * @param aGroup Group that was modified.
+ */
+ void groupModified(Group aGroup);
+
+ /**
+ * Finds the group by name.
+ * @param aName Group name.
+ * @return Group or null if not found.
+ */
+ Group find(String aName);
+
+ /**
+ * Determines if the group exists.
+ * @param aGroup Group.
+ * @return True iff the group exists.
+ */
+ boolean contains(Group aGroup);
+
+ /**
+ * Adds a group. If the group already exists, the existing group set
+ * is left unchanged.
+ * @param aGroup Group.
+ */
+ boolean add(Group aGroup);
+
+ /**
+ * Removes a group. If the group does not exist, this method is a no-op.
+ * @param aGroup Group to remove.
+ * @return True if the group was removed, false otherwise.
+ */
+ boolean remove(Group aGroup);
+
+ /**
+ * Returns the current groups.
+ * @return Groups.
+ */
+ Set<Group> list();
+
+ /**
+ * @return The number of groups.
+ */
+ int size();
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * In-memory group set implementation.
+ */
+public class InMemoryGroupSet implements GroupSet {
+
+ /**
+ * Groups.
+ */
+ private Set<Group> _groups;
+
+ /**
+ * Constructs an empty group set.
+ */
+ public InMemoryGroupSet() {
+ _groups = new TreeSet<Group>();
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#groupModified(org.wamblee.usermgt.Group)
+ */
+ public void groupModified(Group aGroup) {
+ _groups.remove(aGroup);
+ _groups.add(aGroup);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#find(java.lang.String)
+ */
+ public Group find(String aName) {
+ for (Group group: _groups) {
+ if ( group.getName().equals(aName)) {
+ return new Group(group);
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#contains(org.wamblee.usermgt.Group)
+ */
+ public boolean contains(Group aGroup) {
+ return _groups.contains(aGroup);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#add(org.wamblee.usermgt.Group)
+ */
+ public boolean add(Group aGroup) {
+ return _groups.add(aGroup);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#remove(org.wamblee.usermgt.Group)
+ */
+ public boolean remove(Group aGroup) {
+ return _groups.remove(aGroup);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#list()
+ */
+ public Set<Group> list() {
+ Set<Group> list = new TreeSet<Group>();
+ for (Group group: _groups) {
+ list.add(new Group(group));
+ }
+ return list;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#size()
+ */
+ public int size() {
+ return _groups.size();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.wamblee.security.encryption.MessageDigester;
+
+/**
+ * In-memory user set.
+ */
+public class InMemoryUserSet extends AbstractUserSet {
+
+ /**
+ * Users. All users in this set have their password validator and encoder set.
+ */
+ private Set<User> _users;
+
+ /**
+ * Constructs an empty user set.
+ */
+ public InMemoryUserSet(NameValidator aPasswordValidator, MessageDigester aPasswordEncoder) {
+ super(aPasswordValidator, aPasswordEncoder);
+ _users = new TreeSet<User>();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#userModified(org.wamblee.usermgt.User)
+ */
+ public void userModified(User aUser) {
+ _users.remove(aUser);
+ setPasswordInfo(aUser);
+ _users.add(aUser);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#find(java.lang.String)
+ */
+ public User find(String aName) {
+ for (User user : _users) {
+ if (user.getName().equals(aName)) {
+ return new User(user);
+ }
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#add(org.wamblee.usermgt.User)
+ */
+ public boolean add(User aUser) {
+ setPasswordInfo(aUser);
+ return _users.add(aUser);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#contains(org.wamblee.usermgt.User)
+ */
+ public boolean contains(User aUser) {
+ return _users.contains(aUser);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#remove(org.wamblee.usermgt.User)
+ */
+ public boolean remove(User aUser) {
+ return _users.remove(aUser);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#list()
+ */
+ public Set<User> list() {
+ Set<User> list = new TreeSet<User>();
+ for (User user : _users) {
+ list.add(new User(user));
+ }
+ return list;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#list(org.wamblee.usermgt.Group)
+ */
+ public Set<User> list(Group aGroup) {
+ Set<User> result = new TreeSet<User>();
+ for (User user : _users) {
+ if (user.getGroups().contains(aGroup)) {
+ result.add(new User(user));
+ }
+ }
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.UserSet#size()
+ */
+ public int size() {
+ return _users.size();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.security.AccessController;
+import java.security.Principal;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+
+/**
+ * Implementation of the user accessor that retrieves user information
+ * from JAAS.
+ */
+public class JaasUserAccessor implements UserAccessor {
+
+ /**
+ * User administration to use.
+ */
+ private UserAdministration _admin;
+
+ /**
+ * Class of the JAAS user principal.
+ */
+ private Class _userPrincipalClass;
+
+ /**
+ * Constructs user accessor.
+ * @param aAdmin User administration.
+ * @param aUserClassName Class name of the user principal.
+ */
+ public JaasUserAccessor(UserAdministration aAdmin, String aUserClassName) {
+ _admin = aAdmin;
+ try {
+ _userPrincipalClass = Class.forName(aUserClassName);
+ if ( !Principal.class.isAssignableFrom(_userPrincipalClass)) {
+ throw new IllegalArgumentException("Specified class '" + aUserClassName + "' is not a subclass of '" +
+ Principal.class.getName());
+ }
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAccessor#getCurrentUser()
+ */
+ public User getCurrentUser() {
+ Subject subject = Subject.getSubject(AccessController.getContext());
+ if (subject == null) {
+ return null;
+ }
+ Principal userPrincipal = getUserPrincipal(subject);
+
+ return _admin.getUser(userPrincipal.getName());
+ }
+
+ /**
+ * Gets the user principal from the subject.
+ * @param subject Subject.
+ * @return User principal.
+ * @throws IllegalArgumentException In case there is a duplicate principal or the principal was not found.
+ */
+ private Principal getUserPrincipal(Subject subject) {
+ Set<Principal> principals = subject.getPrincipals();
+ Principal userPrincipal = null;
+ for ( Principal principal: principals) {
+ if ( principal.getClass().equals(_userPrincipalClass)) {
+ if ( userPrincipal != null ) {
+ throw new IllegalArgumentException(
+ "Multiple principals for class '" + _userPrincipalClass + "', subject: " + subject);
+ }
+ userPrincipal = principal;
+ }
+ }
+ if ( userPrincipal == null ) {
+ throw new IllegalArgumentException(
+ "No user principal found for class '" + _userPrincipalClass + "', subject: " + subject);
+ }
+ return userPrincipal;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+/**
+ * Validator of names.
+ */
+public interface NameValidator {
+
+ /**
+ * Validates a name.
+ * @param aName Name
+ * @throws UserMgtException In case the name is invalid.
+ */
+ void validate(String aName) throws UserMgtException;
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import org.wamblee.usermgt.UserMgtException.Reason;
+
+/**
+ * Validation of names based on a regular expression.
+ */
+public class RegexpNameValidator implements NameValidator {
+
+ /**
+ * Convenience pattern for an id.
+ */
+ public static final String ID_PATTERN = "[a-zA-Z]+[a-zA-Z0-9]*";
+
+ /**
+ * Convenience pattern for a password consisting of at least 6 characters.
+ */
+ public static final String PASSWORD_PATTERN = ".{6}.*";
+
+ /**
+ * Pattern to use.
+ */
+ private String _pattern;
+
+ /**
+ * Reason to use when validation fails.
+ */
+ private Reason _reason;
+
+ /**
+ * Message to report.
+ */
+ private String _message;
+
+ /**
+ * Validates a regular expression.
+ * @param aPattern Pattern that names must comply to.
+ * @param aReason Reason to report when validation fails.
+ * @param aMessage Message to report.
+ */
+ public RegexpNameValidator(String aPattern, Reason aReason, String aMessage) {
+ _pattern = aPattern;
+ _reason = aReason;
+ _message = aMessage;
+ }
+
+ /**
+ * Convenience constructor with all string parameters. Useful for configuration
+ * in Spring.
+ * @param aPattern Pattern to use.
+ * @param aReason Reason.
+ * @param aMessage Message.
+ */
+ public RegexpNameValidator(String aPattern, String aReason, String aMessage) {
+ this(aPattern, Reason.valueOf(aReason), aMessage);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.NameValidator#validate(java.lang.String)
+ */
+ public void validate(String aName) throws UserMgtException {
+ if ( !aName.matches(_pattern)) {
+ throw new UserMgtException(_reason, _message);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.io.Serializable;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.wamblee.persistence.AbstractPersistent;
+import org.wamblee.security.encryption.MessageDigester;
+import org.wamblee.usermgt.UserMgtException.Reason;
+
+/**
+ * Represents a user.
+ * The methods for managing the groups of the user have package scope.
+ * Managing the groups of the user should be done through the
+ * {@link org.wamblee.usermgt.UserAdministration} interface.
+ */
+public class User extends AbstractPersistent implements Serializable, Comparable {
+
+ /**
+ * User name.
+ */
+ private String _name;
+
+ /**
+ * Password.
+ */
+ private String _password;
+
+ /**
+ * Groups the user belongs to.
+ */
+ private Set<Group> _groups;
+
+ /**
+ * Password validator.
+ */
+ private NameValidator _passwordValidator;
+
+ /**
+ * Password encoder.
+ */
+ private MessageDigester _passwordEncoder;
+
+ /**
+ * Constructs the user.
+ * @param aName User name.
+ * @param aPassword Password.
+ * @param aGroup Group the user belongs to.
+ */
+ User(String aName, String aPassword, Group aGroup, NameValidator aPasswordValidator,
+ MessageDigester aPasswordEncoder) throws UserMgtException {
+ super();
+ _name = aName;
+ aPasswordValidator.validate(aPassword);
+ _password = aPasswordEncoder.hash(aPassword);
+ _groups = new TreeSet<Group>();
+ _groups.add(aGroup);
+ _passwordValidator = aPasswordValidator;
+ _passwordEncoder = aPasswordEncoder;
+ }
+
+ public User(User aUser) {
+ super(aUser);
+ _name = aUser._name;
+ _password = aUser._password;
+ _groups = new TreeSet<Group>();
+ for (Group group: aUser._groups) {
+ _groups.add(new Group(group));
+ }
+ _passwordValidator = aUser._passwordValidator;
+ _passwordEncoder = aUser._passwordEncoder;
+ }
+
+ User() {
+ super();
+ _name = null;
+ _password = null;
+ _groups = null;
+ _passwordValidator = null;
+ _passwordEncoder = null;
+ }
+
+ /**
+ * Sets the password validator.
+ * @param aPasswordValidator Validator.
+ */
+ public void setPasswordValidator(NameValidator aPasswordValidator) {
+ _passwordValidator = aPasswordValidator;
+ }
+
+ /**
+ * Sets the password encoder.
+ * @param aPasswordEncoder Encoder.
+ */
+ public void setPasswordEncoder(MessageDigester aPasswordEncoder) {
+ _passwordEncoder = aPasswordEncoder;
+ }
+
+ /**
+ * @return Returns the _password.
+ */
+ String getPassword() {
+ return _password;
+ }
+
+ /**
+ * Checks the password.
+ * @param aPassword Password to check.
+ * @throws UserMgtException In case the password is incorrect.
+ */
+ public void checkPassword(String aPassword) throws UserMgtException {
+ String encoded = _passwordEncoder.hash(aPassword);
+ if ( !_password.equals(encoded) ) {
+ throw new UserMgtException(Reason.INVALID_PASSWORD, this);
+ }
+ }
+
+ /**
+ * Changes the password.
+ * @param aOldPassword Old password.
+ * @param aNewPassword New password.
+ * @throws UserMgtException In case the old password is incorrect.
+ */
+ public void changePassword(String aOldPassword, String aNewPassword) throws UserMgtException {
+ checkPassword(aOldPassword);
+ _passwordValidator.validate(aNewPassword);
+ setPassword(aNewPassword);
+ }
+
+ /**
+ * @param aPassword
+ * The password to set.
+ */
+ public void setPassword(String aPassword) throws UserMgtException {
+ _passwordValidator.validate(aPassword);
+ _password = _passwordEncoder.hash(aPassword);
+ }
+
+ /**
+ * For OR mapping.
+ * @return Password.
+ */
+ protected String getPasswordString() {
+ return _password;
+ }
+
+ /**
+ * For OR mapping.
+ * @param aPassword Password.
+ */
+ protected void setPasswordString(String aPassword) {
+ _password = aPassword;
+ }
+
+ /**
+ * @return Returns the _user.
+ */
+ public String getName() {
+ return _name;
+ }
+
+ /**
+ * @param aName
+ * The username to set.
+ */
+ void setName(String aName) {
+ _name = aName;
+ }
+
+ /**
+ * Gets the groups the user belongs to.
+ * @return Groups.
+ */
+ public Set<Group> getGroups() {
+ Set<Group> result = new TreeSet<Group>();
+ result.addAll(_groups);
+ return result;
+ }
+
+ /**
+ * Checks whether the user belongs to the given group.
+ * @param aGroup Group.
+ * @return True if the user belongs to the group.
+ */
+ public boolean isInGroup(Group aGroup) {
+ return _groups.contains(aGroup);
+ }
+
+ /**
+ * Checks whether the user belongs to the given group.
+ * @param aGroup Group.
+ * @return True if the user belongs to the group.
+ */
+ public boolean isInGroup(String aGroup) {
+ return _groups.contains(new Group(aGroup));
+ }
+
+ /**
+ * Gets the group set. For OR mapping.
+ * @return set of groups.
+ */
+ Set<Group> getGroupSet() {
+ return _groups;
+ }
+
+ /**
+ * Sets the groups the user belongs to, for OR mapping.
+ * @param aGroups Groups.
+ */
+ void setGroupSet(Set<Group> aGroups) {
+ _groups = aGroups;
+ }
+
+ /**
+ * Adds the user to a group.
+ * @param aGroup Group to add the user to.
+ * @throws UserMgtException In case the user already belongs to the group.
+ */
+ void addGroup(Group aGroup) throws UserMgtException {
+ if (_groups.contains(aGroup)) {
+ throw new UserMgtException(Reason.USER_ALREADY_IN_GROUP, aGroup);
+ }
+ _groups.add(aGroup);
+ }
+
+ /**
+ * Removes the user from a group.
+ * @param aGroup Group.
+ * @throws UserMgtException In case the user does not belong to the group.
+ */
+ void removeGroup(Group aGroup) throws UserMgtException {
+ if (!_groups.contains(aGroup)) {
+ throw new UserMgtException(Reason.USER_NOT_IN_GROUP, this, aGroup);
+ }
+ if ( _groups.size() == 1 ) {
+ throw new UserMgtException(Reason.USER_MUST_BE_IN_A_GROUP, this, aGroup);
+ }
+ _groups.remove(aGroup);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object aUser) {
+ if ( !(aUser instanceof User)) {
+ return false;
+ }
+ User user = (User)aUser;
+ return _name.equals(user._name);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return _name.hashCode();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ String result = "User(name=" + _name + ", password=" + _password;
+ for (Group group: _groups) {
+ result += ", group=" + group;
+ }
+ return result + ")";
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(T)
+ */
+ public int compareTo(Object aUser) {
+ return _name.compareTo(((User)aUser)._name);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+/**
+ * Interface for accessing the currently logged in user.
+ */
+public interface UserAccessor {
+ /**
+ * Gets the current user.
+ * @return Currently logged in user or null if no user is found.
+ */
+ User getCurrentUser();
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.security.NoSuchAlgorithmException;
+
+import org.apache.log4j.Logger;
+
+/**
+ * User administration initializer. It populates the user administration with a
+ * number of groups and users but only in case no users exist.
+ */
+public class UserAdminInitializer {
+
+ private static final Logger LOGGER = Logger.getLogger(UserAdminInitializer.class);
+
+ /**
+ * Initializes the user administration in case no users are present.
+ *
+ */
+ public UserAdminInitializer(UserAdministration aAdmin, String[] aUsers,
+ String[] aGroups, String[] aPasswords) throws UserMgtException, NoSuchAlgorithmException {
+ if (aUsers.length != aGroups.length
+ || aUsers.length != aPasswords.length) {
+ throw new IllegalArgumentException(
+ "Array sizes for users, groups, and passwords differ: "
+ + aUsers.length + "," + aGroups.length + ","
+ + aPasswords.length);
+
+ }
+ if (aAdmin.getUserCount() == 0) {
+ initialize(aAdmin, aUsers, aGroups, aPasswords);
+ }
+
+ }
+
+ /**
+ * Adds the specified users and groups to the user administration.
+ * @param aAdmin User administration.
+ * @param aUsers Users.
+ * @param aGroups Groups.
+ * @param aPasswords Passwords.
+ * @throws UserMgtException In case of a problem creating users or groups.
+ */
+ private void initialize(UserAdministration aAdmin, String[] aUsers,
+ String[] aGroups, String[] aPasswords) throws UserMgtException {
+ for (int i = 0; i < aUsers.length; i++) {
+ String user = aUsers[i];
+ String group = aGroups[i];
+ String password = aPasswords[i];
+
+ if (aAdmin.getUser(user) == null) {
+ // must create user.
+ Group groupObj = aAdmin.getGroup(group);
+ if (groupObj == null) {
+ // must create group
+ LOGGER.info("Creating group: " + group);
+ groupObj = aAdmin.createGroup(group);
+ }
+ assert groupObj != null;
+
+ LOGGER.info("Creating user: " + user + " password: " + password);
+ aAdmin.createUser(user, password, groupObj);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.util.Set;
+
+/**
+ * Interface for user administration. Manages the users and groups.
+ */
+public interface UserAdministration {
+
+ /**
+ * Creates a new user.
+ * @param aUser Username.
+ * @param aPassword Password.
+ * @param aGroup Group.
+ * @return User.
+ * @throws UserMgtException In case there is a conflict with an existing user.
+ */
+ User createUser(String aUser, String aPassword, Group aGroup) throws UserMgtException;
+
+ /**
+ * Creates a new group.
+ * @param aName Group name.
+ * @return Group
+ * @throws UserMgtException In case there is a conflict with an existing group.
+ */
+ Group createGroup(String aName) throws UserMgtException;
+
+ /**
+ * @return Number of users.
+ */
+ int getUserCount();
+
+ /**
+ * @return Number of groups.
+ */
+ int getGroupCount();
+
+ /**
+ * Must be called when the user is modified.
+ * @param aUser User.
+ */
+ void userModified(User aUser);
+
+ /**
+ * Must be called when the group is modified.
+ * @param aGroup Group.
+ */
+ void groupModified(Group aGroup);
+
+ /**
+ * Gets the user for a given name.
+ * @param aName User name.
+ * @return User or null if not found.
+ */
+ User getUser(String aName);
+
+ /**
+ * Gets the group for a given group name.
+ * @param aName Group name.
+ * @return Group or null if not found.
+ */
+ Group getGroup(String aName);
+
+ /**
+ * Get the users.
+ * @return All known users.
+ */
+ Set<User> getUsers();
+
+ /**
+ * Gets the users for a given group.
+ * @param aGroup Group.
+ * @return Set of users (always non-null).
+ */
+ Set<User> getUsers(Group aGroup);
+
+ /**
+ * Gets all known groups.
+ * @return Groups.
+ */
+ Set<Group> getGroups();
+
+ /**
+ * Renames a user.
+ * @param aUser User object for which user name must be changed.
+ * @param aUserName New user name.
+ * @throws UserMgtException In case the user is not known or the new user
+ * name is already in use by another user.
+ */
+ void renameUser(User aUser, String aUserName) throws UserMgtException;
+
+ /**
+ * Renames a group.
+ * @param aGroup Group to rename.
+ * @param aGroupName New name for the group.
+ * @throws UserMgtException In case the new group name is already used by
+ * another group of if the existing group is unknown.
+ */
+ void renameGroup(Group aGroup, String aGroupName) throws UserMgtException;
+
+ /**
+ * Removes the user.
+ * @param aUser User to remove.
+ * @throws UserMgtException In case the user does not exist.
+ */
+ void removeUser(User aUser) throws UserMgtException;
+
+ /**
+ * Removes the group.
+ * @param aGroup Group to remove.
+ * @throws UserMgtException In case there are still users that are in the given group.
+ */
+ void removeGroup(Group aGroup) throws UserMgtException;
+
+ /**
+ * Adds a user to a group.
+ * @param aUser User.
+ * @param aGroup Group.
+ * @throws UserMgtException In case the user or group or not known or if the user
+ * is already part of the group.
+ */
+ void addUserToGroup(User aUser, Group aGroup) throws UserMgtException;
+
+ /**
+ * Removes a user from a group.
+ * @param aUser User
+ * @param aGroup Group
+ * @throws UserMgtException In case the user or group are unknown or if the user
+ * is not part of the group.
+ */
+ void removeUserFromGroup(User aUser, Group aGroup) throws UserMgtException;
+}
+
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import static org.wamblee.usermgt.UserMgtException.Reason.DUPLICATE_GROUP;
+import static org.wamblee.usermgt.UserMgtException.Reason.DUPLICATE_USER;
+import static org.wamblee.usermgt.UserMgtException.Reason.GROUP_STILL_OCCUPIED;
+import static org.wamblee.usermgt.UserMgtException.Reason.TRIVIAL_RENAME;
+import static org.wamblee.usermgt.UserMgtException.Reason.UNKNOWN_GROUP;
+import static org.wamblee.usermgt.UserMgtException.Reason.UNKNOWN_USER;
+
+import java.util.Set;
+
+/**
+ * Administration of users and groups.
+ */
+public class UserAdministrationImpl implements UserAdministration {
+
+ /**
+ * All known users.
+ */
+ private UserSet _users;
+
+ /**
+ * All known groups.
+ */
+ private GroupSet _groups;
+
+ /**
+ * Validator for user names.
+ */
+ private NameValidator _userValidator;
+
+ /**
+ * Validator for group names.
+ */
+ private NameValidator _groupValidator;
+
+ /**
+ * Constructs empty user administration.
+ *
+ */
+ public UserAdministrationImpl(UserSet aUsers, GroupSet aGroups, NameValidator aUserValidator,
+ NameValidator aGroupValidator) {
+ _users = aUsers;
+ _groups = aGroups;
+ _userValidator = aUserValidator;
+ _groupValidator = aGroupValidator;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#createUser(java.lang.String,
+ * java.lang.String)
+ */
+ public User createUser(String aUser, String aPassword, Group aGroup)
+ throws UserMgtException {
+ _userValidator.validate(aUser);
+ checkGroup(aGroup);
+ User user = _users.createUser(aUser, aPassword, aGroup);
+ return new User(user);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#createGroup(java.lang.String)
+ */
+ public Group createGroup(String aName) throws UserMgtException {
+ _groupValidator.validate(aName);
+ Group group = new Group(aName);
+ if (_groups.contains(group)) {
+ throw new UserMgtException(DUPLICATE_GROUP, group);
+ }
+ _groups.add(group);
+ return new Group(group);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#userModified(org.wamblee.usermgt.User)
+ */
+ public void userModified(User aUser) {
+ _users.userModified(aUser);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#groupModified(org.wamblee.usermgt.Group)
+ */
+ public void groupModified(Group aGroup) {
+ _groups.groupModified(aGroup);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#getUser(java.lang.String)
+ */
+ public User getUser(String aName) {
+ return _users.find(aName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#getGroup(java.lang.String)
+ */
+ public Group getGroup(String aName) {
+ return _groups.find(aName);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#getUsers()
+ */
+ public Set<User> getUsers() {
+ return _users.list();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#getUsers(org.wamblee.usermgt.Group)
+ */
+ public Set<User> getUsers(Group aGroup) {
+ return _users.list(aGroup);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#getGroups()
+ */
+ public Set<Group> getGroups() {
+ return _groups.list();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#removeUser(org.wamblee.usermgt.User)
+ */
+ public void removeUser(User aUser) throws UserMgtException {
+ checkUser(aUser);
+ _users.remove(aUser);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#removeGroup(org.wamblee.usermgt.Group)
+ */
+ public void removeGroup(Group aGroup) throws UserMgtException {
+ checkGroup(aGroup);
+ if (getUsers(aGroup).size() > 0) {
+ throw new UserMgtException(GROUP_STILL_OCCUPIED, aGroup);
+ }
+ _groups.remove(aGroup);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#renameUser(org.wamblee.usermgt.User,
+ * java.lang.String)
+ */
+ public void renameUser(User aUser, String aUserName)
+ throws UserMgtException {
+ checkUser(aUser);
+ if (aUser.getName().equals(aUserName)) {
+ throw new UserMgtException(TRIVIAL_RENAME, aUser);
+ }
+ if (_users.find(aUserName) != null) {
+ throw new UserMgtException(DUPLICATE_USER, aUser);
+ }
+ _userValidator.validate(aUserName);
+ // we are modifying the user so we should re-insert it into the set
+ // after renaming it.
+ _users.remove(aUser);
+ aUser.setName(aUserName);
+ _users.add(aUser);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#renameGroup(org.wamblee.usermgt.Group,
+ * java.lang.String)
+ */
+ public void renameGroup(Group aGroup, String aGroupName)
+ throws UserMgtException {
+ checkGroup(aGroup);
+ if (aGroup.getName().equals(aGroupName)) {
+ throw new UserMgtException(TRIVIAL_RENAME, aGroup);
+ }
+ if (_groups.find(aGroupName) != null) {
+ throw new UserMgtException(DUPLICATE_GROUP, aGroup);
+ }
+ _groupValidator.validate(aGroupName);
+ // we are renaming the group so we should re-insert it into the set
+ // after renaming it.
+ _groups.remove(aGroup);
+ aGroup.setName(aGroupName);
+ _groups.add(aGroup);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#addUserToGroup(org.wamblee.usermgt.User,
+ * org.wamblee.usermgt.Group)
+ */
+ public void addUserToGroup(User aUser, Group aGroup)
+ throws UserMgtException {
+ checkUser(aUser);
+ checkGroup(aGroup);
+ aUser.addGroup(aGroup);
+ _users.userModified(aUser);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministration#removeUserFromGroup(org.wamblee.usermgt.User,
+ * org.wamblee.usermgt.Group)
+ */
+ public void removeUserFromGroup(User aUser, Group aGroup)
+ throws UserMgtException {
+ checkUser(aUser);
+ checkGroup(aGroup);
+ aUser.removeGroup(aGroup);
+ _users.userModified(aUser);
+ }
+
+ /**
+ * @param aUser
+ * @throws UserMgtException
+ */
+ private void checkUser(User aUser) throws UserMgtException {
+ if (!_users.contains(aUser)) {
+ throw new UserMgtException(UNKNOWN_USER, aUser);
+ }
+ }
+
+ /**
+ * @param aGroup
+ * @throws UserMgtException
+ */
+ private void checkGroup(Group aGroup) throws UserMgtException {
+ if (!_groups.contains(aGroup)) {
+ throw new UserMgtException(UNKNOWN_GROUP, aGroup);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.UserAdministration#getUserCount()
+ */
+ public int getUserCount() {
+ return _users.size();
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.UserAdministration#getGroupCount()
+ */
+ public int getGroupCount() {
+ return _groups.size();
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.util.EnumMap;
+
+/**
+ * User management exception.
+ */
+public class UserMgtException extends Exception {
+
+ static final long serialVersionUID = 5585349754997507529L;
+
+ /**
+ * Possible causes for the exception.
+ *
+ */
+ public enum Reason {
+ UNKNOWN_USER,
+ UNKNOWN_GROUP,
+ DUPLICATE_USER,
+ DUPLICATE_GROUP,
+ USER_ALREADY_IN_GROUP,
+ USER_NOT_IN_GROUP,
+ TRIVIAL_RENAME,
+ INVALID_PASSWORD,
+ GROUP_STILL_OCCUPIED,
+ USER_MUST_BE_IN_A_GROUP,
+ INVALID_USERNAME,
+ INVALID_GROUPNAME
+ }
+
+ /**
+ * Mapping of enum to exception message text.
+ */
+ private static final EnumMap<Reason,String> MESSAGES = new EnumMap<Reason,String>(Reason.class);
+
+ static {
+ MESSAGES.put(Reason.UNKNOWN_USER, "Unknown user");
+ MESSAGES.put(Reason.UNKNOWN_GROUP, "Unknown group");
+ MESSAGES.put(Reason.DUPLICATE_USER, "Duplicate user");
+ MESSAGES.put(Reason.DUPLICATE_GROUP, "Duplicate group");
+ MESSAGES.put(Reason.USER_ALREADY_IN_GROUP, "User already in group");
+ MESSAGES.put(Reason.USER_NOT_IN_GROUP, "User not in group");
+ MESSAGES.put(Reason.TRIVIAL_RENAME, "Trivial rename");
+ MESSAGES.put(Reason.INVALID_PASSWORD, "Invalid password");
+ MESSAGES.put(Reason.GROUP_STILL_OCCUPIED, "Group still occupied");
+ MESSAGES.put(Reason.USER_MUST_BE_IN_A_GROUP, "User must be in at least one group");
+ MESSAGES.put(Reason.INVALID_USERNAME, "Invalid user name");
+ MESSAGES.put(Reason.INVALID_GROUPNAME, "Invalid group name");
+ }
+
+ /**
+ * Cause of the exception.
+ */
+ private Reason _cause;
+
+ /**
+ * User or null if no user is relevant for the problem.
+ */
+ private User _user;
+
+ /**
+ * Group or null if no group is relevant for the problem.
+ */
+ private Group _group;
+
+ public UserMgtException(Reason aCause, String aMessage) {
+ super(MESSAGES.get(aCause) + ": " + aMessage);
+ _cause = aCause;
+ }
+
+ public UserMgtException(Reason aCause, User aUser) {
+ this(aCause, "for user '" + aUser.getName() + "'");
+ _user = aUser;
+ }
+
+ public UserMgtException(Reason aCause, Group aGroup) {
+ this(aCause, "for group '" + aGroup.getName() + "'");
+ _group = aGroup;
+ }
+
+ public UserMgtException(Reason aCause, User aUser, Group aGroup) {
+ this(aCause, "for user '" + aUser.getName() + "' and group '" + aGroup.getName() + "'");
+ _user = aUser;
+ _group = aGroup;
+ }
+
+ /**
+ * Gets the cause of the problem.
+ * @return Cause.
+ */
+ public Reason getReason() {
+ return _cause;
+ }
+
+ /**
+ * Gets the user for which the problem occurred.
+ * @return User or null if not applicable.
+ */
+ public User getUser() {
+ return _user;
+ }
+
+ /**
+ * Gets the group for which the problem occured.
+ * @return Group or null if not applicable.
+ */
+ public Group getGroup() {
+ return _group;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.util.Set;
+
+/**
+ * Represents a set of users.
+ * Typical implementations would be an implementation based on a static configuration file or
+ * an implementation backed by a database.
+ */
+public interface UserSet {
+
+ /**
+ * Creates a user.
+ * @param aUsername User name.
+ * @param aPassword Password.
+ * @param aGroup Group.
+ * @return New user.
+ * @throws UserMgtException In case the user cannot be created.
+ */
+ User createUser(String aUsername, String aPassword, Group aGroup) throws UserMgtException;
+
+ /**
+ * Must be called whenever a user object has been modified to notify the
+ * user set.
+ * @param aUser Modified user.
+ */
+ void userModified(User aUser);
+
+ /**
+ * Finds user.
+ * @param aName Username.
+ * @return User or null if not found.
+ */
+ User find(String aName);
+
+ /**
+ * Checks if a user exists.
+ * @param aUser User.
+ * @return True iff the user exists.
+ */
+ boolean contains(User aUser);
+
+ /**
+ * Adds a user. If the user already exists, the user details are updated with that
+ * of the specified user object.
+ * @param aUser User to add.
+ */
+ boolean add(User aUser);
+
+ /**
+ * Removes a user. If the user does not exist, nothing happens.
+ * @param aUser
+ */
+ boolean remove(User aUser);
+
+ /**
+ * Lists the current users.
+ * @return Users.
+ */
+ Set<User> list();
+
+ /**
+ * Lists the users belonging to a particular group.
+ * @param aGroup Group.
+ * @return Groups.
+ */
+ Set<User> list(Group aGroup);
+
+ /**
+ *
+ * @return The number of users.
+ */
+ int size();
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt.hibernate;
+
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.wamblee.persistence.hibernate.HibernateSupport;
+import org.wamblee.usermgt.Group;
+import org.wamblee.usermgt.GroupSet;
+
+/**
+ * Set of groups backed by the database.
+ */
+public class HibernateGroupSet extends HibernateSupport implements GroupSet {
+
+
+ private static final String QUERY_FIND_BY_NAME = "findGroupByName";
+
+ private static final String PARAM_NAME = "name";
+
+ private static final String QUERY_COUNT_GROUPS = "countGroups";
+
+ public HibernateGroupSet() {
+ // Empty
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#groupModified(org.wamblee.usermgt.Group)
+ */
+ public void groupModified(Group aGroup) {
+ assert aGroup.getPrimaryKey() != null;
+ super.merge(aGroup);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#find(java.lang.String)
+ */
+ public Group find(String aName) {
+ List list = getHibernateTemplate().findByNamedQueryAndNamedParam(QUERY_FIND_BY_NAME, PARAM_NAME, aName);
+ if ( list.size() > 1 ) {
+ throw new RuntimeException("More than one group with the same name '" + aName + "'");
+ }
+ if ( list.size() == 0 ) {
+ return null;
+ }
+ return new Group((Group)list.get(0));
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#contains(org.wamblee.usermgt.Group)
+ */
+ public boolean contains(Group aGroup) {
+ return find(aGroup.getName()) != null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#add(org.wamblee.usermgt.Group)
+ */
+ public boolean add(Group aGroup) {
+ assert aGroup.getPrimaryKey() == null;
+ if ( contains(aGroup) ) {
+ return false;
+ }
+ super.merge(aGroup);
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#remove(org.wamblee.usermgt.Group)
+ */
+ public boolean remove(Group aGroup) {
+ assert aGroup.getPrimaryKey() != null;
+ if ( !contains(aGroup)) {
+ return false;
+ }
+ Group group = (Group) getHibernateTemplate().merge(aGroup);
+ getHibernateTemplate().delete(group);
+ aGroup.setPrimaryKey(null);
+ aGroup.setPersistedVersion(-1);
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#list()
+ */
+ public Set<Group> list() {
+ Set<Group> groups = new TreeSet<Group>();
+ List<Group> list = getHibernateTemplate().loadAll(Group.class);
+ for (Group group: list) {
+ groups.add(new Group(group));
+ }
+ return groups;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.GroupSet#size()
+ */
+ public int size() {
+ Long result = (Long) getHibernateTemplate().findByNamedQuery(QUERY_COUNT_GROUPS).get(0);
+ return result.intValue();
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt.hibernate;
+
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.hibernate.SessionFactory;
+import org.springframework.orm.hibernate3.HibernateTemplate;
+import org.wamblee.cache.Cache;
+import org.wamblee.persistence.hibernate.HibernateSupport;
+import org.wamblee.security.encryption.MessageDigester;
+import org.wamblee.usermgt.AbstractUserSet;
+import org.wamblee.usermgt.Group;
+import org.wamblee.usermgt.NameValidator;
+import org.wamblee.usermgt.User;
+
+/**
+ * User set backed by the database.
+ */
+public class HibernateUserSet extends AbstractUserSet {
+
+ private static final String QUERY_FIND_BY_NAME = "findUserByName";
+
+ private static final String QUERY_FIND_BY_GROUP_NAME = "findUserByGroupName";
+
+ private static final String PARAM_NAME = "name";
+
+ private static final String QUERY_COUNT_USERS = "countUsers";
+
+ /**
+ * Cache of users. Every user in the cache has its password validator and encoder set.
+ */
+ private Cache<String, User> _cache;
+
+ /**
+ * Spring hibernate support.
+ */
+ private HibernateSupport _hibernateSupport;
+
+ /**
+ * Constructs a user set backed by the database.
+ * @param aCache User cache to use.
+ */
+ public HibernateUserSet(Cache<String,User> aCache,
+ NameValidator aPasswordValidator, MessageDigester aPasswordEncoder) {
+ super(aPasswordValidator, aPasswordEncoder);
+ _cache = aCache;
+ _hibernateSupport = new HibernateSupport();
+ }
+
+ /**
+ * Sets the session factory.
+ * @param aFactory Session factory.
+ */
+ public void setSessionFactory(SessionFactory aFactory) {
+ _hibernateSupport.setSessionFactory(aFactory);
+ }
+
+ /**
+ * Gets the hibernate template.
+ * @return Hibernate template.
+ */
+ private HibernateTemplate getHibernateTemplate() {
+ return _hibernateSupport.getHibernateTemplate();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#userModified(org.wamblee.usermgt.User)
+ */
+ public void userModified(User aUser) {
+ assert aUser.getPrimaryKey() != null;
+ _hibernateSupport.merge(aUser);
+ _cache.remove(aUser.getName());
+ setPasswordInfo(aUser);
+ _cache.put(aUser.getName(), new User(aUser));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#find(java.lang.String)
+ */
+ public User find(String aName) {
+ User user = _cache.get(aName);
+ if (user != null) {
+ return user;
+ }
+ List result = getHibernateTemplate().findByNamedQueryAndNamedParam(
+ QUERY_FIND_BY_NAME, PARAM_NAME, aName);
+ if (result.size() > 1) {
+ throw new RuntimeException(
+ "Implementation problem, more than one user with the same name!");
+ }
+ if (result.size() == 0) {
+ return null;
+ }
+ user = (User) result.get(0);
+ setPasswordInfo(user);
+ _cache.put(aName, user);
+ return new User(user);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#contains(org.wamblee.usermgt.User)
+ */
+ public boolean contains(User aUser) {
+ return find(aUser.getName()) != null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#add(org.wamblee.usermgt.User)
+ */
+ public boolean add(User aUser) {
+ assert aUser.getPrimaryKey() == null;
+ if (contains(aUser)) {
+ return false;
+ }
+ getHibernateTemplate().saveOrUpdate(aUser);
+ setPasswordInfo(aUser);
+ _cache.put(aUser.getName(), aUser);
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#remove(org.wamblee.usermgt.User)
+ */
+ public boolean remove(User aUser) {
+ assert aUser.getPrimaryKey() != null;
+ if (!contains(aUser)) {
+ return false;
+ }
+ User user = (User) getHibernateTemplate().merge(aUser);
+ getHibernateTemplate().delete(user);
+ aUser.setPersistedVersion(-1);
+ aUser.setPrimaryKey(null);
+ _cache.remove(aUser.getName());
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#list()
+ */
+ public Set<User> list() {
+ Set<User> users = new TreeSet<User>();
+ List<User> list = getHibernateTemplate().loadAll(User.class);
+ for (User user : list) {
+ setPasswordInfo(user);
+ users.add(new User(user));
+ }
+ return users;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserSet#list(org.wamblee.usermgt.Group)
+ */
+ public Set<User> list(Group aGroup) {
+ Set<User> users = new TreeSet<User>();
+ List<User> list = getHibernateTemplate().findByNamedQueryAndNamedParam(
+ QUERY_FIND_BY_GROUP_NAME, PARAM_NAME, aGroup.getName());
+ for (User user : list) {
+ setPasswordInfo(user);
+ users.add(new User(user));
+ }
+ return users;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.UserSet#size()
+ */
+ public int size() {
+ Long result = (Long)getHibernateTemplate().findByNamedQuery(QUERY_COUNT_USERS).get(0);
+ return result.intValue();
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import static org.wamblee.security.authorization.AuthorizationResult.DENIED;
+import static org.wamblee.security.authorization.AuthorizationResult.GRANTED;
+
+import org.wamblee.persistence.hibernate.HibernateMappingFiles;
+import org.wamblee.test.SpringConfigFiles;
+import org.wamblee.test.SpringTestCase;
+import org.wamblee.usermgt.UserAccessor;
+
+/**
+ * Tests the authorization service.
+ */
+public class AuthorizationServiceTest extends SpringTestCase {
+
+ private AuthorizationRule _rule1;
+ private AuthorizationRule _rule2;
+ private AuthorizationRule _rule3;
+ private AuthorizationService _service;
+
+
+ public AuthorizationServiceTest() {
+ super(SpringConfigFiles.class, HibernateMappingFiles.class);
+ }
+
+ public AuthorizationServiceTest(Class<? extends SpringConfigFiles>aSpringFiles,
+ Class<? extends HibernateMappingFiles> aMappings) {
+ super(aSpringFiles, aMappings);
+ }
+
+ protected AuthorizationService getService() {
+ return _service;
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ _rule1 = createRule(GRANTED, "users", "/oni/", AllOperation.class);
+ _rule2 = createRule(DENIED, "users", "/abc/", ReadOperation.class);
+ _rule3 = createRule(GRANTED, "users", "/abc/", AllOperation.class);
+
+ _service = createService();
+ _service.appendRule(_rule1);
+ _service.appendRule(_rule2);
+ _service.appendRule(_rule3);
+ }
+
+ protected void resetTestRules() {
+ ((TestAuthorizationRule)_rule1).reset();
+ ((TestAuthorizationRule)_rule2).reset();
+ ((TestAuthorizationRule)_rule3).reset();
+ }
+
+ protected UserAccessor createUserAccessor() {
+ return new TestUserAccessor();
+ }
+
+ /**
+ * Creates an authorization service with some rules for testing. .
+ * @return Authorization service.
+ */
+ protected AuthorizationService createService() {
+ DefaultAuthorizationService service = new DefaultAuthorizationService() ;
+ service.setUserAccessor(createUserAccessor());
+ return service;
+ }
+
+ protected AuthorizationRule createRule(AuthorizationResult aResult, String aGroup, String aPath, Class<? extends Operation> aOperation) {
+ return new TestAuthorizationRule(aResult, aGroup, aPath, aOperation);
+ }
+
+ protected void checkMatchCount(int aCount, AuthorizationRule aRule) {
+ assertEquals( aCount, ((TestAuthorizationRule)aRule).getMatchCount());
+ }
+
+ protected Object createResource(String aPath) {
+ return new TestResource(aPath);
+ }
+
+ protected void checkRuleCount(int aCount) {
+ // Empty
+ }
+
+ /**
+ * Several checks to verify the outcome of matching against the first rule.
+ *
+ */
+ public void testFirstRuleGrants() {
+ assertTrue( _service.isAllowed(createResource("/oni/xyz.jpg"), new ReadOperation()));
+ checkMatchCount(1, _rule1);
+ assertTrue(_service.isAllowed(createResource("/oni/xyz.jpg"), new WriteOperation()));
+ checkMatchCount(2, _rule1);
+ assertTrue(_service.isAllowed(createResource("/oni/xyz.jpg"), new DeleteOperation()));
+ checkMatchCount(3, _rule1);
+ assertTrue(_service.isAllowed(createResource("/oni/xyz.jpg"), new CreateOperation()));
+ checkMatchCount(4, _rule1);
+ checkMatchCount(0, _rule2);
+ checkMatchCount(0, _rule3);
+ }
+
+ /**
+ * Verify that a match with the second rule leads to a denial of authorization.
+ *
+ */
+ public void testSecondRuleDenies() {
+ assertFalse(_service.isAllowed(createResource("/abc/xyz.jpg"), new ReadOperation()));
+ checkMatchCount(0, _rule1);
+ checkMatchCount(1, _rule2);
+ checkMatchCount(0, _rule3);
+ }
+
+ /**
+ * Verifies that the third rule is used when appropriate and that it grants access.
+ *
+ */
+ public void testThirdRuleGrants() {
+ assertTrue(_service.isAllowed(createResource("/abc/xyz.jpg"), new WriteOperation()));
+ checkMatchCount(0, _rule1);
+ checkMatchCount(0, _rule2);
+ checkMatchCount(1, _rule3);
+ }
+
+ /**
+ * Removes a rule and checks it is removed.
+ *
+ */
+ public void testRemoveRule() {
+ checkRuleCount(3);
+ assertTrue(_service.isAllowed(createResource("/abc/xyz.jpg"), new WriteOperation()));
+ _service.removeRule(2);
+ assertFalse(_service.isAllowed(createResource("/abc/xyz.jpg"), new WriteOperation()));
+ checkRuleCount(2);
+ }
+
+ /**
+ * Inserts a rule and checks it is inserted.
+ *
+ */
+ public void testInsertRule() {
+ checkRuleCount(3);
+ assertFalse(_service.isAllowed(createResource("/janse/xyz.jpg"), new WriteOperation()));
+ _service.appendRule(createRule(GRANTED, "users", "/janse/", WriteOperation.class));
+ assertTrue(_service.isAllowed(createResource("/janse/xyz.jpg"), new WriteOperation()));
+ checkRuleCount(4);
+
+ }
+
+ /**
+ * Gets the rules. Verifies that all rules are obtained.
+ *
+ */
+ public void testGetRules() {
+ AuthorizationRule[] rules = _service.getRules();
+ assertEquals(3, rules.length);
+ }
+
+ /**
+ * Verifies that when no rules match, access is denied.
+ *
+ */
+ public void testNoRulesSupportResource() {
+ assertFalse(_service.isAllowed(createResource("/xyxyxyxy"), new ReadOperation()));
+ checkMatchCount(0, _rule1);
+ checkMatchCount(0, _rule2);
+ checkMatchCount(0, _rule3);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import junit.framework.TestCase;
+
+/**
+ * Test of the operation registry.
+ */
+public class DefaultOperationRegistryTest extends TestCase {
+
+ private OperationRegistry _registry;
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+
+ _registry = new DefaultOperationRegistry(new Operation[] {
+ new AllOperation(),
+ new ReadOperation(),
+ new WriteOperation(),
+ new DeleteOperation(),
+ new CreateOperation()
+ });
+ }
+
+ /**
+ * Tests encoding and decoding of no operations.
+ *
+ */
+ public void testEncodeDecodeNooperations() {
+ assertEquals("", _registry.encode(new Operation[0]));
+ assertEquals(0, _registry.decode(Object.class, "").length);
+ }
+
+ /**
+ * Verifies that encoding of operations into a string works.
+ *
+ */
+ public void testEncode() {
+ assertEquals("read,write", _registry.encode(new Operation[] { new ReadOperation(), new WriteOperation() }));
+ }
+
+ /**
+ * Verifies that decoding of operation from a string works.
+ *
+ */
+ public void testDecode() {
+ Operation[] operations = _registry.decode(Object.class, "read,write");
+ assertTrue( operations[0] instanceof ReadOperation);
+ assertTrue( operations[1] instanceof WriteOperation);
+ }
+
+ /**
+ * Verifies that an IllegalArgumentException occurs when attempting to decode
+ * an operation that is not known.
+ *
+ */
+ public void testDecodeUnknownOperation() {
+ try {
+ _registry.decode(Object.class, "bla");
+ fail();
+ } catch (IllegalArgumentException e) {
+ // ok
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import junit.framework.TestCase;
+
+/**
+ * Test for regular expression matching.
+ */
+public class RegexpPathConditionTest extends TestCase {
+
+ /**
+ * Various tests.
+ *
+ */
+ public void testMatch() {
+ PathCondition cond = new RegexpPathCondition("abc");
+ assertTrue(cond.matches("abc"));
+ assertFalse(cond.matches("xabcx"));
+ cond = new RegexpPathCondition("/[a-z]*/.*");
+ assertTrue(cond.matches("/hallo/xyz"));
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for StartsWithPathCondition.
+ */
+public class StartsWithPathConditionTest extends TestCase {
+
+ /**
+ * Various tests.
+ */
+ public void testMatches() {
+ PathCondition cond = new StartsWithPathCondition("/hallo");
+ assertTrue(cond.matches("/hallo"));
+ assertTrue(cond.matches("/hallox"));
+ assertTrue(cond.matches("/hallo/abc"));
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import static org.wamblee.security.authorization.AuthorizationResult.DENIED;
+import static org.wamblee.security.authorization.AuthorizationResult.GRANTED;
+
+import org.wamblee.usermgt.User;
+
+/**
+ * Test authorization rule that also counts the number of times the rule matches.
+ */
+public class TestAuthorizationRule extends UrlAuthorizationRule {
+
+ /**
+ * Counts the number of matches.
+ */
+ private int _matches = 0;
+
+ public TestAuthorizationRule( AuthorizationResult aResult, String aGroup,
+ String aPath, Class<? extends Operation> aOperation) {
+ super(aResult, new GroupUserCondition(aGroup),
+ new StartsWithPathCondition(aPath), TestResource.class, new IsaOperationCondition(aOperation));
+ }
+
+ protected TestAuthorizationRule() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.UrlAuthorizationRule#getPath(java.lang.Object)
+ */
+ @Override
+ protected String getResourcePath(Object aResource) {
+ return ((TestResource)aResource).getPath();
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.UrlAuthorizationRule#isAllowed(java.lang.Object, org.wamblee.security.authorization.Operation, org.wamblee.usermgt.UserAccessor)
+ */
+ @Override
+ public AuthorizationResult isAllowed(Object aResource, Operation anOperation, User aUser) {
+
+ AuthorizationResult result = super.isAllowed(aResource, anOperation, aUser);
+ if ( result.equals(GRANTED) || result.equals(DENIED)) {
+ _matches++;
+ }
+ return result;
+ }
+
+ public int getMatchCount() {
+ return _matches;
+ }
+
+ public void reset() {
+ _matches = 0;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+/**
+ * A test resource for authorization.
+ */
+public class TestResource {
+
+ private String _path;
+
+ public TestResource(String aPath) {
+ _path = aPath;
+ }
+
+ public String getPath() {
+ return _path;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import junit.framework.TestCase;
+
+import org.wamblee.security.encryption.Md5HexMessageDigester;
+import org.wamblee.usermgt.Group;
+import org.wamblee.usermgt.InMemoryGroupSet;
+import org.wamblee.usermgt.InMemoryUserSet;
+import org.wamblee.usermgt.RegexpNameValidator;
+import org.wamblee.usermgt.User;
+import org.wamblee.usermgt.UserAccessor;
+import org.wamblee.usermgt.UserAdministration;
+import org.wamblee.usermgt.UserAdministrationImpl;
+import org.wamblee.usermgt.UserMgtException;
+import org.wamblee.usermgt.UserMgtException.Reason;
+
+/**
+ * User access that always returns a user that belongs to
+ * a fixed group.
+ */
+public class TestUserAccessor implements UserAccessor {
+
+ private static final String USER = "erik";
+ private static final String PASSWORD = "abc123";
+ private static final String GROUP = "users";
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAccessor#getCurrentUser()
+ */
+ public User getCurrentUser() {
+ UserAdministration admin = new UserAdministrationImpl(
+ new InMemoryUserSet( new RegexpNameValidator(RegexpNameValidator.PASSWORD_PATTERN, Reason.INVALID_PASSWORD, "Password must contain at least 6 characters"),
+ new Md5HexMessageDigester()), new InMemoryGroupSet(),
+ new RegexpNameValidator(RegexpNameValidator.ID_PATTERN, Reason.INVALID_USERNAME, "Invalid user"),
+ new RegexpNameValidator(RegexpNameValidator.ID_PATTERN, Reason.INVALID_GROUPNAME, "Invalid group")
+ );
+ try {
+ Group group = admin.createGroup(GROUP);
+ return admin.createUser(USER, PASSWORD, group);
+ } catch (UserMgtException e) {
+ TestCase.fail(e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization;
+
+import static org.wamblee.security.authorization.AuthorizationResult.GRANTED;
+import static org.wamblee.security.authorization.AuthorizationResult.UNDECIDED;
+import static org.wamblee.security.authorization.AuthorizationResult.UNSUPPORTED_RESOURCE;
+import junit.framework.TestCase;
+
+import org.wamblee.usermgt.User;
+
+
+/**
+ * Tests for the {@link org.wamblee.security.authorization.UrlAuthorizationRule}.
+ */
+public class UrlAuthorizationRuleTest extends TestCase {
+
+ /**
+ * Constructs the rule with a result of UNDECIDED. Verifies that an IllegalArgumentException
+ * is thrown.
+ *
+ */
+ public void testConstructWithUndecidedResult() {
+ try {
+ new TestAuthorizationRule(UNDECIDED, "users", "/path", ReadOperation.class);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // ok
+ }
+ }
+
+ /**
+ * Constructs the rule with a result of UNSUPPORTED_RESOURCE. Verifies that an IllegalArgumentException
+ * is thrown.
+ *
+ */
+ public void testConstructWithUnsupportedResult() {
+ try {
+ new TestAuthorizationRule(UNSUPPORTED_RESOURCE, "users", "/path", ReadOperation.class);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // ok
+ }
+ }
+
+ /**
+ * Constructs the authorization rule and applies it to an unsupported object type.
+ * Verifies that the result is UNSUPPORTED_RESOURCE.
+ *
+ */
+ public void testUnsupportedObject() {
+ AuthorizationRule rule = new TestAuthorizationRule(GRANTED, "users", "/path", ReadOperation.class);
+ assertEquals(UNSUPPORTED_RESOURCE, rule.isAllowed("hello", new ReadOperation(), new TestUserAccessor().getCurrentUser()));
+ }
+
+ public void testMatchingScenarios() {
+ AuthorizationRule rule = new TestAuthorizationRule(GRANTED, "users", "/path/", ReadOperation.class);
+ User user = new TestUserAccessor().getCurrentUser();
+
+ // everything matches
+ assertEquals(GRANTED, rule.isAllowed(new TestResource("/path/a"), new ReadOperation(), user));
+ assertEquals(GRANTED, rule.isAllowed(new TestResource("/path/"), new ReadOperation(), user));
+
+ // path does not match.
+ assertEquals(UNDECIDED, rule.isAllowed(new TestResource("/path"), new ReadOperation(), user));
+
+ // operation does not match.
+ assertEquals(UNDECIDED, rule.isAllowed(new TestResource("/path/"), new WriteOperation(), user));
+
+ // group does not match.
+ AuthorizationRule rule2 = new TestAuthorizationRule(GRANTED, "users2", "/path/", ReadOperation.class);
+ assertEquals(UNDECIDED, rule2.isAllowed(new TestResource("/path/a"), new ReadOperation(), user));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization.hibernate;
+
+import org.wamblee.usermgt.UsermgtHibernateMappingFiles;
+
+/**
+ * Mapping files for authorization.
+ */
+public class AuthorizationMappingFiles extends UsermgtHibernateMappingFiles {
+
+ public AuthorizationMappingFiles() {
+ super(new String[]{ "hbm/AuthorizationRule.hbm.xml", "hbm/UserCondition.hbm.xml",
+ "hbm/AuthorizationService.hbm.xml", "hbm/OperationCondition.hbm.xml", "hbm/PathCondition.hbm.xml",
+ "hbm/TestAuthorizationRule.hbm.xml" });
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization.hibernate;
+
+import org.wamblee.usermgt.UsermgtSpringConfigFiles;
+
+/**
+ *
+ */
+public class AuthorizationSpringConfigFiles extends UsermgtSpringConfigFiles {
+
+ public AuthorizationSpringConfigFiles() {
+ super(new String[] { "spring/test.org.wamblee.security.authorization.xml" });
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.authorization.hibernate;
+
+import java.sql.SQLException;
+
+import org.apache.log4j.Logger;
+import org.springframework.orm.hibernate3.HibernateTemplate;
+import org.wamblee.general.BeanKernel;
+import org.wamblee.security.authorization.AuthorizationService;
+import org.wamblee.security.authorization.AuthorizationServiceTest;
+
+/**
+ * Unit test for the persistent authorization service.
+ */
+public class PersistentAuthorizationServiceTest extends AuthorizationServiceTest {
+
+ private static final Logger LOGGER = Logger.getLogger(PersistentAuthorizationServiceTest.class);
+
+ private static final String SERVICE_TABLE = "AUTHORIZATION_SERVICE";
+ private static final String RULES_TABLE = "AUTHORIZATION_RULES";
+ private static final String SERVICE_RULES_TABLE = "AUTHORIZATION_SERVICE_RULES";
+ private static final String OPERATIONCOND_TABLE = "OPERATION_CONDITIONS";
+ private static final String PATHCOND_TABLE = "PATH_CONDITIONS";
+ private static final String USERCOND_TABLE = "USER_CONDITIONS";
+
+
+ public PersistentAuthorizationServiceTest() {
+ super(AuthorizationSpringConfigFiles.class, AuthorizationMappingFiles.class);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.AuthorizationServiceTest#createService()
+ */
+ @Override
+ protected AuthorizationService createService() {
+ PersistentAuthorizationService service = new PersistentAuthorizationService("DEFAULT",
+ BeanKernel.getBeanFactory().find(HibernateTemplate.class), createUserAccessor(), 10000);
+ return service;
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.security.authorization.AuthorizationServiceTest#checkRuleCount(int)
+ */
+ @Override
+ protected void checkRuleCount(int aCount) {
+ try {
+ assertEquals(1, getTableSize(SERVICE_TABLE));
+ assertEquals(aCount, getTableSize(RULES_TABLE));
+ assertEquals(aCount, getTableSize(SERVICE_RULES_TABLE));
+ assertEquals(aCount, getTableSize(USERCOND_TABLE));
+ assertEquals(aCount, getTableSize(PATHCOND_TABLE));
+ assertEquals(aCount, getTableSize(OPERATIONCOND_TABLE));
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void testPerformance() {
+
+ PersistentAuthorizationService service = (PersistentAuthorizationService)getService();
+
+ int n = 1000;
+ long time = System.currentTimeMillis();
+ for (int i = 0; i < n; i++) {
+ testFirstRuleGrants();
+ resetTestRules();
+ testSecondRuleDenies();
+ resetTestRules();
+ testThirdRuleGrants();
+ resetTestRules();
+ testNoRulesSupportResource();
+ }
+ LOGGER.info("Executed " + 4*n + " authorization checks in " + (float)(System.currentTimeMillis()-time)/(float)1000 + " seconds.");
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.security.encryption;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the message digester.
+ */
+public class MessageDigesterTest extends TestCase {
+
+ public void testMd5HexEncoding() {
+ assertEquals("e99a18c428cb38d5f260853678922e03", new Md5HexMessageDigester().hash("abc123"));
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.sql.SQLException;
+import java.util.Set;
+
+import org.wamblee.persistence.hibernate.HibernateMappingFiles;
+import org.wamblee.test.SpringConfigFiles;
+import org.wamblee.test.SpringTestCase;
+
+/**
+ * Tests the inmemory group set. Intended to be subclassed for other
+ * implementations of group set.
+ */
+public class InMemoryGroupSetTest extends SpringTestCase {
+
+ protected GroupSet _groups;
+
+ public InMemoryGroupSetTest() {
+ super(SpringConfigFiles.class, HibernateMappingFiles.class);
+ }
+
+ protected InMemoryGroupSetTest(Class<? extends SpringConfigFiles> aSprings,
+ Class<? extends HibernateMappingFiles> aMappings) {
+ super(aSprings, aMappings);
+ }
+
+ /**
+ * This method must be overriden in subclasses.
+ * @return New group set object.
+ */
+ protected GroupSet createGroupSet() {
+ return new InMemoryGroupSet();
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.test.SpringTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ _groups = createGroupSet();
+ checkGroupCount(0);
+ }
+
+
+
+ /**
+ * Additional check to be implemented by a subclass.
+ * @param aGroup Group to check for existence.
+ */
+ protected void checkGroupExists(String aGroup) throws SQLException {
+ // Empty
+ }
+
+ /**
+ * Additional check to be implemented by a subclass.
+ * @param aGroup Group to check for non-existence.
+ */
+ protected void checkGroupNotExists(String aGroup) throws SQLException {
+ // Empty
+ }
+
+ /**
+ * Additional check to be implemented by a subclass.
+ * @param aSize Expected number of groups.
+ */
+ protected void checkGroupCount(int aSize) throws SQLException {
+ assertEquals(aSize, _groups.size());
+ }
+
+ /**
+ * Adds a group and verifies that the group is added using
+ * find(), list(), and contains().
+ *
+ */
+ public void testAdd() throws SQLException {
+ Group group = new Group("group1");
+ assertTrue( _groups.add(group) );
+ checkGroupExists(group.getName());
+ checkGroupCount(1);
+ Group group2 = _groups.find("group1");
+ assertNotNull(group2);
+ assertEquals(group.getName(), group2.getName());
+ Set<Group> set = _groups.list();
+ assertEquals(1, set.size());
+ assertTrue(set.contains(group));
+ }
+
+ /**
+ * Tries to find a non-existing group. Verifies that null is
+ * returned.
+ *
+ */
+ public void testFindUnknownGroup() throws SQLException {
+ Group group1 = new Group("group1");
+ Group group2 = new Group("group2");
+ _groups.add(group1);
+ _groups.add(group2);
+ checkGroupExists(group1.getName());
+ checkGroupExists(group2.getName());
+
+ assertNull( _groups.find("group3") );
+ checkGroupNotExists("group3");
+ }
+
+ /**
+ * Adds duplicate group. Verifies that the existing group is left untouched.
+ */
+ public void testAddDuplicateGroup() throws SQLException {
+ Group group1 = new Group("group1");
+ _groups.add(group1);
+
+ assertEquals(1, _groups.list().size());
+ assertTrue(_groups.contains(group1));
+ group1 = new Group("group1");
+ assertFalse(_groups.add(group1));
+ assertEquals(1, _groups.list().size());
+
+ checkGroupExists(group1.getName());
+ checkGroupCount(1);
+ }
+
+ /**
+ * Removes a group. Verifies that the group is
+ * removed and the return value is true.
+ *
+ */
+ public void testRemoveGroup() throws SQLException {
+ Group group1 = new Group("group1");
+ _groups.add(group1);
+ assertTrue(_groups.contains(group1));
+ checkGroupCount(1);
+
+ assertTrue(_groups.remove(group1));
+ assertFalse(_groups.contains(group1));
+ assertNull(_groups.find(group1.getName()));
+ assertEquals(0, _groups.list().size());
+ checkGroupCount(0);
+ }
+
+ /**
+ * Removes a non-existing group. Verifies that no groups are
+ * removed an that the return value is true.
+ *
+ */
+ public void testRemoveNonExistingGroup() throws SQLException {
+ Group group1 = new Group("group1");
+ _groups.add(group1);
+ checkGroupCount(1);
+ Group nonExistingGroup = new Group("group2");
+ nonExistingGroup.setPrimaryKey(new Long(1000));
+ nonExistingGroup.setPersistedVersion(1000);
+ assertFalse(_groups.remove(nonExistingGroup));
+ assertTrue(_groups.contains(group1));
+ assertEquals(1, _groups.list().size());
+ checkGroupCount(1);
+ }
+
+ /**
+ * Adds a number of groups to the set and verifies that list()
+ * returns them all.
+ *
+ */
+ public void testList() throws SQLException {
+ Group group1 = new Group("group1");
+ Group group2 = new Group("group2");
+ Group group3 = new Group("group3");
+ assertTrue(_groups.add(group1));
+ assertTrue(_groups.add(group2));
+ assertTrue(_groups.add(group3));
+
+ checkGroupExists(group1.getName());
+ checkGroupExists(group2.getName());
+ checkGroupExists(group3.getName());
+
+ Set<Group> set = _groups.list();
+ assertTrue(set.contains(group1));
+ assertTrue(set.contains(group2));
+ assertTrue(set.contains(group3));
+
+ checkGroupCount(3);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.sql.SQLException;
+import java.util.Set;
+
+import org.wamblee.persistence.hibernate.HibernateMappingFiles;
+import org.wamblee.security.encryption.Md5HexMessageDigester;
+import org.wamblee.test.SpringConfigFiles;
+import org.wamblee.test.SpringTestCase;
+import org.wamblee.usermgt.UserMgtException.Reason;
+
+/**
+ * Tests the inmemory user set. Intended to be subclassed for other
+ * implementations of user set.
+ */
+public class InMemoryUserSetTest extends SpringTestCase {
+
+ protected static final String PASSWORD = "abc123";
+
+ private UserSet _users;
+ private GroupSet _groups;
+
+ private Group _group;
+
+ public InMemoryUserSetTest() {
+ super(SpringConfigFiles.class, HibernateMappingFiles.class);
+ }
+
+ protected InMemoryUserSetTest(Class<? extends SpringConfigFiles> aSprings,
+ Class<? extends HibernateMappingFiles> aMappings) {
+ super(aSprings, aMappings);
+ }
+
+ /**
+ * This method must be overriden in subclasses.
+ * @return New user set object.
+ */
+ protected UserSet createUserSet() {
+ return new InMemoryUserSet( new RegexpNameValidator(RegexpNameValidator.PASSWORD_PATTERN, Reason.INVALID_PASSWORD, "Password must contain at least 6 characters"),
+ new Md5HexMessageDigester());
+ }
+
+ /**
+ * This method must be overriden in subclasses.
+ * @return New group set object.
+ */
+ protected GroupSet createGroupSet() {
+ return new InMemoryGroupSet();
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.test.SpringTestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ _users = createUserSet();
+ _groups = createGroupSet();
+ _group = new Group("group0");
+ _groups.add(_group);
+ checkUserCount(0);
+
+ }
+
+ protected UserSet getUsers() {
+ return _users;
+ }
+
+ protected GroupSet getGroups() {
+ return _groups;
+ }
+
+ protected Group createGroup(String aName) {
+ return new Group(aName);
+ }
+
+ protected User createUser(String aName, String aPassword, Group aGroup) throws UserMgtException {
+ return UsermgtTestUtils.createUser(aName, aPassword, aGroup);
+ }
+
+ protected void addUserToGroup(User aUser, Group aGroup) throws UserMgtException {
+ aUser.addGroup(aGroup);
+ }
+
+ protected void removeUserFromGroup(User aUser, Group aGroup ) throws UserMgtException {
+ aUser.removeGroup(aGroup);
+ }
+
+ /**
+ * Additional check to be implemented by a subclass.
+ * @param aUser User to check for existence.
+ */
+ protected void checkUserExists(String aUser) throws SQLException {
+ // Empty
+ }
+
+ /**
+ * Additional check to be implemented by a subclass.
+ * @param aUser User to check for non-existence.
+ */
+ protected void checkUserNotExists(String aUser) throws SQLException {
+ // Empty
+ }
+
+ /**
+ * Additional check to be implemented by a subclass.
+ * @param aSize Expected number of users.
+ */
+ protected void checkUserCount(int aSize) throws SQLException {
+ assertEquals(aSize, _users.size());
+ }
+
+ /**
+ * Additional check to be implemented by a subclass.
+ * @param aUser User to check for existence.
+ */
+ protected void checkGroupExists(String aUser) throws SQLException {
+ // Empty
+ }
+
+ /**
+ * Additional check to be implemented by a subclass.
+ * @param aUser User to check for non-existence.
+ */
+ protected void checkGroupNotExists(String aUser) throws SQLException {
+ // Empty
+ }
+
+ /**
+ * Additional check to be implemented by a subclass.
+ * @param aSize Expected number of users.
+ */
+ protected void checkGroupCount(int aSize) throws SQLException {
+ // Empty
+ }
+
+
+ /**
+ * Adds a user and verifies that the user is added using
+ * find(), list(), and contains().
+ *
+ */
+ public void testAdd() throws SQLException, UserMgtException {
+ User user = createUser("user1", PASSWORD, _group);
+ assertTrue( _users.add(user) );
+ checkUserExists(user.getName());
+ checkUserCount(1);
+ User user2 = _users.find("user1");
+ assertNotNull(user2);
+ assertEquals(user.getName(), user2.getName());
+ Set<User> set = _users.list();
+ assertEquals(1, set.size());
+ assertTrue(set.contains(user));
+ }
+
+ /**
+ * Tries to find a non-existing user. Verifies that null is
+ * returned.
+ *
+ */
+ public void testFindUnknownUser() throws SQLException, UserMgtException {
+ User user1 = createUser("user1", PASSWORD, _group);
+ User user2 = createUser("user2", PASSWORD, _group);
+ _users.add(user1);
+ _users.add(user2);
+ checkUserExists(user1.getName());
+ checkUserExists(user2.getName());
+
+ assertNull( _users.find("user3") );
+ checkUserNotExists("user3");
+ }
+
+ /**
+ * Adds duplicate user. Verifies that the existing user is left untouched.
+ */
+ public void testAddDuplicateUser() throws SQLException, UserMgtException {
+ User user1 = createUser("user1", PASSWORD, _group);
+ _users.add(user1);
+
+ assertEquals(1, _users.list().size());
+ assertTrue(_users.contains(user1));
+ user1 = createUser("user1", PASSWORD, _group);
+ assertFalse(_users.add(user1));
+ assertEquals(1, _users.list().size());
+
+ checkUserExists(user1.getName());
+ checkUserCount(1);
+ }
+
+ /**
+ * Removes a user. Verifies that the user is
+ * removed and the return value is true.
+ *
+ */
+ public void testRemoveUser() throws SQLException, UserMgtException {
+ User user1 = createUser("user1", PASSWORD, _group);
+ _users.add(user1);
+ assertTrue(_users.contains(user1));
+ checkUserCount(1);
+
+ assertTrue(_users.remove(user1));
+ assertFalse(_users.contains(user1));
+ assertNull(_users.find(user1.getName()));
+ assertEquals(0, _users.list().size());
+ checkUserCount(0);
+ }
+
+ /**
+ * Removes a non-existing user. Verifies that no users are
+ * removed an that the return value is true.
+ *
+ */
+ public void testRemoveNonExistingUser() throws SQLException, UserMgtException {
+ User user1 = createUser("user1", PASSWORD, _group);
+ _users.add(user1);
+ checkUserCount(1);
+ User nonExistingUser = createUser("user2", PASSWORD, _group);
+ nonExistingUser.setPrimaryKey(new Long(1000));
+ nonExistingUser.setPersistedVersion(10);
+ assertFalse(_users.remove(nonExistingUser));
+ assertTrue(_users.contains(user1));
+ assertEquals(1, _users.list().size());
+ checkUserCount(1);
+ }
+
+ /**
+ * Adds a number of users to the set and verifies that list()
+ * returns them all.
+ *
+ */
+ public void testList() throws SQLException, UserMgtException {
+ User user1 = createUser("user1", PASSWORD, _group);
+ User user2 = createUser("user2", PASSWORD, _group);
+ User user3 = createUser("user3", PASSWORD, _group);
+ assertTrue(_users.add(user1));
+ assertTrue(_users.add(user2));
+ assertTrue(_users.add(user3));
+
+ checkUserExists(user1.getName());
+ checkUserExists(user2.getName());
+ checkUserExists(user3.getName());
+
+ Set<User> set = _users.list();
+ assertTrue(set.contains(user1));
+ assertTrue(set.contains(user2));
+ assertTrue(set.contains(user3));
+
+ checkUserCount(3);
+ }
+
+ /**
+ * Adds several users to different groups and verifies that
+ * the correct users are returned when looking for users in
+ * different groups.
+ * @throws SQLException
+ */
+ public void testListByGroup() throws SQLException, UserMgtException {
+ Group group1 = new Group("group1");
+ Group group2 = new Group("group2");
+ Group group3 = new Group("group3");
+ _groups.add(group1);
+ _groups.add(group2);
+ _groups.add(group3);
+
+ // user1 user2 user3
+ // group1 y
+ // group2 y y
+ // group3 y y y
+
+ User user1 = createUser("user1", PASSWORD, group1);
+ user1.addGroup(group2);
+ user1.addGroup(group3);
+ User user2 = createUser("user2", PASSWORD, group2);
+ user2.addGroup(group3);
+ User user3 = createUser("user3", PASSWORD, group3);
+ _users.add(user1);
+ _users.add(user2);
+ _users.add(user3);
+
+ checkUserExists(user1.getName());
+ checkUserExists(user2.getName());
+ checkUserExists(user3.getName());
+
+ checkGroupExists(group1.getName());
+ checkGroupExists(group2.getName());
+ checkGroupExists(group3.getName());
+
+ checkUserCount(3);
+ checkGroupCount(3+1); // also count the group that was created in the setUp().
+
+ Set<User> list = _users.list(group1);
+ assertTrue(list.contains(user1));
+ assertEquals(1, list.size());
+
+ list = _users.list(group2);
+ assertTrue(list.contains(user1));
+ assertTrue(list.contains(user2));
+ assertEquals(2, list.size());
+
+ list = _users.list(group3);
+ assertTrue(list.contains(user1));
+ assertTrue(list.contains(user2));
+ assertTrue(list.contains(user3));
+ assertEquals(3, list.size());
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.wamblee.persistence.hibernate.HibernateMappingFiles;
+import org.wamblee.security.encryption.Md5HexMessageDigester;
+import org.wamblee.test.SpringConfigFiles;
+import org.wamblee.test.SpringTestCase;
+import org.wamblee.usermgt.UserMgtException.Reason;
+
+/**
+ * Test of user administration implementation.
+ */
+public class UserAdministrationImplTest extends SpringTestCase {
+
+ private static final Logger LOGGER = Logger
+ .getLogger(UserAdministrationImplTest.class);
+
+ private static final String USER1 = "piet";
+
+ private static final String PASS1 = "passpiet";
+
+ private static final String USER2 = "kees";
+
+ private static final String PASS2 = "passkees";
+
+ private static final String GROUP1 = "cyclists";
+
+ private static final String GROUP2 = "runners";
+
+ private UserAdministration _admin;
+
+ public UserAdministrationImplTest() {
+ super(SpringConfigFiles.class, HibernateMappingFiles.class);
+ }
+
+ public UserAdministrationImplTest(
+ Class<? extends SpringConfigFiles> aSprings,
+ Class<? extends HibernateMappingFiles> aMappings) {
+ super(aSprings, aMappings);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ _admin = createAdmin();
+ }
+
+ protected UserAdministration createAdmin() {
+ UserSet users = new InMemoryUserSet( new RegexpNameValidator(RegexpNameValidator.PASSWORD_PATTERN, Reason.INVALID_PASSWORD, "Password must contain at least 6 characters"),
+ new Md5HexMessageDigester());
+ GroupSet groups = new InMemoryGroupSet();
+ return new UserAdministrationImpl(users, groups,
+ new RegexpNameValidator(RegexpNameValidator.ID_PATTERN,
+ Reason.INVALID_USERNAME, "Invalid user"),
+ new RegexpNameValidator(RegexpNameValidator.ID_PATTERN,
+ Reason.INVALID_GROUPNAME, "Invalid group"));
+ }
+
+ protected User createUser(String aName, String aPassword, Group aGroup) throws UserMgtException {
+ return UsermgtTestUtils.createUser(aName, aPassword, aGroup);
+ }
+
+ /**
+ * Constructs the admin, verify it contains no users and no groups.
+ */
+ public void testConstruct() {
+ assertEquals(0, _admin.getUsers().size());
+ assertEquals(0, _admin.getGroups().size());
+ assertEquals(0, _admin.getUserCount());
+ assertEquals(0, _admin.getGroupCount());
+ }
+
+ /**
+ * Creates a new group. Verifies the group is created correctly and that the
+ * user is added.
+ *
+ */
+ public void testCreateGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ assertNotNull(group);
+ assertEquals(GROUP1, group.getName());
+
+ Set<Group> groups = _admin.getGroups();
+ assertEquals(1, groups.size());
+ assertEquals(1, _admin.getGroupCount());
+ assertTrue(groups.contains(group));
+ }
+
+ private void createInvalidGroup(String aUsername) {
+ try {
+ _admin.createGroup(aUsername);
+ fail();
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.INVALID_GROUPNAME, e
+ .getReason());
+ assertEquals(0, _admin.getGroupCount());
+ }
+ }
+
+ /**
+ * Creates a new group with an invalid name. Verifies that the appropriate
+ * exception is thrown.
+ *
+ * @throws UserMgtException
+ */
+ public void testCreateInvalidGroupName() throws UserMgtException {
+ createInvalidGroup("");
+ createInvalidGroup("0abc"); // should not start with digits
+ createInvalidGroup("a b"); // should not contain spaces
+ createInvalidGroup(" aa");
+ createInvalidGroup("aa ");
+ }
+
+ /**
+ * Creates a new group which conflicts with an existing one. Verifies that
+ * the UserMgtException is thrown and that no group is added.
+ *
+ */
+ public void testCreateDuplicateGroup() throws UserMgtException {
+ _admin.createGroup(GROUP1);
+ try {
+ _admin.createGroup(GROUP1);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.DUPLICATE_GROUP, e.getReason());
+ assertEquals(1, _admin.getGroupCount());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Creates a new user. Verifies the user is created correctly and that the
+ * user is added.
+ *
+ */
+ public void testCreateUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ assertNotNull(user);
+ assertEquals(USER1, user.getName());
+ user.checkPassword(PASS1);
+
+ Set<User> users = _admin.getUsers();
+ assertEquals(1, users.size());
+ assertEquals(1, _admin.getUserCount());
+ assertTrue(users.contains(user));
+ }
+
+ private void createInvalidUser(String aUsername, Group aGroup) {
+ try {
+ _admin.createUser(aUsername, "pass", aGroup);
+ fail();
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.INVALID_USERNAME, e
+ .getReason());
+ assertEquals(0, _admin.getUserCount());
+ }
+ }
+
+ /**
+ * Constructs users with invalid names. Verifies that the appropriate
+ * exception is thrown.
+ *
+ */
+ public void testCreateInvalidUserName() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ createInvalidUser("", group);
+ createInvalidUser("0abc", group); // should not start with digits
+ createInvalidUser("a b", group); // should not contain spaces
+ createInvalidUser(" aa", group);
+ createInvalidUser("aa ", group);
+ }
+
+ /**
+ * Creates a new user which conflicts with an existing one. Verifies that
+ * the UserMgtException is thrown and that no user is added.
+ *
+ */
+ public void testCreateDuplicateUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ _admin.createUser(USER1, PASS1, group);
+ try {
+ _admin.createUser(USER1, PASS2, group);
+ fail();
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.DUPLICATE_USER, e.getReason());
+ assertEquals(1, _admin.getUserCount());
+ }
+ }
+
+ /**
+ * Gets a known user by name. Verifies the correct user is obtained.
+ * Verifies that null is returned when trying to obtain an unknown user.
+ *
+ */
+ public void testGetUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ User user2 = _admin.getUser(USER1);
+ assertTrue(user.equals(user2));
+ assertNull(_admin.getUser(USER2));
+ }
+
+ /**
+ * Gets a known group by name. Verifies the correct group is obtained.
+ * Verifies that null is returned when the group is not known.
+ *
+ */
+ public void testGetGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ Group group2 = _admin.getGroup(GROUP1);
+ assertTrue(group.equals(group2));
+ assertNull(_admin.getGroup(GROUP2));
+ }
+
+ /**
+ * Adds a user to a group. Verifies that the user is added using several API
+ * calls. Verifies that an exception occurs if the user is not already part
+ * of the group.
+ *
+ */
+ public void testAddUserToGroup() throws UserMgtException {
+
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ Group group2 = _admin.createGroup(GROUP2);
+ assertTrue(user.isInGroup(group));
+ assertFalse(user.isInGroup(group2));
+ _admin.addUserToGroup(user, group2);
+ assertTrue(user.isInGroup(group));
+ assertTrue(user.isInGroup(group2));
+ Set<User> users = _admin.getUsers(group2);
+ assertNotNull(users);
+ assertEquals(1, users.size());
+ assertTrue(users.contains(user));
+
+ try {
+ _admin.addUserToGroup(user, group);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.USER_ALREADY_IN_GROUP, e
+ .getReason());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Adds a user to a group where the user does not exist. Verifies that an
+ * exception occurs.
+ *
+ */
+ public void testAddUserToGroupUnknownUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = createUser(USER1, PASS1, group);
+ try {
+ _admin.addUserToGroup(user, group);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_USER, e.getReason());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Adds a user to a group where the user does not exist. Verifies that an
+ * exception occurs.
+ *
+ */
+ public void testAddUserToGroupUnknownGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ Group group2 = new Group(GROUP2);
+ try {
+ _admin.addUserToGroup(user, group2);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_GROUP, e.getReason());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Removes a user from a group. Verifies that the user is removed from the
+ * group using several API calls. Verifies that an exception occurs if the
+ * user not part of the group or if the user is only part of one group.
+ */
+ public void testRemoveUserFromGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+
+ User user = _admin.createUser(USER1, PASS1, group);
+ Group group2 = _admin.createGroup(GROUP2);
+ _admin.addUserToGroup(user, group2);
+ Set<Group> groups = user.getGroups();
+ assertEquals(2, groups.size());
+ assertTrue(groups.contains(group));
+ assertTrue(groups.contains(group2));
+
+ _admin.removeUserFromGroup(user, group);
+ groups = user.getGroups();
+ assertEquals(1, groups.size());
+ assertTrue(groups.contains(group2));
+ assertFalse(groups.contains(group));
+ }
+
+ /**
+ * Removes a user from a group where the user is not known. Verifies that an
+ * exception is thrown.
+ *
+ */
+ public void testRemoveUserFromGroupUnknownUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = createUser(USER1, GROUP1, group);
+ try {
+ _admin.removeUserFromGroup(user, group);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_USER, e.getReason());
+ }
+ }
+
+ /**
+ * Removes a user from a group where the group is not known. Verifies that
+ * an exception is thrown.
+ *
+ */
+ public void testRemoveUserFromGroupUnknownGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ Group group2 = new Group(GROUP2);
+ try {
+ _admin.removeUserFromGroup(user, group2);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_GROUP, e.getReason());
+ }
+ }
+
+ /**
+ * Removes a user from a group where the user is only part of one group.
+ * Verifies that an exception is thrown.
+ */
+ public void testRemoveUserFromGroupOnlyGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ try {
+ _admin.removeUserFromGroup(user, group);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.USER_MUST_BE_IN_A_GROUP, e
+ .getReason());
+ }
+ }
+
+ /**
+ * Gets the list of users and groups. Verifies that the correct suers and
+ * groups are returned. Verifies also that the relations from user to group
+ * are correct.
+ *
+ */
+ public void testGetUsersAndGroups() throws UserMgtException {
+ Group group1 = _admin.createGroup(GROUP1);
+ Group group2 = _admin.createGroup(GROUP2);
+
+ User user1 = _admin.createUser(USER1, PASS1, group1);
+ _admin.addUserToGroup(user1, group2);
+ User user2 = _admin.createUser(USER2, PASS2, group2);
+
+ Set<User> users = _admin.getUsers();
+ assertEquals(2, users.size());
+ assertTrue(users.contains(user1));
+ assertTrue(users.contains(user2));
+
+ Set<Group> groups = _admin.getGroups();
+ assertEquals(2, groups.size());
+ assertTrue(groups.contains(group1));
+ assertTrue(groups.contains(group2));
+
+ assertTrue(user1.isInGroup(group1));
+ assertTrue(user1.isInGroup(group2));
+ assertFalse(user2.isInGroup(group1));
+ assertTrue(user2.isInGroup(group2));
+
+ Set<Group> groups1 = user1.getGroups();
+ assertEquals(2, groups1.size());
+
+ Set<Group> groups2 = user2.getGroups();
+ assertEquals(1, groups2.size());
+ }
+
+ /**
+ * Renames a user. Verifies that the user is renamed. Verifies that
+ * exceptions are thrown when an attempt is made to rename the user to
+ * itself or to another existing user, or when the group does not exist.
+ *
+ */
+ public void testRenameUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user1 = _admin.createUser(USER1, PASS1, group);
+ _admin.renameUser(user1, USER2);
+ assertEquals(USER2, user1.getName());
+ assertEquals(user1, _admin.getUser(USER2));
+
+ _admin.createUser(USER1, PASS1, group);
+
+ try {
+ _admin.renameUser(user1, USER1);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.DUPLICATE_USER, e.getReason());
+
+ // do a trivial reanem
+ try {
+ _admin.renameUser(user1, user1.getName());
+ } catch (UserMgtException e2) {
+ assertEquals(UserMgtException.Reason.TRIVIAL_RENAME, e2
+ .getReason());
+ return;
+ }
+ fail();
+ }
+ fail();
+ }
+
+ /**
+ * Renames a user to a user with an invalid username. Verifies that the
+ * appropriate exception is thrown.
+ *
+ */
+ public void testRenameUserInvalidUsername() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user1 = _admin.createUser(USER1, PASS1, group);
+ try {
+ _admin.renameUser(user1, USER2);
+ } catch (UserMgtException e) {
+ assertEquals(e.getReason(), Reason.INVALID_USERNAME);
+ }
+ }
+
+ /**
+ * Renames a group. Verifies that the group is renamed. Verifies that
+ * exceptions are thrown when an attempt is made to rename the group to
+ * itself or to another existing group or when the group does not exist.
+ *
+ */
+ public void testRenameGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ _admin.renameGroup(group, GROUP2);
+ assertEquals(GROUP2, group.getName());
+ assertEquals(group, _admin.getGroup(GROUP2));
+
+ _admin.createGroup(GROUP1);
+ try {
+ _admin.renameGroup(group, GROUP1);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.DUPLICATE_GROUP, e.getReason());
+
+ // do a trivial reanem
+ try {
+ _admin.renameGroup(group, group.getName());
+ } catch (UserMgtException e2) {
+ assertEquals(UserMgtException.Reason.TRIVIAL_RENAME, e2
+ .getReason());
+ return;
+ }
+ fail();
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Renames a group to a group with an invalid name. Verifies that the
+ * appropriate exception is thrown.
+ *
+ */
+ public void testRenameGroupInvalidGroupname() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ try {
+ _admin.renameGroup(group, "a b");
+ } catch (UserMgtException e) {
+ assertEquals(e.getReason(), Reason.INVALID_GROUPNAME);
+ }
+ }
+
+ /**
+ * Removes a user. Verifies that the user is removed. Verifies that the an
+ * exception is thrown when the user does not exist.
+ *
+ */
+ public void testRemoveUser() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+
+ assertEquals(1, _admin.getUserCount());
+ _admin.removeUser(user);
+ assertEquals(0, _admin.getUserCount());
+
+ _admin.createUser(USER1, PASS1, group);
+ assertEquals(1, _admin.getUserCount());
+
+ User user2 = createUser(USER2, PASS2, group);
+
+ try {
+ _admin.removeUser(user2);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_USER, e.getReason());
+ }
+ }
+
+ /**
+ * Removes a group. Verifies that the group is removed. Verifies that the an
+ * exception is thrown when the group does not exist or if there are still
+ * users in the group.
+ *
+ */
+ public void testRemoveGroup() throws UserMgtException {
+ Group group1 = _admin.createGroup(GROUP1);
+ assertEquals(1, _admin.getGroupCount());
+ _admin.removeGroup(group1);
+ assertEquals(0, _admin.getGroupCount());
+ group1 = _admin.createGroup(GROUP1);
+
+ _admin.createUser(USER1, PASS1, group1);
+ try {
+ _admin.removeGroup(group1);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.GROUP_STILL_OCCUPIED, e
+ .getReason());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Tries to remove an unknown group. Verifies that an exception is thrown.
+ *
+ */
+ public void testRemoveGroupUnknownGroup() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ Group group2 = new Group(GROUP2);
+ try {
+ _admin.removeGroup(group2);
+ } catch (UserMgtException e) {
+ assertEquals(UserMgtException.Reason.UNKNOWN_GROUP, e.getReason());
+ }
+ }
+
+ /**
+ * Changes the password, verifies that this succeeds.
+ *
+ * @throws UserMgtException
+ */
+ public void testChangePassword() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ User user = _admin.createUser(USER1, PASS1, group);
+ user.changePassword(PASS1, PASS2);
+
+ // retrieve the user and verifies the password hasn't changed.
+ User user2 = _admin.getUser(USER1);
+ try {
+ user2.checkPassword(PASS2);
+ fail(); // password should not have changed already.
+ } catch (UserMgtException e) {
+ // ok.
+ }
+
+ // now notify the admin of the change in the user
+ _admin.userModified(user);
+
+ user2 = _admin.getUser(USER1);
+ user2.checkPassword(PASS2); // this time it should succeed.
+
+ }
+
+ /**
+ * Performance test. Finds a user by name.
+ *
+ */
+ public void testPerformanceFindUserByName() throws UserMgtException {
+ Group group = _admin.createGroup(GROUP1);
+ _admin.createUser(USER1, PASS1, group);
+
+ int n = 1000;
+ long time = System.currentTimeMillis();
+ for (int i = 0; i < n; i++) {
+ _admin.getUser(USER1);
+ }
+ LOGGER.info("Looked up a user " + n + " times in "
+ + (float) (System.currentTimeMillis() - time) / 1000.0);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.util.Collections;
+
+import org.wamblee.persistence.hibernate.HibernateMappingFiles;
+
+/**
+ * Hibernate mapping files for user management.
+ */
+public class UsermgtHibernateMappingFiles extends HibernateMappingFiles {
+
+ public UsermgtHibernateMappingFiles() {
+ super(new String[] {
+ "hbm/Group.hbm.xml", "hbm/User.hbm.xml"
+ });
+ }
+
+ public UsermgtHibernateMappingFiles(String[] aFiles) {
+ this();
+ Collections.addAll(this, aFiles);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import java.util.Collections;
+
+import org.wamblee.test.SpringConfigFiles;
+
+/**
+ * Spring config files for user management.
+ */
+public class UsermgtSpringConfigFiles extends SpringConfigFiles {
+
+ public UsermgtSpringConfigFiles() {
+ super(new String[] { "spring/test.org.wamblee.security.properties.xml",
+ "spring/test.org.wamblee.security.datasource.xml",
+ "spring/test.org.wamblee.security.database.xml",
+ "spring/test.org.wamblee.security.usermgt.xml" });
+ }
+
+ public UsermgtSpringConfigFiles(String[] aFiles) {
+ this();
+ Collections.addAll(this, aFiles);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt;
+
+import org.wamblee.security.encryption.Md5HexMessageDigester;
+import org.wamblee.usermgt.UserMgtException.Reason;
+
+/**
+ * User management test utilities.
+ */
+public class UsermgtTestUtils {
+
+ private static final String DUMMY_GROUP = "dummygroup";
+ private static final String DUMMY_PASSWD = "dummypasswd";
+
+ public static Group createGroup(String aName) {
+ return new Group(aName);
+ }
+
+ public static User createUser(String aUsername) throws UserMgtException {
+ return createUser(aUsername, DUMMY_GROUP);
+ }
+
+ public static User createUser(String aUsername, String aGroup) throws UserMgtException {
+ return createUser(aUsername, createGroup(aGroup));
+ }
+
+ public static User createUser(String aUsername, Group aGroup) throws UserMgtException {
+ return createUser(aUsername, DUMMY_PASSWD, aGroup);
+ }
+
+ public static User createUser(String aName, String aPassword, Group aGroup) throws UserMgtException {
+ return new User(aName, aPassword, aGroup,
+ new RegexpNameValidator(RegexpNameValidator.PASSWORD_PATTERN,
+ Reason.INVALID_PASSWORD, "Password must be at least 6 chars"),
+ new Md5HexMessageDigester());
+ }
+
+ public static void addUserToGroup(User aUser, Group aGroup) throws UserMgtException {
+ aUser.addGroup(aGroup);
+ }
+
+ public static void removeUserFromGroup(User aUser, Group aGroup) throws UserMgtException {
+ aUser.removeGroup(aGroup);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt.hibernate;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.wamblee.general.BeanKernel;
+import org.wamblee.test.TestTransactionCallback;
+import org.wamblee.usermgt.GroupSet;
+import org.wamblee.usermgt.InMemoryGroupSetTest;
+import org.wamblee.usermgt.UsermgtHibernateMappingFiles;
+import org.wamblee.usermgt.UsermgtSpringConfigFiles;
+
+/**
+ * Tests for {@link org.wamblee.usermgt.hibernate.HibernateGroupSet}
+ */
+public class HibernateGroupSetTest extends InMemoryGroupSetTest {
+
+ private static final String GROUP_TABLE = "GROUPS";
+
+ private static final String GROUP_QUERY = "select * from " + GROUP_TABLE + " where name = ?";
+
+ public HibernateGroupSetTest() {
+ super(UsermgtSpringConfigFiles.class, UsermgtHibernateMappingFiles.class);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#checkGroupCount(int)
+ */
+ @Override
+ protected void checkGroupCount(int aSize) throws SQLException {
+ super.flush();
+ super.checkGroupCount(aSize);
+ assertEquals(aSize, getTableSize(GROUP_TABLE));
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#checkGroupExists(java.lang.String)
+ */
+ @Override
+ protected void checkGroupExists(final String aGroup) throws SQLException {
+ flush();
+ Map<String,Integer> result =
+ executeTransaction(new TestTransactionCallback() {
+ /* (non-Javadoc)
+ * @see org.wamblee.test.TestTransactionCallback#execute()
+ */
+ @Override
+ public Map execute() throws Exception {
+ ResultSet result = executeQuery(GROUP_QUERY, aGroup);
+ Map<String,Integer> res = new HashMap<String,Integer>();
+ res.put("result", countResultSet(result));
+ return res;
+ }
+ });
+
+ int count = result.get("result");
+ assertEquals(1, count);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#checkGroupNotExists(java.lang.String)
+ */
+ @Override
+ protected void checkGroupNotExists(String aGroup) throws SQLException {
+ flush();
+ ResultSet result = executeQuery(GROUP_QUERY, aGroup);
+ assertEquals(0, countResultSet(result));
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#createGroupSet()
+ */
+ @Override
+ protected GroupSet createGroupSet() {
+ return BeanKernel.getBeanFactory().find(GroupSet.class);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt.hibernate;
+
+import java.lang.reflect.Method;
+import java.sql.SQLException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wamblee.cache.Cache;
+import org.wamblee.general.BeanKernel;
+import org.wamblee.test.TestTransactionCallbackWithoutResult;
+import org.wamblee.usermgt.UserAdministration;
+import org.wamblee.usermgt.UserAdministrationImplTest;
+import org.wamblee.usermgt.UsermgtHibernateMappingFiles;
+import org.wamblee.usermgt.UsermgtSpringConfigFiles;
+
+/**
+ * User administration tests with persistence based on Hibernate. This executes
+ * the same test cases as {@link org.wamblee.usermgt.UserAdministrationImplTest}
+ * with in addition, one test case that executes all Hibernate test cases
+ * separately with each test case in its own transaction.
+ */
+public class HibernateUserAdministrationTest extends UserAdministrationImplTest {
+
+ private static final Log LOG = LogFactory.getLog(HibernateUserAdministrationTest.class);
+
+ public HibernateUserAdministrationTest() {
+ super(UsermgtSpringConfigFiles.class,
+ UsermgtHibernateMappingFiles.class);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.UserAdministrationImplTest#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ clearUserCache();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.usermgt.UserAdministrationImplTest#createAdmin()
+ */
+ @Override
+ protected UserAdministration createAdmin() {
+ return BeanKernel.getBeanFactory().find(UserAdministration.class);
+ }
+
+ public void testAllTestsInASeparateTransaction() throws SQLException {
+
+ Method[] methods = UserAdministrationImplTest.class.getMethods();
+ for (final Method method : methods) {
+ if (method.getName().startsWith("test")) {
+ cleanDatabase();
+ clearUserCache();
+ executeTransaction(new TestTransactionCallbackWithoutResult() {
+ public void execute() throws Exception {
+ LOG.info("Running test " + method.getName());
+ try {
+ method.invoke(HibernateUserAdministrationTest.this);
+ } catch (Throwable t) {
+ LOG.error("Test " + method.getName() + " failed");
+ throw new RuntimeException(t.getMessage(), t);
+ }
+ finally {
+ LOG.info("Test " + method.getName() + " finished");
+ }
+
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private void clearUserCache() {
+ BeanKernel.getBeanFactory().find("userCache", Cache.class).clear();
+ }
+}
--- /dev/null
+/*
+ * Copyright 2005 the original author or authors.
+ *
+ * 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 org.wamblee.usermgt.hibernate;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Set;
+
+import org.wamblee.cache.Cache;
+import org.wamblee.general.BeanKernel;
+import org.wamblee.usermgt.Group;
+import org.wamblee.usermgt.GroupSet;
+import org.wamblee.usermgt.InMemoryUserSetTest;
+import org.wamblee.usermgt.User;
+import org.wamblee.usermgt.UserMgtException;
+import org.wamblee.usermgt.UserSet;
+import org.wamblee.usermgt.UsermgtHibernateMappingFiles;
+import org.wamblee.usermgt.UsermgtSpringConfigFiles;
+
+/**
+ * Tests for {@link org.wamblee.usermgt.hibernate.HibernateGroupSet}
+ */
+public class HibernateUserSetTest extends InMemoryUserSetTest {
+
+ private static final String USER_TABLE = "USERS";
+ private static final String GROUP_TABLE = "GROUPS";
+
+ private static final String USER_QUERY = "select * from " + USER_TABLE + " where name = ?";
+ private static final String GROUP_QUERY = "select * from " + GROUP_TABLE + " where name = ?";
+
+ public HibernateUserSetTest() {
+ super(UsermgtSpringConfigFiles.class, UsermgtHibernateMappingFiles.class);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryUserSetTest#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ clearUserCache();
+ }
+
+ /**
+ * Clears the user cache.
+ */
+ private void clearUserCache() {
+ BeanKernel.getBeanFactory().find("userCache", Cache.class).clear();
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#checkGroupCount(int)
+ */
+ @Override
+ protected void checkUserCount(int aSize) throws SQLException {
+ super.flush();
+ super.checkUserCount(aSize);
+ assertEquals(aSize, getTableSize(USER_TABLE));
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#checkGroupExists(java.lang.String)
+ */
+ @Override
+ protected void checkUserExists(String aUser) throws SQLException {
+ flush();
+ ResultSet result = executeQuery(USER_QUERY, aUser);
+ assertEquals(1, countResultSet(result));
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#checkGroupNotExists(java.lang.String)
+ */
+ @Override
+ protected void checkUserNotExists(String aUser) throws SQLException {
+ flush();
+ ResultSet result = executeQuery(USER_QUERY, aUser);
+ assertEquals(0, countResultSet(result));
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#checkGroupCount(int)
+ */
+ @Override
+ protected void checkGroupCount(int aSize) throws SQLException {
+ super.flush();
+ assertEquals(aSize, getTableSize(GROUP_TABLE));
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#checkGroupExists(java.lang.String)
+ */
+ @Override
+ protected void checkGroupExists(String aGroup) throws SQLException {
+ flush();
+
+ ResultSet result = executeQuery(GROUP_QUERY, aGroup);
+ assertEquals(1, countResultSet(result));
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#checkGroupNotExists(java.lang.String)
+ */
+ @Override
+ protected void checkGroupNotExists(String aGroup) throws SQLException {
+ flush();
+ ResultSet result = executeQuery(GROUP_QUERY, aGroup);
+ assertEquals(0, countResultSet(result));
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryGroupSetTest#createGroupSet()
+ */
+ @Override
+ protected UserSet createUserSet() {
+ return BeanKernel.getBeanFactory().find(UserSet.class);
+ }
+
+ /* (non-Javadoc)
+ * @see org.wamblee.usermgt.InMemoryUserSetTest#createGroupSet()
+ */
+ @Override
+ protected GroupSet createGroupSet() {
+ return BeanKernel.getBeanFactory().find(GroupSet.class);
+ }
+
+ /**
+ * Reproduction of a bug.
+ * Create a user which is in group1
+ * Add it to a second group group2.
+ * Remove the user from group1.
+ * Verify the user is in group2.
+ */
+ public void testVerifyAddRemove() throws SQLException, UserMgtException {
+ cleanDatabase(); // just to be sure.
+ GroupSet groups = getGroups();
+ assertEquals(0, groups.size());
+ Group group1 = createGroup("group1");
+ Group group2 = createGroup("group2");
+ groups.add(group1);
+ groups.add(group2);
+ checkGroupExists("group1");
+ checkGroupExists("group2");
+
+ User user = createUser("user", PASSWORD, group1);
+ getUsers().add(user);
+ checkUserExists("user");
+
+ addUserToGroup(user, group2);
+ getUsers().userModified(user);
+ clearUserCache();
+ User user2 = getUsers().find("user");
+ Set<Group> userGroups = user2.getGroups();
+ assertTrue(user2.isInGroup("group1"));
+ assertTrue(user2.isInGroup("group2"));
+ assertEquals(2, userGroups.size());
+
+ removeUserFromGroup(user, group1);
+ getUsers().userModified(user);
+ clearUserCache();
+ user2 = getUsers().find("user");
+ userGroups = user2.getGroups();
+ assertFalse(user2.isInGroup("group1"));
+ assertTrue(user2.isInGroup("group2"));
+ assertEquals(1, userGroups.size());
+ }
+
+}
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+ <hibernate-mapping>
+
+ <class name="org.wamblee.security.authorization.AuthorizationRule"
+ table="AUTHORIZATION_RULES"
+ select-before-update="true"
+ lazy="false">
+ <id name="primaryKey" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <discriminator column="TYPE" type="string"/>
+ <version name="persistedVersion" column="VERSION"/>
+
+ <subclass name="org.wamblee.security.authorization.UrlAuthorizationRule"
+ discriminator-value="ISINGROUP"
+ lazy="false">
+ <property name="authorizationResultString" column="RESULT"/>
+ <property name="resourceClassName" column="RESOURCE_CLASSNAME"/>
+ <many-to-one name="userCondition"
+ class="org.wamblee.security.authorization.UserCondition"
+ column="USERCONDITION_ID"
+ cascade="all"
+ lazy="false"/>
+ <many-to-one name="pathCondition"
+ class="org.wamblee.security.authorization.PathCondition"
+ column="PATHCONDITION_ID"
+ cascade="all"
+ lazy="false"/>
+ <many-to-one name="operationCondition"
+ class="org.wamblee.security.authorization.OperationCondition"
+ column="OPERATIONCONDITION_ID"
+ cascade="all"
+ lazy="false"/>
+ </subclass>
+
+ </class>
+
+
+ </hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+ <hibernate-mapping>
+
+ <class name="org.wamblee.security.authorization.AuthorizationService" table="AUTHORIZATION_SERVICE"
+ select-before-update="true">
+ <id name="primaryKey" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <discriminator column="TYPE" type="string"/>
+ <version name="persistedVersion" column="VERSION"/>
+
+ <subclass name="org.wamblee.security.authorization.DefaultAuthorizationService"
+ discriminator-value="DEFAULT">
+
+ <property name="name" column="NAME"/>
+
+ <list name="mappedRules" table="AUTHORIZATION_SERVICE_RULES" lazy="false" cascade="all-delete-orphan">
+ <key column="ID"/>
+ <index column="POSITION"/>
+ <many-to-many class="org.wamblee.security.authorization.AuthorizationRule"
+ column="RULE_ID"/>
+ </list>
+ </subclass>
+
+ </class>
+
+ <query name="findAuthorizationServiceByName">
+ select service
+ from org.wamblee.security.authorization.AuthorizationService service
+ where service.name = :name
+ </query>
+
+ </hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+ <class name="org.wamblee.usermgt.Group" table="GROUPS" select-before-update="true">
+ <id name="primaryKey" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <version name="persistedVersion" column="VERSION"/>
+ <property name="name" column="NAME" unique="true"/>
+ </class>
+
+ <query name="findGroupByName">
+ from org.wamblee.usermgt.Group grp where grp.name = :name
+ </query>
+
+ <query name="countGroups">
+ select count(*)
+ from org.wamblee.usermgt.Group group
+ </query>
+
+</hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+ <hibernate-mapping>
+
+ <class name="org.wamblee.security.authorization.OperationCondition" table="OPERATION_CONDITIONS"
+ select-before-update="true"
+ lazy="false">
+ <id name="primaryKey" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <discriminator column="TYPE" type="string"/>
+ <version name="persistedVersion" column="VERSION"/>
+
+ <subclass name="org.wamblee.security.authorization.IsaOperationCondition"
+ discriminator-value="ISA"
+ lazy="false">
+ <property name="operationString" column="OPERATION"/>
+ </subclass>
+
+ </class>
+
+
+ </hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+ <hibernate-mapping>
+
+ <class name="org.wamblee.security.authorization.PathCondition" table="PATH_CONDITIONS"
+ select-before-update="true"
+ lazy="false">
+ <id name="primaryKey" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <discriminator column="TYPE" type="string"/>
+ <version name="persistedVersion" column="VERSION"/>
+
+ <subclass name="org.wamblee.security.authorization.StartsWithPathCondition"
+ discriminator-value="STARTS_WITH"
+ lazy="false">
+ <property name="path" column="PATH"/>
+ </subclass>
+
+ </class>
+
+
+ </hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+ <hibernate-mapping>
+ <subclass name="org.wamblee.photos.authorizationrules.PageAuthorizationRule"
+ extends="org.wamblee.security.authorization.UrlAuthorizationRule"
+ discriminator-value="PAGE"
+ lazy="false"/>
+
+ </hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+ <hibernate-mapping>
+
+ <class name="org.wamblee.security.authorization.PathCondition" table="PATH_CONDITIONS"
+ select-before-update="true"
+ lazy="false">
+ <id name="primaryKey" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <discriminator column="TYPE" type="string"/>
+ <version name="persistedVersion" column="VERSION"/>
+
+ <subclass name="org.wamblee.security.authorization.RegexpPathCondition"
+ discriminator-value="REGEXP"
+ lazy="false">
+ <property name="pattern" column="PATTERN"/>
+
+ <subclass name="org.wamblee.security.authorization.StartsWithPathCondition"
+ discriminator-value="STARTS_WITH"
+ lazy="false">
+ </subclass>
+
+ </subclass>
+
+ </class>
+
+
+ </hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+ <hibernate-mapping>
+ <subclass name="org.wamblee.photos.authorizationrules.PhotoAuthorizationRule"
+ extends="org.wamblee.security.authorization.AuthorizationRule"
+ discriminator-value="PHOTOS"
+ lazy="false"/>
+
+ </hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+ <hibernate-mapping>
+ <subclass name="org.wamblee.security.authorization.TestAuthorizationRule"
+ extends="org.wamblee.security.authorization.UrlAuthorizationRule"
+ discriminator-value="TEST"
+ lazy="false"/>
+
+ </hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+ <class name="org.wamblee.usermgt.User" table="USERS" select-before-update="true">
+ <id name="primaryKey" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <version name="persistedVersion" column="VERSION"/>
+ <property name="name" column="NAME" unique="true"/>
+ <property name="passwordString" column="PASSWORD"/>
+ <set name="groupSet" table="USER_GROUPS" lazy="false">
+ <key column="USER_ID"/>
+ <many-to-many class="org.wamblee.usermgt.Group" column="GROUP_ID"/>
+ </set>
+ </class>
+
+ <query name="findUserByName">
+ from org.wamblee.usermgt.User user where user.name = :name
+ </query>
+
+ <query name="findUserByGroupName">
+ select user
+ from org.wamblee.usermgt.User user
+ join user.groupSet grp
+ where grp.name = :name
+ </query>
+
+ <query name="countUsers">
+ select count(*)
+ from org.wamblee.usermgt.User user
+ </query>
+
+
+</hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+ <hibernate-mapping>
+
+ <class name="org.wamblee.security.authorization.UserCondition" table="USER_CONDITIONS"
+ select-before-update="true"
+ lazy="false">
+ <id name="primaryKey" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <discriminator column="TYPE" type="string"/>
+ <version name="persistedVersion" column="VERSION"/>
+
+ <subclass name="org.wamblee.security.authorization.GroupUserCondition"
+ discriminator-value="URL"
+ lazy="false">
+ <property name="group" column="GROUPNAME"/>
+ </subclass>
+
+ <subclass name="org.wamblee.security.authorization.AnyUserCondition"
+ discriminator-value="ANY"
+ lazy="false">
+ </subclass>
+
+ </class>
+
+
+ </hibernate-mapping>
\ No newline at end of file
--- /dev/null
+<ehcache>
+
+ <!-- Sets the path to the directory where cache .data files are created.
+
+ If the path is a Java System Property it is replaced by
+ its value in the running VM.
+
+ The following properties are translated:
+ user.home - User's home directory
+ user.dir - User's current working directory
+ java.io.tmpdir - Default temp file path -->
+ <diskStore path="java.io.tmpdir"/>
+
+
+ <!--Default Cache configuration. These will applied to caches programmatically created through
+ the CacheManager.
+
+ The following attributes are required:
+
+ maxElementsInMemory - Sets the maximum number of objects that will be created in memory
+ eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the
+ element is never expired.
+ overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
+ has reached the maxInMemory limit.
+
+ The following attributes are optional:
+ timeToIdleSeconds - Sets the time to idle for an element before it expires.
+ i.e. The maximum amount of time between accesses before an element expires
+ Is only used if the element is not eternal.
+ Optional attribute. A value of 0 means that an Element can idle for infinity.
+ The default value is 0.
+ timeToLiveSeconds - Sets the time to live for an element before it expires.
+ i.e. The maximum time between creation time and when an element expires.
+ Is only used if the element is not eternal.
+ Optional attribute. A value of 0 means that and Element can live for infinity.
+ The default value is 0.
+ diskPersistent - Whether the disk store persists between restarts of the Virtual Machine.
+ The default value is false.
+ diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value
+ is 120 seconds.
+ -->
+
+ <defaultCache
+ maxElementsInMemory="10000"
+ eternal="false"
+ overflowToDisk="false"
+ timeToIdleSeconds="120"
+ timeToLiveSeconds="120"
+ diskPersistent="false"
+ diskExpiryThreadIntervalSeconds="120"
+ />
+
+ <cache
+ name="users"
+ maxElementsInMemory="10000"
+ eternal="false"
+ overflowToDisk="false"
+ timeToIdleSeconds="120"
+ timeToLiveSeconds="120"
+ diskPersistent="false"
+ diskExpiryThreadIntervalSeconds="120"
+ />
+
+ <cache
+ name="photos"
+ maxElementsInMemory="1000"
+ eternal="false"
+ overflowToDisk="false"
+ timeToIdleSeconds="120"
+ timeToLiveSeconds="120"
+ diskPersistent="false"
+ diskExpiryThreadIntervalSeconds="120"
+ />
+
+</ehcache>
--- /dev/null
+
+###################################################################################
+# dialect
+###################################################################################
+hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
+
+###################################################################################
+# debugging settings: Log4j configuration can provide more detail.
+###################################################################################
+hibernate.show_sql=false
+
+###################################################################################
+# hibernate cache provider
+###################################################################################
+hibernate.cache.provider=org.hibernate.cache.EhCacheProvider
+
+###################################################################################
+# query cache
+###################################################################################
+hibernate.cache.use_query_cache=true
\ No newline at end of file
--- /dev/null
+
+
+# Database properties for test runs in a J2SE environment.
+
+database.driver=com.mysql.jdbc.Driver
+database.url=jdbc:mysql://localhost:3306/test
+database.username=erik
+database.password=abc123
\ No newline at end of file
--- /dev/null
+<ehcache>
+
+ <!-- Sets the path to the directory where cache .data files are created.
+
+ If the path is a Java System Property it is replaced by
+ its value in the running VM.
+
+ The following properties are translated:
+ user.home - User's home directory
+ user.dir - User's current working directory
+ java.io.tmpdir - Default temp file path -->
+ <diskStore path="java.io.tmpdir"/>
+
+
+ <!--Default Cache configuration. These will applied to caches programmatically created through
+ the CacheManager.
+
+ The following attributes are required:
+
+ maxElementsInMemory - Sets the maximum number of objects that will be created in memory
+ eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the
+ element is never expired.
+ overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
+ has reached the maxInMemory limit.
+
+ The following attributes are optional:
+ timeToIdleSeconds - Sets the time to idle for an element before it expires.
+ i.e. The maximum amount of time between accesses before an element expires
+ Is only used if the element is not eternal.
+ Optional attribute. A value of 0 means that an Element can idle for infinity.
+ The default value is 0.
+ timeToLiveSeconds - Sets the time to live for an element before it expires.
+ i.e. The maximum time between creation time and when an element expires.
+ Is only used if the element is not eternal.
+ Optional attribute. A value of 0 means that and Element can live for infinity.
+ The default value is 0.
+ diskPersistent - Whether the disk store persists between restarts of the Virtual Machine.
+ The default value is false.
+ diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value
+ is 120 seconds.
+ -->
+
+ <defaultCache
+ maxElementsInMemory="10000"
+ eternal="false"
+ overflowToDisk="false"
+ timeToIdleSeconds="120"
+ timeToLiveSeconds="120"
+ diskPersistent="false"
+ diskExpiryThreadIntervalSeconds="120"
+ />
+
+ <cache
+ name="users"
+ maxElementsInMemory="10000"
+ eternal="false"
+ overflowToDisk="false"
+ timeToIdleSeconds="120"
+ timeToLiveSeconds="120"
+ diskPersistent="false"
+ diskExpiryThreadIntervalSeconds="120"
+ />
+
+ <cache
+ name="photos"
+ maxElementsInMemory="1000"
+ eternal="false"
+ overflowToDisk="false"
+ timeToIdleSeconds="120"
+ timeToLiveSeconds="120"
+ diskPersistent="false"
+ diskExpiryThreadIntervalSeconds="120"
+ />
+
+</ehcache>
--- /dev/null
+
+###################################################################################
+# dialect
+###################################################################################
+hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
+
+###################################################################################
+# debugging settings: Log4j configuration can provide more detail.
+###################################################################################
+hibernate.show_sql=false
+
+###################################################################################
+# hibernate cache provider
+###################################################################################
+hibernate.cache.provider=org.hibernate.cache.EhCacheProvider
+
+###################################################################################
+# query cache
+###################################################################################
+hibernate.cache.use_query_cache=true
\ No newline at end of file
--- /dev/null
+
+##############################################################################
+# Name of the administrators group
+##############################################################################
+org.wamblee.security.admingroup=administrators
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<beans>
+
+ <bean id="org.wamblee.usermgt.UserAccessor"
+ class="org.wamblee.security.authorization.TestUserAccessor">
+
+ </bean>
+
+ <bean id="org.wamblee.security.authorization.OperationRegistry"
+ class="org.wamblee.security.authorization.DefaultOperationRegistry">
+ <constructor-arg>
+ <list>
+ <bean class="org.wamblee.security.authorization.AllOperation"/>
+ <bean class="org.wamblee.security.authorization.CreateOperation"/>
+ <bean class="org.wamblee.security.authorization.DeleteOperation"/>
+ <bean class="org.wamblee.security.authorization.ReadOperation"/>
+ <bean class="org.wamblee.security.authorization.WriteOperation"/>
+ </list>
+ </constructor-arg>
+ </bean>
+
+ <bean id="org.wamblee.security.authorization.AuthorizationService"
+ class="org.wamblee.security.authorization.hibernate.PersistentAuthorizationService">
+ <constructor-arg><value>DEFAULT</value></constructor-arg>
+ <constructor-arg><ref bean="org.springframework.orm.hibernate3.HibernateTemplate"/></constructor-arg>
+ <constructor-arg><ref bean="org.wamblee.usermgt.UserAccessor"/></constructor-arg>
+ <constructor-arg><value type="long">10000</value></constructor-arg>
+ </bean>
+
+ <!-- any user -->
+ <bean id="anyUserCondition" class="org.wamblee.security.authorization.AnyUserCondition">
+ </bean>
+
+ <!-- administrators -->
+ <bean id="adminUserCondition" class="org.wamblee.security.authorization.GroupUserCondition">
+ <constructor-arg><value>administrators</value></constructor-arg>
+ </bean>
+
+</beans>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<!-- This is the Spring configuration to define the database-related stuff for the
+ all persistence tests. -->
+<beans>
+
+ <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
+ <property name="dataSource">
+ <ref bean="dataSource"/>
+ </property>
+ <property name="hibernateProperties">
+ <props>
+ <prop key="hibernate.dialect">${hibernate.dialect}</prop>
+ <prop key="hibernate.cache.provider_class">${hibernate.cache.provider}</prop>
+ <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
+ <prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
+ </props>
+ </property>
+ <property name="mappingResources"><ref bean="hibernateMappingFiles"/></property>
+ </bean>
+
+ <bean id="transactionManager"
+ class="org.springframework.orm.hibernate3.HibernateTransactionManager">
+ <property name="sessionFactory">
+ <ref local="sessionFactory"/>
+ </property>
+ </bean>
+
+ <!-- Hibernate template used within test code for addition
+ Hibernate-specific stuff -->
+ <bean id="org.springframework.orm.hibernate3.HibernateTemplate"
+ class="org.springframework.orm.hibernate3.HibernateTemplate">
+ <property name="sessionFactory">
+ <ref bean="sessionFactory"/>
+ </property>
+ </bean>
+</beans>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<!-- This is the Spring configuration to define the database-related stuff for the
+ all persistence tests. -->
+ <beans>
+ <bean id="dataSource"
+ class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+ <property name="driverClassName"><value>${database.driver}</value></property>
+ <property name="url"><value>${database.url}</value></property>
+ <property name="username"><value>${database.username}</value></property>
+ <property name="password"><value>${database.password}</value></property>
+ </bean>
+ </beans>
+
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+ <beans>
+
+ <bean id="propertyBean"
+ class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+ <property name="locations">
+ <list>
+ <value>properties/test.org.wamblee.security.hibernate.properties</value>
+ <value>properties/test.org.wamblee.security.usermgt.properties</value>
+ <value>properties/test.org.wamblee.security.database.properties</value>
+ </list>
+ </property>
+ </bean>
+ </beans>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+ <beans>
+
+ <bean id="cacheConfig" class="org.wamblee.io.ClassPathResource">
+ <constructor-arg><value>properties/test.org.wamblee.security.ehcache.xml</value></constructor-arg>
+ </bean>
+
+ <bean id="userCache" class="org.wamblee.cache.EhCache">
+ <constructor-arg><ref local="cacheConfig"/></constructor-arg>
+ <constructor-arg><value>users</value></constructor-arg>
+ </bean>
+
+
+ <bean id="passwordValidator"
+ class="org.wamblee.usermgt.RegexpNameValidator">
+ <constructor-arg><value>.{5,}</value></constructor-arg>
+ <constructor-arg><value>INVALID_PASSWORD</value></constructor-arg>
+ <constructor-arg><value>Password must have at least 5 characters</value></constructor-arg>
+ </bean>
+
+ <bean id="passwordDigester"
+ class="org.wamblee.security.encryption.Md5HexMessageDigester">
+ </bean>
+
+ <bean id="org.wamblee.usermgt.UserSet"
+ class="org.wamblee.usermgt.hibernate.HibernateUserSet">
+ <constructor-arg><ref local="userCache"/></constructor-arg>
+ <constructor-arg><ref local="passwordValidator"/></constructor-arg>
+ <constructor-arg><ref local="passwordDigester"/></constructor-arg>
+
+ <property name="sessionFactory"><ref bean="sessionFactory"/></property>
+
+ </bean>
+
+ <bean id="org.wamblee.usermgt.GroupSet"
+ class="org.wamblee.usermgt.hibernate.HibernateGroupSet">
+
+ <property name="sessionFactory"><ref bean="sessionFactory"/></property>
+ </bean>
+
+ <bean id="org.wamblee.usermgt.UserAdministration-target"
+ class="org.wamblee.usermgt.UserAdministrationImpl">
+
+ <constructor-arg>
+ <ref local="org.wamblee.usermgt.UserSet"/>
+ </constructor-arg>
+
+ <constructor-arg>
+ <ref local="org.wamblee.usermgt.GroupSet"/>
+ </constructor-arg>
+
+ <constructor-arg>
+ <bean class="org.wamblee.usermgt.RegexpNameValidator">
+ <constructor-arg><value>[a-zA-Z]+[a-zA-Z0-9]*</value></constructor-arg>
+ <constructor-arg><value>INVALID_USERNAME</value></constructor-arg>
+ <constructor-arg><value></value></constructor-arg>
+ </bean>
+ </constructor-arg>
+
+ <constructor-arg>
+ <bean class="org.wamblee.usermgt.RegexpNameValidator">
+ <constructor-arg><value>[a-zA-Z]+[a-zA-Z0-9]*</value></constructor-arg>
+ <constructor-arg><value>INVALID_GROUPNAME</value></constructor-arg>
+ <constructor-arg><value></value></constructor-arg>
+ </bean>
+ </constructor-arg>
+
+ </bean>
+
+ <bean id="usermanagement-lock" class="org.wamblee.concurrency.JvmLock"/>
+
+ <bean id="usermanagement-lock-advice" class="org.wamblee.concurrency.LockAdvice">
+ <constructor-arg><ref bean="usermanagement-lock"/></constructor-arg>
+ </bean>
+
+ <bean id="org.wamblee.usermgt.UserAdministration"
+ class="org.springframework.aop.framework.ProxyFactoryBean">
+ <property name="proxyInterfaces"><value>org.wamblee.usermgt.UserAdministration</value></property>
+ <property name="interceptorNames"><value>usermanagement-lock-advice</value></property>
+ <property name="target"><ref bean="org.wamblee.usermgt.UserAdministration-target"/></property>
+ </bean>
+
+ <bean id="usermgtInitializer"
+ class="org.wamblee.usermgt.UserAdminInitializer">
+ <constructor-arg><ref local="org.wamblee.usermgt.UserAdministration"/></constructor-arg>
+ <!-- users -->
+ <constructor-arg>
+ <list>
+ <value>erik</value>
+ <value>admin</value>
+ </list>
+ </constructor-arg>
+ <!-- groups -->
+ <constructor-arg>
+ <list>
+ <value>users</value>
+ <value>${org.wamblee.security.admingroup}</value>
+ </list>
+ </constructor-arg>
+ <!-- passwords -->
+ <constructor-arg>
+ <list>
+ <value>abc123</value>
+ <value>abc123</value>
+ </list>
+ </constructor-arg>
+ </bean>
+
+ </beans>
\ No newline at end of file
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
}
/**
- * Executes an SQL query within a transaction.
+ * Executes an SQL query.
*
* @param aSql
* Query to execute.
}
/**
- * Executes a query within a transaction. See
+ * Executes a query. See
* {@link #setPreparedParam(int, PreparedStatement, Object)}for details on
* supported argument types.
*
* @return Result set.
*/
public ResultSet executeQuery(final String aSql, final Object[] aArgs) {
- Map results = executeTransaction(new TestTransactionCallback() {
- public Map execute() throws Exception {
- Connection connection = getConnection();
-
- PreparedStatement statement = connection.prepareStatement(aSql);
- setPreparedParams(aArgs, statement);
+ try {
+ Connection connection = getConnection();
- ResultSet resultSet = statement.executeQuery();
- TreeMap results = new TreeMap();
- results.put("resultSet", resultSet);
+ PreparedStatement statement = connection.prepareStatement(aSql);
+ setPreparedParams(aArgs, statement);
- return results;
- }
- });
-
- return (ResultSet) results.get("resultSet");
+ return statement.executeQuery();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
}
/**
* @return
* @throws SQLException
*/
- protected int getTableSize(String aTable) throws SQLException {
+ protected int getTableSize(final String aTable) throws SQLException {
+
ResultSet resultSet = executeQuery("select * from " + aTable);
int count = 0;
while (resultSet.next()) {
count++;
}
-
return count;
}