Merged changes from the import branch that were accidentally committed into the trunk.
git-svn-id: https://svn.apache.org/repos/asf/incubator/jsecurity/trunk@749350 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/common.ant.xml b/common.ant.xml
index 4d833a0..74fb5b8 100644
--- a/common.ant.xml
+++ b/common.ant.xml
@@ -95,9 +95,10 @@
<fileset dir="@{srcdir}">
<include name="**/*"/>
<exclude name="**/*.java"/>
+ <exclude name="**/*.tld"/>
</fileset>
</copy>
- <copy todir="@{destdir}" preservelastmodified="true">
+ <copy todir="@{destdir}/META-INF" flatten="true" preservelastmodified="true">
<fileset dir="@{srcdir}">
<include name="**/*.tld"/>
</fileset>
@@ -120,6 +121,7 @@
<jar jarfile="${dist.jar}">
<fileset dir="${classes.dir}">
<include name="**"/>
+ <exclude name="META-INF/**"/>
</fileset>
<metainf dir="${classes.dir}/META-INF">
<include name="**"/>
diff --git a/core/src/org/jsecurity/authc/pam/AbstractAuthenticationStrategy.java b/core/src/org/jsecurity/authc/pam/AbstractAuthenticationStrategy.java
index 9161af3..adf2baa 100644
--- a/core/src/org/jsecurity/authc/pam/AbstractAuthenticationStrategy.java
+++ b/core/src/org/jsecurity/authc/pam/AbstractAuthenticationStrategy.java
@@ -24,14 +24,14 @@
import java.util.Collection;
/**
- * Abstract base implementation for JSecurity's concrete <code>ModularAuthenticationStrategy</code>
+ * Abstract base implementation for JSecurity's concrete <code>AuthenticationStrategy</code>
* implementations.
*
* @author Jeremy Haile
* @author Les Hazlewood
* @since 0.9
*/
-public abstract class AbstractAuthenticationStrategy implements ModularAuthenticationStrategy {
+public abstract class AbstractAuthenticationStrategy implements AuthenticationStrategy {
/**
* Simply returns <code>new {@link SimpleAuthenticationInfo SimpleAuthenticationInfo}();</code>, which supports
diff --git a/core/src/org/jsecurity/authc/pam/AllSuccessfulModularAuthenticationStrategy.java b/core/src/org/jsecurity/authc/pam/AllSuccessfulStrategy.java
similarity index 95%
rename from core/src/org/jsecurity/authc/pam/AllSuccessfulModularAuthenticationStrategy.java
rename to core/src/org/jsecurity/authc/pam/AllSuccessfulStrategy.java
index bfb233f..29f1407 100644
--- a/core/src/org/jsecurity/authc/pam/AllSuccessfulModularAuthenticationStrategy.java
+++ b/core/src/org/jsecurity/authc/pam/AllSuccessfulStrategy.java
@@ -27,7 +27,7 @@
import org.jsecurity.realm.Realm;
/**
- * <tt>ModularAuthenticationStrategy</tt> implementation that requires <em>all</em> configured realms to
+ * <tt>AuthenticationStrategy</tt> implementation that requires <em>all</em> configured realms to
* <b>successfully</b> process the submitted <tt>AuthenticationToken</tt> during the log-in attempt.
*
* <p>If one or more realms do not support the submitted token, or one or more are unable to acquire
@@ -37,10 +37,10 @@
* @author Les Hazlewood
* @since 0.2
*/
-public class AllSuccessfulModularAuthenticationStrategy extends AbstractAuthenticationStrategy {
+public class AllSuccessfulStrategy extends AbstractAuthenticationStrategy {
/** Private class log instance. */
- private static final Log log = LogFactory.getLog(AllSuccessfulModularAuthenticationStrategy.class);
+ private static final Log log = LogFactory.getLog(AllSuccessfulStrategy.class);
/**
* Because all realms in this strategy must complete successfully, this implementation ensures that the given
diff --git a/core/src/org/jsecurity/authc/pam/AtLeastOneSuccessfulModularAuthenticationStrategy.java b/core/src/org/jsecurity/authc/pam/AtLeastOneSuccessfulStrategy.java
similarity index 87%
rename from core/src/org/jsecurity/authc/pam/AtLeastOneSuccessfulModularAuthenticationStrategy.java
rename to core/src/org/jsecurity/authc/pam/AtLeastOneSuccessfulStrategy.java
index 0206507..7a23069 100644
--- a/core/src/org/jsecurity/authc/pam/AtLeastOneSuccessfulModularAuthenticationStrategy.java
+++ b/core/src/org/jsecurity/authc/pam/AtLeastOneSuccessfulStrategy.java
@@ -23,7 +23,7 @@
import org.jsecurity.authc.AuthenticationToken;
/**
- * <tt>ModularAuthenticationStrategy</tt> implementation that requires <em>at least one</em> configured realm to
+ * <tt>AuthenticationStrategy</tt> implementation that requires <em>at least one</em> configured realm to
* successfully process the submitted <tt>AuthenticationToken</tt> during the log-in attempt.
*
* <p>This means any number of configured realms do not have to support the submitted log-in token, or they may
@@ -33,13 +33,13 @@
* <p>Note that this implementation will aggregate the account data from <em>all</em> successfully consulted
* realms during the authentication attempt. If you want only the account data from the first successfully
* consulted realm and want to ignore all subsequent realms, use the
- * {@link FirstSuccessfulAuthenticationStrategy FirstSuccessfulAuthenticationStrategy} instead.
+ * {@link FirstSuccessfulStrategy FirstSuccessfulAuthenticationStrategy} instead.
*
* @author Les Hazlewood
- * @see FirstSuccessfulAuthenticationStrategy FirstSuccessfulAuthenticationStrategy
+ * @see FirstSuccessfulStrategy FirstSuccessfulAuthenticationStrategy
* @since 0.2
*/
-public class AtLeastOneSuccessfulModularAuthenticationStrategy extends AbstractAuthenticationStrategy {
+public class AtLeastOneSuccessfulStrategy extends AbstractAuthenticationStrategy {
/**
* Ensures that the <code>aggregate</code> method argument is not <code>null</code> and
diff --git a/core/src/org/jsecurity/authc/pam/ModularAuthenticationStrategy.java b/core/src/org/jsecurity/authc/pam/AuthenticationStrategy.java
similarity index 93%
rename from core/src/org/jsecurity/authc/pam/ModularAuthenticationStrategy.java
rename to core/src/org/jsecurity/authc/pam/AuthenticationStrategy.java
index 4676b06..707f8e6 100644
--- a/core/src/org/jsecurity/authc/pam/ModularAuthenticationStrategy.java
+++ b/core/src/org/jsecurity/authc/pam/AuthenticationStrategy.java
@@ -26,7 +26,7 @@
import java.util.Collection;
/**
- * A <tt>ModularAuthenticationStrategy</tt> implementation assists the {@link ModularRealmAuthenticator} during the
+ * A <tt>AuthenticationStrategy</tt> implementation assists the {@link ModularRealmAuthenticator} during the
* log-in process in a pluggable realm (PAM) environment.
*
* <p>The <tt>ModularRealmAuthenticator</tt> will consult implementations of this interface on what to do during each
@@ -34,12 +34,12 @@
* attempt must be successful for all realms, only 1 or more realms, no realms, etc.
*
* @author Les Hazlewood
- * @see org.jsecurity.authc.pam.AllSuccessfulModularAuthenticationStrategy AllSuccessfulModularAuthenticationStrategy
- * @see org.jsecurity.authc.pam.AtLeastOneSuccessfulModularAuthenticationStrategy AtLeastOneSuccessfulModularAuthenticationStrategy
- * @see org.jsecurity.authc.pam.FirstSuccessfulAuthenticationStrategy FirstSuccessfulAuthenticationStrategy
+ * @see AllSuccessfulStrategy AllSuccessfulAuthenticationStrategy
+ * @see AtLeastOneSuccessfulStrategy AtLeastOneSuccessfulAuthenticationStrategy
+ * @see FirstSuccessfulStrategy FirstSuccessfulAuthenticationStrategy
* @since 0.2
*/
-public interface ModularAuthenticationStrategy {
+public interface AuthenticationStrategy {
/**
* Method invoked by the ModularAuthenticator signifying that the authentication process is about to begin for the
diff --git a/core/src/org/jsecurity/authc/pam/FirstSuccessfulAuthenticationStrategy.java b/core/src/org/jsecurity/authc/pam/FirstSuccessfulStrategy.java
similarity index 84%
rename from core/src/org/jsecurity/authc/pam/FirstSuccessfulAuthenticationStrategy.java
rename to core/src/org/jsecurity/authc/pam/FirstSuccessfulStrategy.java
index e7af122..c8637a5 100644
--- a/core/src/org/jsecurity/authc/pam/FirstSuccessfulAuthenticationStrategy.java
+++ b/core/src/org/jsecurity/authc/pam/FirstSuccessfulStrategy.java
@@ -26,17 +26,17 @@
import java.util.Collection;
/**
- * {@link ModularAuthenticationStrategy} implementation that only accepts the account data from
+ * {@link AuthenticationStrategy} implementation that only accepts the account data from
* the first successfully consulted Realm and ignores all subsequent realms. This is slightly
* different behavior than
- * {@link org.jsecurity.authc.pam.AtLeastOneSuccessfulModularAuthenticationStrategy AtLeastOneSuccessfulModularAuthenticationStrategy},
+ * {@link AtLeastOneSuccessfulStrategy AtLeastOneSuccessfulAuthenticationStrategy},
* so please review both to see which one meets your needs better.
*
* @author Les Hazlewood
- * @see org.jsecurity.authc.pam.AtLeastOneSuccessfulModularAuthenticationStrategy AtLeastOneSuccessfulModularAuthenticationStrategy
+ * @see AtLeastOneSuccessfulStrategy AtLeastOneSuccessfulAuthenticationStrategy
* @since 0.9
*/
-public class FirstSuccessfulAuthenticationStrategy extends AbstractAuthenticationStrategy {
+public class FirstSuccessfulStrategy extends AbstractAuthenticationStrategy {
/**
* Returns <code>null</code> immediately, relying on this class's {@link #merge merge} implementation to return
diff --git a/core/src/org/jsecurity/authc/pam/ModularRealmAuthenticator.java b/core/src/org/jsecurity/authc/pam/ModularRealmAuthenticator.java
index 8797f33..3bda973 100644
--- a/core/src/org/jsecurity/authc/pam/ModularRealmAuthenticator.java
+++ b/core/src/org/jsecurity/authc/pam/ModularRealmAuthenticator.java
@@ -46,7 +46,7 @@
* authenticator allows customized behavior for interpreting what happens when interacting with multiple realms - for
* example, you might require all realms to be successful during the attempt, or perhaps only at least one must be
* successful, or some other interpretation. This customized behavior can be performed via the use of a
- * {@link #setModularAuthenticationStrategy(ModularAuthenticationStrategy) ModularAuthenticationStrategy}, which
+ * {@link #setAuthenticationStrategy(AuthenticationStrategy) AuthenticationStrategy}, which
* you can inject as a property of this class.
*
* <p>The strategy object provides callback methods that allow you to
@@ -54,13 +54,13 @@
* in a mult-realm scenario, the strategy object is only utilized when more than one Realm is configured.
*
* <p>For greater security in a multi-realm configuration, unless overridden, the default implementation is the
- * {@link AllSuccessfulModularAuthenticationStrategy AllSuccessfulModularAuthenticationStrategy}
+ * {@link AllSuccessfulStrategy AllSuccessfulAuthenticationStrategy}
*
* @author Jeremy Haile
* @author Les Hazlewood
* @see #setRealms
- * @see AllSuccessfulModularAuthenticationStrategy
- * @see AtLeastOneSuccessfulModularAuthenticationStrategy
+ * @see AllSuccessfulStrategy
+ * @see AtLeastOneSuccessfulStrategy
* @since 0.1
*/
public class ModularRealmAuthenticator extends AbstractAuthenticator {
@@ -81,27 +81,27 @@
/**
* The authentication strategy to use during authentication attempts.
*/
- private ModularAuthenticationStrategy modularAuthenticationStrategy;
+ private AuthenticationStrategy authenticationStrategy;
/*--------------------------------------------
| C O N S T R U C T O R S |
============================================*/
/**
* Default no-argument constructor which
- * {@link #setModularAuthenticationStrategy(ModularAuthenticationStrategy) enables} a
- * {@link org.jsecurity.authc.pam.AllSuccessfulModularAuthenticationStrategy AllSuccessfulModularAuthenticationStrategy}
+ * {@link #setAuthenticationStrategy(AuthenticationStrategy) enables} a
+ * {@link AllSuccessfulStrategy AllSuccessfulAuthenticationStrategy}
* by default.
*/
public ModularRealmAuthenticator() {
- ModularAuthenticationStrategy strategy = new AllSuccessfulModularAuthenticationStrategy();
- setModularAuthenticationStrategy(strategy);
+ AuthenticationStrategy strategy = new AllSuccessfulStrategy();
+ setAuthenticationStrategy(strategy);
}
/**
* Constructor which initializes this <code>Authenticator</code> with a single realm to use during
* an authentiation attempt. Because
- * this would set a single realm, no {@link #setModularAuthenticationStrategy(ModularAuthenticationStrategy)
- * modularAuthenticationStrategy} would be used during authentication attempts.
+ * this would set a single realm, no {@link #setAuthenticationStrategy(AuthenticationStrategy)
+ * AuthenticationStrategy} would be used during authentication attempts.
*
* @param realm the realm to consult during an authentication attempt.
*/
@@ -113,7 +113,7 @@
* Constructor which initializes this <code>Authenticator</code> with multiple realms that will be
* consulted during an authentication attempt, effectively enabling PAM (Pluggable Authentication Module)
* behavior according to the configured
- * {@link #setModularAuthenticationStrategy(ModularAuthenticationStrategy) ModularAuthenticationStrategy}.
+ * {@link #setAuthenticationStrategy(AuthenticationStrategy) AuthenticationStrategy}.
*
* @param realms the realms to consult during an authentication attempt.
*/
@@ -155,29 +155,29 @@
}
/**
- * Returns the <tt>ModularAuthenticationStrategy</tt> utilized by this modular authenticator during a multi-realm
+ * Returns the <tt>AuthenticationStrategy</tt> utilized by this modular authenticator during a multi-realm
* log-in attempt. This object is only used when two or more Realms are configured.
*
* <p>Unless overridden by
- * the {@link #setModularAuthenticationStrategy(ModularAuthenticationStrategy)} method, the default implementation
- * is the {@link AllSuccessfulModularAuthenticationStrategy}.
+ * the {@link #setAuthenticationStrategy(AuthenticationStrategy)} method, the default implementation
+ * is the {@link AllSuccessfulStrategy}.
*
- * @return the <tt>ModularAuthenticationStrategy</tt> utilized by this modular authenticator during a log-in attempt.
+ * @return the <tt>AuthenticationStrategy</tt> utilized by this modular authenticator during a log-in attempt.
* @since 0.2
*/
- public ModularAuthenticationStrategy getModularAuthenticationStrategy() {
- return modularAuthenticationStrategy;
+ public AuthenticationStrategy getAuthenticationStrategy() {
+ return authenticationStrategy;
}
/**
- * Allows overriding the default <tt>ModularAuthenticationStrategy</tt> utilized during multi-realm log-in attempts.
+ * Allows overriding the default <tt>AuthenticationStrategy</tt> utilized during multi-realm log-in attempts.
* This object is only used when two or more Realms are configured.
*
- * @param modularAuthenticationStrategy the strategy implementation to use during log-in attempts.
+ * @param authenticationStrategy the strategy implementation to use during log-in attempts.
* @since 0.2
*/
- public void setModularAuthenticationStrategy(ModularAuthenticationStrategy modularAuthenticationStrategy) {
- this.modularAuthenticationStrategy = modularAuthenticationStrategy;
+ public void setAuthenticationStrategy(AuthenticationStrategy authenticationStrategy) {
+ this.authenticationStrategy = authenticationStrategy;
}
/*--------------------------------------------
@@ -223,7 +223,7 @@
}
/**
- * Performs the multi-realm authentication attempt by calling back to a {@link ModularAuthenticationStrategy} object
+ * Performs the multi-realm authentication attempt by calling back to a {@link AuthenticationStrategy} object
* as each realm is consulted for <tt>AuthenticationInfo</tt> for the specified <tt>token</tt>.
*
* @param realms the multiple realms configured on this Authenticator instance.
@@ -233,7 +233,7 @@
*/
protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) {
- ModularAuthenticationStrategy strategy = getModularAuthenticationStrategy();
+ AuthenticationStrategy strategy = getAuthenticationStrategy();
AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);
diff --git a/core/src/org/jsecurity/authc/pam/UnsupportedTokenException.java b/core/src/org/jsecurity/authc/pam/UnsupportedTokenException.java
index b96faf6..070e756 100644
--- a/core/src/org/jsecurity/authc/pam/UnsupportedTokenException.java
+++ b/core/src/org/jsecurity/authc/pam/UnsupportedTokenException.java
@@ -26,7 +26,7 @@
* supported by one or more configured {@link org.jsecurity.realm.Realm Realm}s.
*
* @author Les Hazlewood
- * @see ModularAuthenticationStrategy
+ * @see AuthenticationStrategy
* @since 0.2
*/
public class UnsupportedTokenException extends AuthenticationException {
diff --git a/core/src/org/jsecurity/authc/pam/package-info.java b/core/src/org/jsecurity/authc/pam/package-info.java
index 4763ab6..4a4a7d5 100644
--- a/core/src/org/jsecurity/authc/pam/package-info.java
+++ b/core/src/org/jsecurity/authc/pam/package-info.java
@@ -27,6 +27,6 @@
* <p/>
* How the <code>ModularRealmAuthenticator</code> actually coordinates this behavior is configurable based on your
* application's needs using an injectible
- * {@link org.jsecurity.authc.pam.ModularAuthenticationStrategy ModularAuthenticationStrategy}.
+ * {@link AuthenticationStrategy}.
*/
package org.jsecurity.authc.pam;
\ No newline at end of file
diff --git a/core/src/org/jsecurity/mgt/AuthenticatingSecurityManager.java b/core/src/org/jsecurity/mgt/AuthenticatingSecurityManager.java
index a064223..8d94565 100644
--- a/core/src/org/jsecurity/mgt/AuthenticatingSecurityManager.java
+++ b/core/src/org/jsecurity/mgt/AuthenticatingSecurityManager.java
@@ -19,7 +19,7 @@
package org.jsecurity.mgt;
import org.jsecurity.authc.*;
-import org.jsecurity.authc.pam.ModularAuthenticationStrategy;
+import org.jsecurity.authc.pam.AuthenticationStrategy;
import org.jsecurity.authc.pam.ModularRealmAuthenticator;
import org.jsecurity.util.LifecycleUtils;
@@ -89,20 +89,20 @@
}
/**
- * Sets the {@link org.jsecurity.authc.pam.ModularAuthenticationStrategy ModularAuthenticationStrategy} to use
+ * Sets the {@link org.jsecurity.authc.pam.AuthenticationStrategy} to use
* in multi-realm environments.
*
- * @param strategy the <code>ModularAuthenticationStrategy</code> to use in multi-realm environments.
+ * @param strategy the <code>AuthenticationStrategy</code> to use in multi-realm environments.
*/
- public void setModularAuthenticationStrategy(ModularAuthenticationStrategy strategy) {
+ public void setAuthenticationStrategy(AuthenticationStrategy strategy) {
if (!(this.authenticator instanceof ModularRealmAuthenticator)) {
- String msg = "Configuring a ModularAuthenticationStrategy is only applicable when the underlying " +
+ String msg = "Configuring a AuthenticationStrategy is only applicable when the underlying " +
"Authenticator implementation is a " + ModularRealmAuthenticator.class.getName() +
" implementation. This SecurityManager has been configured with an Authenticator of type " +
this.authenticator.getClass().getName();
throw new IllegalStateException(msg);
}
- ((ModularRealmAuthenticator) this.authenticator).setModularAuthenticationStrategy(strategy);
+ ((ModularRealmAuthenticator) this.authenticator).setAuthenticationStrategy(strategy);
}
/**
@@ -130,7 +130,7 @@
public void setAuthenticationListeners(Collection<AuthenticationListener> listeners) {
assertAuthenticatorListenerSupport();
if (!(this.authenticator instanceof AuthenticationListenerRegistrar)) {
- String msg = "Configuring a ModularAuthenticationStrategy is only applicable when the underlying " +
+ String msg = "Configuring a AuthenticationStrategy is only applicable when the underlying " +
"Authenticator implementation is a " + AuthenticationListenerRegistrar.class.getName() +
" implementation. This SecurityManager has been configured with an Authenticator of type " +
this.authenticator.getClass().getName() + ", which does not implement that interface.";
diff --git a/core/src/org/jsecurity/realm/SimpleAccountRealm.java b/core/src/org/jsecurity/realm/SimpleAccountRealm.java
index fdc262a..1673783 100644
--- a/core/src/org/jsecurity/realm/SimpleAccountRealm.java
+++ b/core/src/org/jsecurity/realm/SimpleAccountRealm.java
@@ -140,12 +140,16 @@
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
SimpleAccount account = (SimpleAccount) getAuthorizationCache().get(upToken.getUsername());
- if (account.isLocked()) {
- throw new LockedAccountException("Account [" + account + "] is locked.");
- }
- if (account.isCredentialsExpired()) {
- String msg = "The credentials for account [" + account + "] are expired";
- throw new ExpiredCredentialsException(msg);
+ if( account != null ) {
+
+ if (account.isLocked()) {
+ throw new LockedAccountException("Account [" + account + "] is locked.");
+ }
+ if (account.isCredentialsExpired()) {
+ String msg = "The credentials for account [" + account + "] are expired";
+ throw new ExpiredCredentialsException(msg);
+ }
+
}
return account;
diff --git a/core/src/org/jsecurity/realm/jdbc/JdbcRealm.java b/core/src/org/jsecurity/realm/jdbc/JdbcRealm.java
index 4daaf55..5768f4b 100644
--- a/core/src/org/jsecurity/realm/jdbc/JdbcRealm.java
+++ b/core/src/org/jsecurity/realm/jdbc/JdbcRealm.java
@@ -274,7 +274,9 @@
// Retrieve roles and permissions from database
roleNames = getRoleNamesForUser(conn, username);
- permissions = getPermissions(conn, username, roleNames);
+ if( permissionsLookupEnabled ) {
+ permissions = getPermissions(conn, username, roleNames);
+ }
} catch (SQLException e) {
final String message = "There was a SQL error while authorizing user [" + username + "]";
diff --git a/core/src/org/jsecurity/realm/text/TextConfigurationRealm.java b/core/src/org/jsecurity/realm/text/TextConfigurationRealm.java
index 5762897..b9a5488 100644
--- a/core/src/org/jsecurity/realm/text/TextConfigurationRealm.java
+++ b/core/src/org/jsecurity/realm/text/TextConfigurationRealm.java
@@ -205,7 +205,9 @@
Map<String, String> pairs = new HashMap<String, String>();
for (String pairString : keyValuePairs) {
String[] pair = StringUtils.splitKeyValue(pairString);
- pairs.put(pair[0].trim(), pair[1].trim());
+ if( pair != null ) {
+ pairs.put(pair[0].trim(), pair[1].trim());
+ }
}
return pairs;
diff --git a/core/test/org/jsecurity/authc/pam/AllSuccessfulModularAuthenticationStrategyTest.java b/core/test/org/jsecurity/authc/pam/AllSuccessfulStrategyTest.java
similarity index 90%
rename from core/test/org/jsecurity/authc/pam/AllSuccessfulModularAuthenticationStrategyTest.java
rename to core/test/org/jsecurity/authc/pam/AllSuccessfulStrategyTest.java
index 65dc10d..5442c64 100644
--- a/core/test/org/jsecurity/authc/pam/AllSuccessfulModularAuthenticationStrategyTest.java
+++ b/core/test/org/jsecurity/authc/pam/AllSuccessfulStrategyTest.java
@@ -26,17 +26,17 @@
import org.jsecurity.realm.Realm;
import org.jsecurity.realm.SimpleAccountRealm;
import org.jsecurity.subject.PrincipalCollection;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
-public class AllSuccessfulModularAuthenticationStrategyTest {
+public class AllSuccessfulStrategyTest {
- private AllSuccessfulModularAuthenticationStrategy strategy;
+ private AllSuccessfulStrategy strategy;
@Before
public void setUp() {
- strategy = new AllSuccessfulModularAuthenticationStrategy();
+ strategy = new AllSuccessfulStrategy();
}
@Test
diff --git a/ivy.xml b/ivy.xml
index 945c03b..3f2cd37 100644
--- a/ivy.xml
+++ b/ivy.xml
@@ -71,6 +71,10 @@
<dependency org="javax.servlet" name="jstl" rev="1.2" transitive="false" conf="samples"/>
<dependency org="taglibs" name="standard" rev="1.1.2" transitive="false" conf="samples"/>
<dependency org="hsqldb" name="hsqldb" rev="1.8.0.7" transitive="false" conf="samples"/>
+ <dependency org="org.hibernate" name="ejb3-persistence" rev="1.0.2.GA" conf="samples"/>
+ <dependency org="org.hibernate" name="hibernate-annotations" rev="3.2.1.ga" conf="samples">
+ <exclude org="javax.transaction"/>
+ </dependency>
<dependency org="org.hibernate" name="hibernate" rev="3.2.6.ga" conf="samples">
<!-- JTA 1.0.1b jar is not allowed in the Maven repo because of Sun's binary license, so we have to
download it explictly from another location (we use Geronimo's version) -->
@@ -87,99 +91,6 @@
<artifact name="docbook-libs" type="zip" ext="zip"/>
</dependency>
- <!-- TODO: move these contents (old library_versions.txt file) into appropriate places in this document. -->
- <!-- This file lists all 3rd party libraries (and their versions!!!) that
- are required to build or run the project.
-
- If you're a developer editing this file, please keep all listings in alphabetical order for
- convenient lookup.
-
- Some notes:
-
- - Each 3rd party library is stored in a directory named after the
- open-source project or company that created it. This makes for
- easy organization of lots of libs.
-
- - Jar files stored _do not_ have version numbers
- actually in their file name. If the jar originally comes as such,
- it is renamed with the version number stripped off. The version
- number is instead maintained in this file. The reason for this is
- so that every time we need to upgrade any 3rd party library,
- we don't have to edit any build.xml or properies files to reflect
- a potential name change due to a version number - you just note
- that change once in this file and overwrite the old jar, checking
- in that overwrite to CVS in the process.
-
- - Each 3rd party lib is listed here along with what it is
- used for and if its needed for build-time, run-time or both.
-
- - Thanks to the gents working on the Spring Framework (http://www.springframework.org)
- that provided the template and the idea for this file.
-
- * atunit/atunut.jar
- - AtUnit 1.0
- - Used in unit tests
-
- * easymock/easymock.jar, easymockclassextension.jar
- - EasyMock 2.2 w/ ClassExtension 2.2 (http://www.easymock.org)
- - Used in test cases for creating dynamic mock objects
-
- * ehcache/ehcache.jar
- - ehcache 1.3.0 (http://ehcache.sourceforge.net/)
- - Required for compiling, using ehcache cache manager, and for runtime session management
-
- * google-collections/google-collect.jar
- - Google Collections Snapshot 20071022
- - Used in test cases for conveniently constructing collections
-
- * hsqldb/hsqldb.jar
- - HSQLDB 1.8.0.7 (http://www.hsqldb.org)
- - Used in the sample application to show an example of a JDBC-based Realm.
-
- * j2ee/jsp-api.jar
- - JSP API 2.0 (http://java.sun.com/products/jsp)
- - Required for building the RI tag libraries
-
- * j2ee/servlet-api.jar
- - Servlet API 2.4 (http://java.sun.com/products/servlet)
- - required for building web support classes (Servlet Filters, etc)
-
- * jakarta-commons/commons-beanutils-core.jar
- - Commons BeanUtils 1.7.0 (http://jakarta.apache.org/commons/beanutils/index.html)
- - required for building and running JSecurity
- - used for constructing Permissions in the Reference Implementation's PermissionAnnotationAuthorizationModule
-
- * jboss/jboss-aop.jar
- - JBoss AOP jar from the JBoss 4.0.4.GA Application Server release
- - Required at build time for JBoss integration support classes.
-
- * jug/jug.jar
- - Java Uuid Genrator (JUG) v. 2.0.0 (Apache 2.0 jar) (http://jug.safehaus.org/)
- - used as a fallback UUID generator for memory-based session management if below Java 1.5
-
- * junit/junit.jar
- - JUnit Test Framework 4.1 (http://www.junit.org)
- - Required for building and running test cases
-
- * log4j/log4j.jar
- - Log4J 1.2.9 (http://logging.apache.org/log4j)
- - required by the RI during build and runtime for logging support
-
- * quartz/quartz.jar
- - Quartz 1.5.2 (http://www.opensymphony.com/quartz)
- - required during build and runtime for Quartz-based session validation support
-
- * retroweaver/retroweaver.jar,retroweaver-rt.jar
- - Retroweaver 2.0 (http://retroweaver.sourceforge.net)
- - required for retroweaving to support JDK 1.3 and 1.4
- - rt jar is required at runtime if running in 1.3 or 1.4
-
- * spring/spring.jar
- - Spring Application Framework 2.0.2 (http://springframework.org)
- - required to build Spring integration support and sample apps
- -->
-
-
</dependencies>
</ivy-module>
\ No newline at end of file
diff --git a/samples/spring-hibernate/build.xml b/samples/spring-hibernate/build.xml
index 33713d9..74d3a3f 100644
--- a/samples/spring-hibernate/build.xml
+++ b/samples/spring-hibernate/build.xml
@@ -56,9 +56,11 @@
<target name="compile" depends="compile.src"/> <!-- no test classes, no need to depend on compile.test -->
<target name="war">
- <war warfile="${dist.war}" webxml="WEB-INF/web.xml">
+ <echo message="DIST DIR: ${dist.dir}"/>
+ <war warfile="${dist.war}" webxml="web/WEB-INF/web.xml">
<lib dir="${dist.dir}" includes="*.jar"/>
- <lib dir="${root.dist.dir}" includes="jsecurity.jar"/>
+ <lib dir="${dist.dir}/samples" includes="jsecurity-samples-sprhib*.jar"/>
+ <lib dir="${dist.dir}/modules" includes="*.jar"/>
<lib dir="${lib.dir}/samples">
<include name="jstl-*.jar"/>
<include name="standard-*.jar"/>
@@ -72,15 +74,16 @@
<!-- Hibernate libs: -->
<lib dir="${lib.dir}/samples">
<include name="hibernate-*.jar"/>
+ <include name="persistence-api-*.jar"/>
<include name="antlr-*.jar"/>
<include name="asm-attrs-*.jar"/>
<include name="asm-*.jar"/>
<include name="cglib-*.jar"/>
- <include name="geronimo-jta_1.0.1B_spec.jar"/>
+ <include name="geronimo-jta_1.0.1B_spec-*.jar"/>
<include name="dom4j-*.jar"/>
<include name="commons-collections-*.jar"/>
</lib>
- <fileset dir="${base.dir}" includes="**" excludes="**/web.xml, **/build.xml"/>
+ <fileset dir="${base.dir}/web" includes="**" excludes="**/web.xml, **/build.xml"/>
</war>
</target>
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/BootstrapDataPopulator.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/BootstrapDataPopulator.java
new file mode 100644
index 0000000..4f90700
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/BootstrapDataPopulator.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.dao;
+
+import org.hibernate.SessionFactory;
+import org.jsecurity.crypto.hash.Sha256Hash;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+
+/**
+ * Loads sample data for the sample app since it's an in-memory database.
+ */
+@Component
+public class BootstrapDataPopulator implements InitializingBean {
+
+ private DataSource dataSource;
+ private SessionFactory sessionFactory;
+
+ @Autowired
+ public void setDataSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ // Session factory is only injected to ensure it is initialized before this runs
+ @Autowired
+ public void setSessionFactory(SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ }
+
+ public void afterPropertiesSet() throws Exception {
+ //because we're using an in-memory hsqldb for the sample app, a new one will be created each time the
+ //app starts, so insert the sample admin user at startup:
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource);
+
+ jdbcTemplate.execute( "insert into roles values (1, 'user', 'The default role given to all users.')" );
+ jdbcTemplate.execute( "insert into roles values (2, 'admin', 'The administrator role only given to site admins')" );
+ jdbcTemplate.execute( "insert into roles_permissions values (2, 'user:*')" );
+ jdbcTemplate.execute( "insert into users(id,username,email,password) values (1, 'admin', 'sample@jsecurity.org', '" + new Sha256Hash("admin").toHex() + "')" );
+ jdbcTemplate.execute( "insert into users_roles values (1, 2)" );
+
+
+ }
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/HibernateDao.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/HibernateDao.java
new file mode 100644
index 0000000..65aedd5
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/HibernateDao.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.dao;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.orm.hibernate3.SessionFactoryUtils;
+
+/**
+ * Convenience superclass for DAOs that contains annotations for injecting the session factory
+ * and accessing the session.
+ */
+public abstract class HibernateDao {
+
+ private SessionFactory sessionFactory;
+
+ @Autowired
+ public void setSessionFactory(SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ }
+
+ public Session getSession() {
+ return SessionFactoryUtils.getSession(this.sessionFactory, true);
+ }
+
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/HibernateUserDAO.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/HibernateUserDAO.java
new file mode 100644
index 0000000..9107ca5
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/HibernateUserDAO.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.dao;
+
+import org.jsecurity.samples.sprhib.model.User;
+import org.springframework.stereotype.Repository;
+import org.springframework.util.Assert;
+
+import java.util.List;
+
+@Repository("userDAO")
+@SuppressWarnings("unchecked")
+public class HibernateUserDAO extends HibernateDao implements UserDAO {
+
+ public User getUser(Long userId) {
+ return (User) getSession().get(User.class, userId);
+ }
+
+ public User findUser(String username) {
+ Assert.hasText(username);
+ String query = "from User u where u.username = :username";
+ return (User) getSession().createQuery(query).setString("username", username).uniqueResult();
+ }
+
+ public void createUser(User user) {
+ getSession().save( user );
+ }
+
+ public List<User> getAllUsers() {
+ return getSession().createQuery("from User order by username").list();
+ }
+
+ public void deleteUser(Long userId) {
+ User user = getUser(userId);
+ if( user != null ) {
+ getSession().delete(user);
+ }
+ }
+
+ public void updateUser(User user) {
+ getSession().update(user);
+ }
+
+}
+
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/eis/UserDAO.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/UserDAO.java
similarity index 68%
rename from samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/eis/UserDAO.java
rename to samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/UserDAO.java
index ef42eea..a6a7ca5 100644
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/eis/UserDAO.java
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/dao/UserDAO.java
@@ -16,20 +16,26 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jsecurity.samples.sprhib.party.eis;
+package org.jsecurity.samples.sprhib.dao;
-import org.jsecurity.samples.sprhib.eis.PrimaryClassDAO;
-import org.jsecurity.samples.sprhib.party.User;
+import org.jsecurity.samples.sprhib.model.User;
+
+import java.util.List;
/**
- * @author Les Hazlewood
+ * Data Access Object for User related operations.
*/
-public interface UserDAO extends PrimaryClassDAO {
+public interface UserDAO {
- public User getUser(Long userId);
+ User getUser(Long userId);
- public User findUser(String username);
+ User findUser(String username);
- //public User findUserByEmail( String email );
+ void createUser(User user);
+ List<User> getAllUsers();
+
+ void deleteUser(Long userId);
+
+ void updateUser(User user);
}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/DataAccessObject.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/DataAccessObject.java
deleted file mode 100644
index 1e5e0e0..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/DataAccessObject.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.eis;
-
-import java.io.Serializable;
-import java.util.Collection;
-
-/**
- * Behavioral specification for any object specializing in accessing, updating, and storing data in
- * an EIS. The methods are common to all forms of EIS's, not just relational databases, meaning
- * this interface should be implemented by <i>all</i> DataAccessObject implementations, regardless
- * of the EIS technology.
- *
- * @author Les Hazlewood
- */
-public interface DataAccessObject {
-
- /**
- * Returns the generated ID for the given entity.
- *
- * @param entity the entity to create in the EIS.
- * @return the generated id after entity creation in the EIS.
- */
- Serializable create(Object entity);
-
- void update(Object entity);
-
- void delete(Object entity);
-
- void deleteById(Class entityType, Serializable id);
-
- void deleteAll(Collection entities);
-}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/PrimaryClassDAO.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/PrimaryClassDAO.java
deleted file mode 100644
index 863cebf..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/PrimaryClassDAO.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.eis;
-
-import org.springframework.dao.DataAccessException;
-
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * A convenience behavioral specification for DataAccessObjects that primarily work with one
- * Object/Class type.
- *
- * Implementations of this interface are by no means restricted to working with their primary type
- * only; indeed they may "know" about any Class needed to accomplish their tasks. This
- * interface is merely intended to specify convenience behaviors common to all DAO's that
- * <i>mostly</i> work with one data type.
- *
- * @author Les Hazlewood
- */
-public interface PrimaryClassDAO extends DataAccessObject {
-
- /**
- * Returns the primary class for which this DAO is responsible. Most Data Access Objects will
- * work on behalf of a specific object type (e.g. User, Post, etc.). Implementations of this
- * interface may of course work with any other classes as needed, but a PrimaryClassDAO always
- * has one primary target class it "knows" about for convenience.
- *
- * @return the primary class this DAO works with.
- */
- Class getPrimaryClass();
-
- /**
- * Reads/retrieves the object of type <code>getPrimaryClass()</code> with the specified id.
- *
- * @param entityId the id identifying the object to retrieve.
- * @return the object with the given entityId
- * @throws org.springframework.dao.DataAccessException
- * if there is an error accessing the EIS, or if no object of type
- * <code>getPrimaryClass()</code> with an id of <code>entityId</code> exists in the
- * EIS.
- */
- Object read(Serializable entityId) throws DataAccessException;
-
- /**
- * Retrieves all instances of type <code>getPrimaryClass()</code> found in the EIS. Use this
- * method judiciously as a very large result set will no doubt incur a performance penalty.
- *
- * @return a List of instances of type <code>getPriamaryClass()</code> found in the EIS.
- * @throws DataAccessException if an error occurs accessing the EIS.
- */
- List readAll() throws DataAccessException;
-
- /**
- * Deletes/Removes the entity of type <code>getPrimaryClass()</code> in the EIS identified by
- * <code>entityId</code>. Cascading deletes of other objects may be performed by the EIS if the
- * EIS is configured to do so.
- *
- * @param entityId the EIS id of the record to delete.
- * @throws DataAccessException if there is an error accessing the EIS.
- */
- void deleteById(Serializable entityId) throws DataAccessException;
-
- /**
- * Deletes <b>all</b> instances of type <code>getPrimaryClass()</code> found in the EIS.
- * Cascading deletes of other objects may be performed by the EIS if the EIS is configured to do
- * so. <b>Only use this method if you're sure you want to delete all objects of the primary
- * type</b>.
- *
- * @throws DataAccessException if there is an error accessing the EIS.
- */
- void deleteAll() throws DataAccessException;
-
-}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/hibernate/GenericEnumUserType.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/hibernate/GenericEnumUserType.java
deleted file mode 100644
index 119a47b..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/hibernate/GenericEnumUserType.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.eis.hibernate;
-
-import org.hibernate.HibernateException;
-import org.hibernate.type.NullableType;
-import org.hibernate.type.TypeFactory;
-import org.hibernate.usertype.EnhancedUserType;
-import org.hibernate.usertype.ParameterizedType;
-
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.Properties;
-
-/**
- * Implements a generic enum user type identified / represented by a single identifier / column.
- *
- *
- * <ul> <li>The enum type being represented by the certain user type must be set by using the
- * 'enumClass' property.</li> <li>The identifier representing a enum value is retrieved by the
- * identifierMethod. The name of the identifier method can be specified by the 'identifierMethod'
- * property and by default the name() method is used.</li> <li>The identifier type is automatically
- * determined by the return-type of the identifierMethod.</li> <li>The valueOfMethod is the name of
- * the static factory method returning the enumeration object being represented by the given
- * indentifier. The valueOfMethod's name can be specified by setting the 'valueOfMethod' property.
- * The default valueOfMethod's name is 'valueOf'.</li> </ul> </p> <p>Example of an enum type
- * represented by an int value:
- * <pre><code>
- * public enum SimpleNumber {
- * Unknown(-1), Zero(0), One(1), Two(2), Three(3);
- *
- * public int toInt() { return value; }
- *
- * public SimpleNumber fromInt(int value) {
- * switch(value) {
- * case 0: return Zero;
- * case 1: return One;
- * case 2: return Two;
- * case 3: return Three;
- * default: return Unknown;
- * }
- * }
- * }</code></pre>
- *
- * <p>The Mapping would look like this:
- * <pre><code>
- * <typedef name="SimpleNumber" class="GenericEnumUserType">
- * <param name="enumClass">SimpleNumber</param>
- * <param name="identifierMethod">toInt</param>
- * <param name="valueOfMethod">fromInt</param>
- * </typedef>
- * <class ...>
- * ...
- * <property name="number" column="number" type="SimpleNumber"/>
- * </class></code></pre>
- *
- * @author Martin Kersten
- * @author Les Hazlewood
- * @since 05.05.2005
- */
-@SuppressWarnings(value = "unchecked")
-public class GenericEnumUserType implements EnhancedUserType, ParameterizedType {
-
- private Class<? extends Enum> enumClass;
-
- private Method identifierMethod;
- private Method valueOfMethod;
-
- private static final String defaultIdentifierMethodName = "name";
- private static final String defaultValueOfMethodName = "valueOf";
-
- private static final Class[] NULL_CLASS_VARARG = null;
- private static final Object[] NULL_OBJECT_VARARG = null;
- private static final char SINGLE_QUOTE = '\'';
-
- private NullableType type;
- private int[] sqlTypes;
-
- public void setParameterValues(Properties parameters) {
- String enumClassName = parameters.getProperty("enumClass");
- try {
- enumClass = Class.forName(enumClassName).asSubclass(Enum.class);
- }
- catch (ClassNotFoundException exception) {
- throw new HibernateException("Enum class not found", exception);
- }
-
- String identifierMethodName =
- parameters.getProperty("identifierMethod", defaultIdentifierMethodName);
-
- Class<?> identifierType;
- try {
- identifierMethod = enumClass.getMethod(identifierMethodName, NULL_CLASS_VARARG);
- identifierType = identifierMethod.getReturnType();
- }
- catch (Exception exception) {
- throw new HibernateException("Failed to obtain identifier method", exception);
- }
-
- type = (NullableType) TypeFactory.basic(identifierType.getName());
-
- if (type == null) {
- throw new HibernateException("Unsupported identifier type " + identifierType.getName());
- }
-
- sqlTypes = new int[]{type.sqlType()};
-
- String valueOfMethodName =
- parameters.getProperty("valueOfMethod", defaultValueOfMethodName);
-
- try {
- valueOfMethod = enumClass.getMethod(valueOfMethodName, identifierType);
- }
- catch (Exception exception) {
- throw new HibernateException("Failed to obtain valueOf method", exception);
- }
- }
-
- public Class returnedClass() {
- return enumClass;
- }
-
- public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
- throws HibernateException, SQLException {
- Object identifier = type.get(rs, names[0]);
- if (identifier == null || rs.wasNull()) {
- return null;
- }
- try {
- return valueOfMethod.invoke(enumClass, identifier);
- } catch (Exception exception) {
- String msg = "Exception while invoking valueOfMethod [" + valueOfMethod.getName() +
- "] of Enum class [" + enumClass.getName() + "] with argument of type [" +
- identifier.getClass().getName() + "], value=[" + identifier + "]";
- throw new HibernateException(msg, exception);
- }
- }
-
- public void nullSafeSet(PreparedStatement st, Object value, int index)
- throws HibernateException, SQLException {
- if (value == null) {
- st.setNull(index, sqlTypes[0]);
- } else {
- try {
- Object identifier = identifierMethod.invoke(value, NULL_OBJECT_VARARG);
- type.set(st, identifier, index);
- } catch (Exception exception) {
- String msg = "Exception while invoking identifierMethod [" + identifierMethod.getName() +
- "] of Enum class [" + enumClass.getName() +
- "] with argument of type [" + value.getClass().getName() + "], value=[" + value + "]";
- throw new HibernateException(msg, exception);
- }
- }
- }
-
- public int[] sqlTypes() {
- return sqlTypes;
- }
-
- public Object assemble(Serializable cached, Object owner) throws HibernateException {
- return cached;
- }
-
- public Object deepCopy(Object value) throws HibernateException {
- return value;
- }
-
- public Serializable disassemble(Object value) throws HibernateException {
- return (Serializable) value;
- }
-
- public String objectToSQLString(Object value) {
- return SINGLE_QUOTE + ((Enum) value).name() + SINGLE_QUOTE;
- }
-
- public String toXMLString(Object value) {
- return ((Enum) value).name();
- }
-
- public Object fromXMLString(String xmlValue) {
- return Enum.valueOf(enumClass, xmlValue);
- }
-
- public boolean equals(Object x, Object y) throws HibernateException {
- return x == y;
- }
-
- public int hashCode(Object x) throws HibernateException {
- return x.hashCode();
- }
-
- public boolean isMutable() {
- return false;
- }
-
- public Object replace(Object original, Object target, Object owner)
- throws HibernateException {
- return original;
- }
-}
-
-
-
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/hibernate/HibernateDAO.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/hibernate/HibernateDAO.java
deleted file mode 100644
index 75bc498..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/hibernate/HibernateDAO.java
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.eis.hibernate;
-
-import org.hibernate.Filter;
-import org.hibernate.LockMode;
-import org.hibernate.ReplicationMode;
-import org.hibernate.criterion.DetachedCriteria;
-import org.jsecurity.samples.sprhib.eis.DataAccessObject;
-import org.springframework.dao.DataAccessException;
-import org.springframework.orm.hibernate3.HibernateCallback;
-import org.springframework.orm.hibernate3.HibernateOperations;
-import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Simplifies hibernate usage and enhances readability for subclasses so they don't have to call
- * <code>getHibernateTemplate()</code> for every Hibernate operation.
- *
- * @author Les Hazlewood
- */
-public class HibernateDAO extends HibernateDaoSupport
- implements HibernateOperations, DataAccessObject {
-
- public Object execute(HibernateCallback action) throws DataAccessException {
- return getHibernateTemplate().execute(action);
- }
-
- public List executeFind(HibernateCallback action) throws DataAccessException {
- return getHibernateTemplate().executeFind(action);
- }
-
- public Object get(Class entityClass, Serializable id) throws DataAccessException {
- return getHibernateTemplate().get(entityClass, id);
- }
-
- public Object get(Class entityClass, Serializable id, LockMode lockMode)
- throws DataAccessException {
- return getHibernateTemplate().get(entityClass, id, lockMode);
- }
-
- public Object get(String entityName, Serializable id) throws DataAccessException {
- return getHibernateTemplate().get(entityName, id);
- }
-
- public Object get(String entityName, Serializable id, LockMode lockMode)
- throws DataAccessException {
- return getHibernateTemplate().get(entityName, id, lockMode);
- }
-
- public Object load(Class entityClass, Serializable id) throws DataAccessException {
- return getHibernateTemplate().load(entityClass, id);
- }
-
- public Object load(Class entityClass, Serializable id, LockMode lockMode)
- throws DataAccessException {
- return getHibernateTemplate().load(entityClass, id, lockMode);
- }
-
- public Object load(String entityName, Serializable id) throws DataAccessException {
- return getHibernateTemplate().load(entityName, id);
- }
-
- public Object load(String entityName, Serializable id, LockMode lockMode)
- throws DataAccessException {
- return getHibernateTemplate().load(entityName, id, lockMode);
- }
-
- public List loadAll(Class entityClass) throws DataAccessException {
- return getHibernateTemplate().loadAll(entityClass);
- }
-
- public void load(Object entity, Serializable id) throws DataAccessException {
- getHibernateTemplate().load(entity, id);
- }
-
- public void refresh(Object entity) throws DataAccessException {
- getHibernateTemplate().refresh(entity);
- }
-
- public void refresh(Object entity, LockMode lockMode) throws DataAccessException {
- getHibernateTemplate().refresh(entity, lockMode);
- }
-
- public boolean contains(Object entity) throws DataAccessException {
- return getHibernateTemplate().contains(entity);
- }
-
- public void evict(Object entity) throws DataAccessException {
- getHibernateTemplate().evict(entity);
- }
-
- public void initialize(Object proxy) throws DataAccessException {
- getHibernateTemplate().initialize(proxy);
- }
-
- public Filter enableFilter(String string) throws IllegalStateException {
- return getHibernateTemplate().enableFilter(string);
- }
-
- public void lock(Object entity, LockMode lockMode) throws DataAccessException {
- getHibernateTemplate().lock(entity, lockMode);
- }
-
- public void lock(String entityName, Object entity, LockMode lockMode)
- throws DataAccessException {
- getHibernateTemplate().lock(entityName, entity, lockMode);
- }
-
- public Serializable create(Object entity) {
- return save(entity);
- }
-
- public Serializable save(Object entity) throws DataAccessException {
- return getHibernateTemplate().save(entity);
- }
-
- public Serializable save(String entityName, Object entity) throws DataAccessException {
- return getHibernateTemplate().save(entityName, entity);
- }
-
- public void update(Object entity) throws DataAccessException {
- getHibernateTemplate().update(entity);
- }
-
- public void update(Object entity, LockMode lockMode) throws DataAccessException {
- getHibernateTemplate().update(entity, lockMode);
- }
-
- public void update(String entityName, Object entity) throws DataAccessException {
- getHibernateTemplate().update(entityName, entity);
- }
-
- public void update(String entityName, Object entity, LockMode lockMode)
- throws DataAccessException {
- getHibernateTemplate().update(entityName, entity, lockMode);
- }
-
- public void saveOrUpdate(Object entity) throws DataAccessException {
- getHibernateTemplate().saveOrUpdate(entity);
- }
-
- public void saveOrUpdate(String entityName, Object entity) throws DataAccessException {
- getHibernateTemplate().saveOrUpdate(entityName, entity);
- }
-
- public void saveOrUpdateAll(Collection entities) throws DataAccessException {
- getHibernateTemplate().saveOrUpdateAll(entities);
- }
-
- public void replicate(Object object, ReplicationMode replicationMode) throws DataAccessException {
- getHibernateTemplate().replicate(object, replicationMode);
- }
-
- public void replicate(String string, Object object, ReplicationMode replicationMode) throws DataAccessException {
- getHibernateTemplate().replicate(string, object, replicationMode);
- }
-
- public void persist(Object entity) throws DataAccessException {
- getHibernateTemplate().persist(entity);
- }
-
- public void persist(String entityName, Object entity) throws DataAccessException {
- getHibernateTemplate().persist(entityName, entity);
- }
-
- public Object merge(Object entity) throws DataAccessException {
- return getHibernateTemplate().merge(entity);
- }
-
- public Object merge(String entityName, Object entity) throws DataAccessException {
- return getHibernateTemplate().merge(entityName, entity);
- }
-
- public void delete(Object entity) throws DataAccessException {
- getHibernateTemplate().delete(entity);
- }
-
- public void delete(Object entity, LockMode lockMode) throws DataAccessException {
- getHibernateTemplate().delete(entity, lockMode);
- }
-
- public void delete(String s, Object o) throws DataAccessException {
- getHibernateTemplate().delete(s, o);
- }
-
- public void delete(String s, Object o, LockMode lockMode) throws DataAccessException {
- getHibernateTemplate().delete(s, o, lockMode);
- }
-
- public void deleteById(Class entityType, Serializable id) {
- delete(load(entityType, id));
- }
-
- public void delete(Collection entities) {
- deleteAll(entities);
- }
-
- public void deleteAll(Collection entities) throws DataAccessException {
- getHibernateTemplate().deleteAll(entities);
- }
-
- public void flush() throws DataAccessException {
- getHibernateTemplate().flush();
- }
-
- public void clear() throws DataAccessException {
- getHibernateTemplate().clear();
- }
-
- public List find(String queryString) throws DataAccessException {
- return getHibernateTemplate().find(queryString);
- }
-
- public List find(String queryString, Object value) throws DataAccessException {
- return getHibernateTemplate().find(queryString, value);
- }
-
- public List find(String queryString, Object[] values) throws DataAccessException {
- return getHibernateTemplate().find(queryString, values);
- }
-
- /**
- * Execute a query for persistent instances expecting only a single result. If no results
- * are returned from the query, this method returns <tt>null</tt>.
- *
- * @param queryString a query expressed in Hibernate's query language
- * @return the single object returned from the query, or <tt>null</tt> if no results were
- * returned from the query.
- * @throws org.springframework.dao.IncorrectResultSizeDataAccessException
- * if more than 1 result is returned
- * @throws org.springframework.dao.DataAccessException
- * in case of Hibernate errors
- * @see org.hibernate.Session#createQuery
- */
- public Object findSingle(String queryString) throws DataAccessException {
- return findSingle(queryString, (Object[]) null);
- }
-
- /**
- * Execute a query expecting a single persistent instance, binding
- * one value to a "?" parameter in the query string.
- *
- * @param queryString a query expressed in Hibernate's query language
- * @param value the value of the parameter
- * @return the single object returned from the query, or <tt>null</tt> if no results were
- * returned from the query.
- * @throws org.springframework.dao.IncorrectResultSizeDataAccessException
- * if more than 1 result is returned
- * @throws org.springframework.dao.DataAccessException
- * in case of Hibernate errors
- * @see org.hibernate.Session#createQuery
- */
- public Object findSingle(String queryString, Object value) {
- return findSingle(queryString, new Object[]{value});
- }
-
- /**
- * Execute a query expecting a single persistent instance, binding a
- * number of values to "?" parameters in the query string.
- *
- * @param queryString a query expressed in Hibernate's query language
- * @param values the values of the parameters
- * @return the single object returned from the query, or <tt>null</tt> if no results were
- * returned from the query.
- * @throws org.springframework.dao.IncorrectResultSizeDataAccessException
- * if more than 1 result is returned
- * @throws org.springframework.dao.DataAccessException
- * in case of Hibernate errors
- * @see org.hibernate.Session#createQuery
- */
- public Object findSingle(String queryString, Object[] values) throws DataAccessException {
- List results = find(queryString, values);
-
- if (results != null && !results.isEmpty()) {
- return results.get(0);
- }
-
- return null;
- }
-
- public List findByCriteria(DetachedCriteria criteria) throws DataAccessException {
- return getHibernateTemplate().findByCriteria(criteria);
- }
-
- public List findByCriteria(DetachedCriteria criteria, int firstResult, int maxResults)
- throws DataAccessException {
- return getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults);
- }
-
- public List findByExample(Object object) throws DataAccessException {
- return getHibernateTemplate().findByExample(object);
- }
-
- public List findByExample(Object object, int i, int i1) throws DataAccessException {
- return getHibernateTemplate().findByExample(object, i, i1);
- }
-
- public List findByExample(String entityName, Object exampleEntity) throws DataAccessException {
- return getHibernateTemplate().findByExample(entityName, exampleEntity);
- }
-
- public List findByExample(String entityName, Object exampleEntity, int firstResult, int maxResults) throws DataAccessException {
- return getHibernateTemplate().findByExample(entityName, exampleEntity, firstResult, maxResults);
- }
-
- public List findByNamedParam(String queryName, String paramName, Object value)
- throws DataAccessException {
- return getHibernateTemplate().findByNamedParam(queryName, paramName, value);
- }
-
- public List findByNamedParam(String queryString, String[] paramNames, Object[] values)
- throws DataAccessException {
- return getHibernateTemplate().findByNamedParam(queryString, paramNames, values);
- }
-
- public List findByValueBean(String queryString, Object valueBean) throws DataAccessException {
- return getHibernateTemplate().findByValueBean(queryString, valueBean);
- }
-
- public List findByNamedQuery(String queryName) throws DataAccessException {
- return getHibernateTemplate().findByNamedQuery(queryName);
- }
-
- public List findByNamedQuery(String queryName, Object value) throws DataAccessException {
- return getHibernateTemplate().findByNamedQuery(queryName, value);
- }
-
- public List findByNamedQuery(String queryName, Object[] values) throws DataAccessException {
- return getHibernateTemplate().findByNamedQuery(queryName, values);
- }
-
- public List findByNamedQueryAndNamedParam(String queryName, String paramName, Object value)
- throws DataAccessException {
- return getHibernateTemplate().findByNamedQueryAndNamedParam(queryName, paramName, value);
- }
-
- public List findByNamedQueryAndNamedParam(String queryName, String[] paramNames,
- Object[] values) throws DataAccessException {
- return getHibernateTemplate().findByNamedQueryAndNamedParam(queryName, paramNames, values);
- }
-
- public List findByNamedQueryAndValueBean(String queryName, Object valueBean)
- throws DataAccessException {
- return getHibernateTemplate().findByNamedQueryAndValueBean(queryName, valueBean);
- }
-
- public Iterator iterate(String queryString) throws DataAccessException {
- return getHibernateTemplate().iterate(queryString);
- }
-
- public Iterator iterate(String queryString, Object value) throws DataAccessException {
- return getHibernateTemplate().iterate(queryString, value);
- }
-
- public Iterator iterate(String queryString, Object[] values) throws DataAccessException {
- return getHibernateTemplate().iterate(queryString, values);
- }
-
- public void closeIterator(Iterator it) throws DataAccessException {
- getHibernateTemplate().closeIterator(it);
- }
-
- public int bulkUpdate(String string) throws DataAccessException {
- return getHibernateTemplate().bulkUpdate(string);
- }
-
- public int bulkUpdate(String string, Object object) throws DataAccessException {
- return getHibernateTemplate().bulkUpdate(string, object);
- }
-
- public int bulkUpdate(String string, Object[] objects) throws DataAccessException {
- return getHibernateTemplate().bulkUpdate(string, objects);
- }
-
-}
-
-
-
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/hibernate/PrimaryClassHibernateDAO.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/hibernate/PrimaryClassHibernateDAO.java
deleted file mode 100644
index 4aa60b5..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/eis/hibernate/PrimaryClassHibernateDAO.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.eis.hibernate;
-
-import org.jsecurity.samples.sprhib.eis.PrimaryClassDAO;
-import org.springframework.dao.DataAccessException;
-
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * @author Les Hazlewood
- */
-public class PrimaryClassHibernateDAO extends HibernateDAO
- implements PrimaryClassDAO {
-
- protected Class primaryClass;
-
- public final Class getPrimaryClass() {
- return primaryClass;
- }
-
- public final void setPrimaryClass(Class clazz) {
- primaryClass = clazz;
- }
-
- protected final void checkDaoConfiguration() throws Exception {
- if (getPrimaryClass() == null) {
- String msg = "Primary class property must be set";
- throw new IllegalArgumentException(msg);
- }
- }
-
- public Object read(Serializable entityId) throws DataAccessException {
- return load(getPrimaryClass(), entityId);
- }
-
-
- public final List readAll() throws DataAccessException {
- return loadAll(getPrimaryClass());
- }
-
-
- public void deleteById(final Serializable id) throws DataAccessException {
- deleteById(getPrimaryClass(), id);
- }
-
- public void deleteAll() throws DataAccessException {
- deleteAll(readAll());
- }
-
-}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/entity/Entity.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/entity/Entity.java
deleted file mode 100644
index 27c3573..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/entity/Entity.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.entity;
-
-import java.io.Serializable;
-
-/**
- * Root parent class for all persistent object entities.
- *
- * <p><b>NOTE:</b> Subclasses should <b>always</b> provide a unique
- * onEquals() and hashCode() implementation and these should <em>not</em> use
- * the {@link #getId id} property. Always keep in mind the subclass' 'business keys' aka 'natural keys'
- * when implementing these two methods.
- *
- * <p>This class was borrowed from the <a href="http://code.google.com/p/pojodm">PojoDM Project</a>'s
- * <a href="http://code.google.com/p/pojodm/source/browse/trunk/src/org/pojodm/entity/Entity.java">Entity.java</a>
- * for a quick kickstart.</p>
- *
- * @author Les Hazlewood
- */
-public abstract class Entity implements Identifiable, Serializable, Cloneable {
-
- /**
- * RDBMS Primary key, aka 'surrogate key'. <code>Long</code> surrogate keys are best
- * for RDBMS performance (for many reasons that can't be expanded on here)
- * But, every single table should _always_ have a 'business key' or 'natural key' - a unique
- * constraint across one or more columns that guarantee row duplicates will
- * never occur. A <code>null</code> value means the object hasn't been persisted to the RDBMS
- */
- protected Long id = null;
-
- /**
- * Used for optimistic locking to ensure two threads (even across different machines)
- * don't simultaneously overwrite entity state. This propert is not necessarily used by all subclasses, but
- * it is pretty much required if in a high-concurrency environment and/or if using distributed
- * caching in a cluster. It (and its corresponding mutator methods) is not called
- * 'version' to prevent eliminating that name from subclasses should the business
- * domain naming conventions require it. Also 'entityVersion' is self-documenting
- * and leaves little room for incorrect interpretation.
- */
- protected int entityVersion = -1;
-
- public Entity() {
- }
-
- public Long getId() {
- return this.id;
- }
-
- /**
- * <p>Should <em>never</em> be called directly. Only via JPA or Hibernate or other EIS framework, since
- * they get the ID from the RDBMS directly.</p>
- *
- * <p>This method can be removed entirely if the EIS framework supports setting the ID property
- * directly (e.g. through reflection). Hibernate does support this, it is called 'property access'.</p>
- *
- * @param id the entity id
- */
- public void setId(Long id) {
- this.id = id;
- }
-
- public int getEntityVersion() {
- return this.entityVersion;
- }
-
- /**
- * For the same reasons as the setId() method, this should only be called by a
- * framework and never directly. Can be removed if the framework supports property access.
- *
- * @param entityVersion the entity version number
- */
- public void setEntityVersion(int entityVersion) {
- this.entityVersion = entityVersion;
- }
-
- /**
- * This method is declared final and does a lot of performance optimization:
- *
- * <p>It delegates the actual "equals" check to subclasses via the onEquals method, but
- * it will only do so if the object for equality comparison is</p>
- *
- * <ol>
- * <li>not the same memory location as the current object (fast sanity check)</li>
- * <li>is <code>instanceof</code> Entity</li>
- * <li>Does not have the same id() property</li>
- * </ol>
- *
- * <p>#3 is important: this is because if two different entities have the ID property
- * already populated, then they have already been inserted in the database, and
- * because of unique constraints on the database (i.e. your 'business key'), you
- * can <em>guarantee</em> that the objects are not the same and there is no need
- * to incur the (sometimes costly) attribute-based comparisons for equals() checks.</p>
- *
- * <p>This little technique is a big performance improvement given the number of times
- * equals checks happen in most applications.</p>
- */
- public final boolean equals(Object o) {
- if (o == this) {
- return true;
- }
-
- if (o instanceof Entity) {
- Entity e = (Entity) o;
- Long thisId = getId();
- Long otherId = e.getId();
- if (thisId != null && otherId != null) {
- return thisId.equals(otherId) && getClass().equals(e.getClass());
- } else {
- return onEquals(e);
- }
- }
-
- return false;
- }
-
- /**
- * Subclasses must do an equals comparison based on business keys, aka 'natural keys' here. Do <em>NOT</em> use
- * the {@link #getId id} property in these checks.
- *
- * @param e the Entity to check for "business" equality based on natural keys.
- * @return <code>true</code> if the specified Entity is naturally equal to this Entity, <code>false</code> otherwise.
- */
- public abstract boolean onEquals(Entity e);
-
- public abstract int hashCode();
-
- /**
- * If children classes override this method they must always call super.clone() to get the object
- * with which they manipulate further to clone remaining attributes. Never acquire
- * the cloned object directly via 'new' operator (this is true in Java for any class - it is not special to
- * this Entity class).
- */
- @Override
- @SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException"})
- public Object clone() {
-
- Entity e;
- try {
- e = (Entity) super.clone();
- } catch (CloneNotSupportedException neverHappens) {
- // Should _never_ happen since this class is Cloneable and
- // a direct subclass of Object
- throw new InternalError("Unable to clone object of type [" + getClass().getName() + "]");
- }
-
- e.setId(null);
- e.setEntityVersion(-1);
- return e;
- }
-
- /**
- * Returns a StringBuffer representing the toString function of the class implementation. This
- * should be overridden by all children classes to represent the object in a meaningful String format.
- *
- * @return a <tt>StringBuffer</tt> reperesenting the <tt>toString</tt> value of this object.
- */
- public StringBuffer toStringBuffer() {
- return new StringBuffer(super.toString());
- }
-
- /**
- * Returns toStringBuffer().toString(). Declared as 'final' to require subclasses to override
- * the {@link #toStringBuffer()} method, a cleaner and better performing mechanism for toString();
- *
- * @return toStringBuffer().toString()
- */
- public final String toString() {
- return toStringBuffer().toString();
- }
-}
-
-
-
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/model/Role.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/model/Role.java
new file mode 100644
index 0000000..766d889
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/model/Role.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.model;
+
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.hibernate.annotations.CollectionOfElements;
+import org.hibernate.annotations.Index;
+
+import javax.persistence.*;
+import java.util.Set;
+
+/**
+ * Model object that represents a security role.
+ */
+@Entity
+@Table(name="roles")
+@Cache(usage= CacheConcurrencyStrategy.READ_WRITE)
+public class Role {
+
+ private Long id;
+
+ private String name;
+
+ private String description;
+
+ private Set<String> permissions;
+
+ protected Role() {
+ }
+
+ public Role(String name) {
+ this.name = name;
+ }
+
+
+ @Id
+ @GeneratedValue
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ @Basic(optional=false)
+ @Column(length=100)
+ @Index(name="idx_roles_name")
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Basic(optional=false)
+ @Column(length=255)
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @CollectionOfElements
+ @JoinTable(name="roles_permissions")
+ @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
+ public Set<String> getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(Set<String> permissions) {
+ this.permissions = permissions;
+ }
+
+}
+
+
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/model/User.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/model/User.java
new file mode 100644
index 0000000..e0ba82f
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/model/User.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.model;
+
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.hibernate.annotations.Index;
+
+import javax.persistence.*;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Simple class that represents any User domain entity in any application.
+ *
+ * <p>Because this class performs its own Realm and Permission checks, and these can happen frequently enough in a
+ * production application, it is highly recommended that the internal User {@link #getRoles} collection be cached
+ * in a 2nd-level cache when using JPA and/or Hibernate. The hibernate xml configuration for this sample application
+ * does in fact do this for your reference (see User.hbm.xml - the 'roles' declaration).</p>
+ */
+@Entity
+@Table(name="users")
+@Cache(usage= CacheConcurrencyStrategy.READ_WRITE)
+public class User {
+
+ private Long id;
+ private String username;
+ private String email;
+ private String password;
+ private Set<Role> roles = new HashSet<Role>();
+
+
+ @Id
+ @GeneratedValue
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ /**
+ * Returns the username associated with this user account;
+ *
+ * @return the username associated with this user account;
+ */
+ @Basic(optional=false)
+ @Column(length=100)
+ @Index(name="idx_users_username")
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ @Basic(optional=false)
+ @Index(name="idx_users_email")
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ /**
+ * Returns the password for this user.
+ *
+ * @return this user's password
+ */
+ @Basic(optional=false)
+ @Column(length=255)
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+
+ @ManyToMany
+ @JoinTable(name="users_roles")
+ @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
+ public Set<Role> getRoles() {
+ return roles;
+ }
+
+ public void setRoles(Set<Role> roles) {
+ this.roles = roles;
+ }
+
+}
+
+
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/Gender.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/Gender.java
deleted file mode 100644
index 1944b1a..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/Gender.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.party;
-
-/**
- * Created by IntelliJ IDEA. User: Les Date: Sep 4, 2006 Time: 7:29:33 PM To change this template
- * use File | Settings | File Templates.
- */
-public enum Gender {
-
- MALE("M", "gender.male"),
-
- FEMALE("F", "gender.female");
-
- private String initial;
- private String i18nCode = null;
-
- private Gender(String initial, String i18nCode) {
- this.initial = initial;
- this.i18nCode = i18nCode;
- }
-
- public String getName() {
- return name();
- }
-
- public String getInitial() {
- return initial;
- }
-
- public String getI18nCode() {
- return i18nCode;
- }
-
- public String toInitial() {
- return getInitial();
- }
-
- public static Gender fromInitial(String initial) {
- for (Gender gender : values()) {
- if (gender.getInitial().equals(initial)) {
- return gender;
- }
- }
-
- throw new IllegalArgumentException("Argument not understood. Need valid initial that matches those " +
- "defined in the " + Gender.class.getName() + " enum");
- }
-
-}
-
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/Person.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/Person.java
deleted file mode 100644
index 73eba0e..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/Person.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.party;
-
-import org.jsecurity.samples.sprhib.entity.Entity;
-
-import java.text.DateFormat;
-import java.util.Date;
-
-/**
- * @author Les Hazlewood
- */
-public class Person extends Entity {
-
- private Gender gender;
- private String nameSalutation;
- private String givenName;
- private String middleNames;
- private String surname;
- private String nameSuffix;
- private Date dateOfBirth;
- private String title;
-
- public Person() {
- }
-
- public Person(String givenName, String surname) {
- setGivenName(givenName);
- setSurname(surname);
- }
-
- public Person(String givenName, String middleNames, String surname) {
- setGivenName(givenName);
- setMiddleNames(middleNames);
- setSurname(surname);
- }
-
-
- public Gender getGender() {
- return gender;
- }
-
- public void setGender(Gender gender) {
- this.gender = gender;
- }
-
- public String getNameSalutation() {
- return nameSalutation;
- }
-
- public void setNameSalutation(String nameSalutation) {
- this.nameSalutation = nameSalutation;
- }
-
- public String getGivenName() {
- return givenName;
- }
-
- public void setGivenName(String givenName) {
- this.givenName = givenName;
- }
-
- public String getMiddleNames() {
- return middleNames;
- }
-
- public void setMiddleNames(String middleNames) {
- this.middleNames = middleNames;
- }
-
- public String getSurname() {
- return surname;
- }
-
- public void setSurname(String surname) {
- this.surname = surname;
- }
-
- public String getNameSuffix() {
- return nameSuffix;
- }
-
- public void setNameSuffix(String nameSuffix) {
- this.nameSuffix = nameSuffix;
- }
-
- public Date getDateOfBirth() {
- return dateOfBirth;
- }
-
- public void setDateOfBirth(Date dateOfBirth) {
- this.dateOfBirth = dateOfBirth;
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- /**
- * Returns this person's givenName and surname (i.e. first and last)
- *
- * @return this person's givenName and surname (i.e. first and last)
- */
- public String getSimpleName() {
- return getSimpleName(true);
- }
-
- public String getSimpleName(boolean givenNameFirst) {
- StringBuffer sb = new StringBuffer();
-
- String first;
- String last;
-
- if (givenNameFirst) {
- first = getGivenName();
- last = getSurname();
- } else {
- first = getSurname();
- last = getGivenName();
- }
-
- if (first != null) {
- sb.append(first);
- }
-
- if (last != null) {
- if (first != null) {
- sb.append(" ");
- }
- sb.append(last);
- }
-
- return sb.toString();
- }
-
- /**
- * Returns this person's full name, with all name components (salutation, givenName, ..., etc).
- *
- * @return this person's full name, with all name components (salutation, givenName, ..., etc).
- */
- public String getFullName() {
- StringBuffer sb = new StringBuffer();
- if (getNameSalutation() != null) {
- sb.append(getNameSalutation());
- }
- if (getGivenName() != null) {
- sb.append(" ").append(getGivenName());
- }
- if (getMiddleNames() != null) {
- sb.append(" ").append(getMiddleNames());
- }
- if (getSurname() != null) {
- sb.append(" ").append(getSurname());
- }
- if (getNameSuffix() != null) {
- sb.append(" ").append(getNameSuffix());
- }
- return sb.toString().trim();
- }
-
- public StringBuffer toStringBuffer() {
- StringBuffer sb = super.toStringBuffer();
- sb.append(",gender=").append(getGender());
- sb.append(",name=").append(getFullName());
- Date dob = getDateOfBirth();
- if (dob != null) {
- DateFormat df = DateFormat.getInstance();
- sb.append(",dateOfBirth=[").append(df.format(dob.getTime())).append("]");
- }
- sb.append(",title=").append(getTitle());
- return sb;
- }
-
- public boolean onEquals(Entity e) {
-
- if (e instanceof Person) {
- Person p = (Person) e;
- return (givenName == null ? p.getGivenName() == null : givenName.equals(p.getGivenName())) &&
- (surname == null ? p.getSurname() == null : surname.equals(p.getSurname())) &&
- (middleNames == null ? p.getMiddleNames() == null : middleNames.equals(p.getMiddleNames())) &&
- (dateOfBirth == null ? p.getDateOfBirth() == null : dateOfBirth.equals(p.getDateOfBirth())) &&
- (gender == null ? p.getGender() == null : gender.equals(p.getGender())) &&
- (nameSalutation == null ? p.getNameSalutation() == null : nameSalutation.equals(p.getNameSalutation())) &&
- (nameSuffix == null ? p.getNameSuffix() == null : nameSuffix.equals(p.getNameSuffix())) &&
- (title == null ? p.getTitle() == null : title.equals(p.getTitle()));
- }
-
- return false;
- }
-
- public int hashCode() {
- int result = gender != null ? gender.hashCode() : 0;
- result = 31 * result + (nameSalutation != null ? nameSalutation.hashCode() : 0);
- result = 31 * result + (givenName != null ? givenName.hashCode() : 0);
- result = 31 * result + (middleNames != null ? middleNames.hashCode() : 0);
- result = 31 * result + (surname != null ? surname.hashCode() : 0);
- result = 31 * result + (nameSuffix != null ? nameSuffix.hashCode() : 0);
- result = 31 * result + (dateOfBirth != null ? dateOfBirth.hashCode() : 0);
- result = 31 * result + (title != null ? title.hashCode() : 0);
- return result;
- }
-
- @Override
- @SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException"})
- public Object clone() {
- Person clone = (Person) super.clone();
- clone.setGender(getGender());
- clone.setNameSalutation(getNameSalutation());
- clone.setGivenName(getGivenName());
- clone.setMiddleNames(getMiddleNames());
- clone.setSurname(getSurname());
- clone.setNameSuffix(getNameSuffix());
- Date dob = getDateOfBirth();
- if (dob != null) {
- clone.setDateOfBirth((Date) dob.clone());
- }
- clone.setTitle(getTitle());
- return clone;
- }
-
-}
-
-
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/User.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/User.java
deleted file mode 100644
index 59932fb..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/User.java
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.party;
-
-import org.jsecurity.authc.Account;
-import org.jsecurity.authz.Permission;
-import org.jsecurity.samples.sprhib.security.Role;
-import org.jsecurity.subject.PrincipalCollection;
-import org.jsecurity.subject.SimplePrincipalCollection;
-
-import java.text.DateFormat;
-import java.util.*;
-import java.util.regex.Pattern;
-
-/**
- * Simple class that represents any User domain entity in any application. It extends the {@link Person Person} class
- * to show a non-trivial class hierarchy, since such hierarchies exist in most Hibernate applications in one form
- * or another. Naturally you could ignore the parent class in your application, but it does represent a clean
- * OO way of modeling things.
- *
- * <p>This class implements the {@link org.jsecurity.authc.Account} interface for dead-simple integration
- * with JSecurity - this allows you to use your User objects directly inside of
- * {@link org.jsecurity.realm.Realm Realm} implementations, significantly reducing the implementation effort.</p>
- *
- * <p>Because this class performs its own Realm and Permission checks, and these can happen frequently enough in a
- * production application, it is highly recommended that the internal User {@link #getUserRoles} collection be cached
- * in a 2nd-level cache when using JPA and/or Hibernate. The hibernate xml configuration for this sample application
- * does in fact do this for your reference (see User.hbm.xml - the 'roles' declaration).</p>
- *
- * <p>If you ever decide not to use JSecurity, the only domain change would be to simply remove the
- * <code>Account</code> interface declaration</p>
- *
- * @author Les Hazlewood
- */
-public class User extends Person implements Account {
-
- /**
- * Requires 6 or more alphanumeric and/or punctuation characters.
- */
- public static final Pattern VALID_PASSWORD_PATTERN = Pattern.compile("[\\p{Alnum}\\p{Punct}]{6,255}");
-
- public static final Pattern VALID_USERNAME_PATTERN = Pattern.compile("[\\p{Alnum}_-]{1,255}");
-
- public static final String ROOT_USER_USERNAME = "root";
-
- private String username;
- private String password;
- private String passwordResetKey; //UUID generated when they ask to reset the password
- private Date passwordResetKeyTimestamp; //when they asked to reset the password
- private Date lastLoginTimestamp; //can be null if never logged in
- private Date lockTimestamp; //date the account was locked, null means unlocked (default behavior)
- private boolean sessionTimeoutEnabled = true; //per-user session configuration
-
- private Set<Role> roles;
-
- public User() {
- }
-
-
- /**
- * Returns the username associated with this user account;
- *
- * @return the username associated with this user account;
- */
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- /**
- * Returns the password for this user.
- *
- * @return this user's password
- */
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- /**
- * If the user forgets their password, this key is set first. If they then request to reset their password, they
- * must submit this key for the reset request to be valid. Otherwise, the password reset is timed out after a
- * certain amount of time after {@link #getPasswordResetKeyTimestamp() passwordResetKeyTimestamp}
- *
- * @return
- */
- public String getPasswordResetKey() {
- return passwordResetKey;
- }
-
- public void setPasswordResetKey(String passwordResetKey) {
- this.passwordResetKey = passwordResetKey;
- }
-
- public Date getPasswordResetKeyTimestamp() {
- return passwordResetKeyTimestamp;
- }
-
- public void setPasswordResetKeyTimestamp(Date passwordResetKeyTimestamp) {
- this.passwordResetKeyTimestamp = passwordResetKeyTimestamp;
- }
-
- /**
- * Returns the timestamp this User last logged in successfully to the application, or
- * <tt>null</tt> if the user has never logged in.
- *
- * @return the timestamp this User last logged in successfully to the application, or
- * <tt>null</tt> if the user has never logged in.
- */
- public Date getLastLoginTimestamp() {
- return lastLoginTimestamp;
- }
-
- /**
- * Sets the timestamp this User last logged in successfully to the application.
- *
- * @param lastLoginTimestamp the timestamp this User last logged in successfully to the
- * application.
- */
- public void setLastLoginTimestamp(Date lastLoginTimestamp) {
- this.lastLoginTimestamp = lastLoginTimestamp;
- }
-
- /**
- * Returns the time when this account was locked, either due to too many login attempts, an
- * explicit lock-out by an administrator, or because of some other security reason. <p>This
- * method returns <tt>null</tt> if the account is not locked and is considered to be in good
- * standing</p>
- *
- * @return the time when this account was locked, or <tt>null</tt> if this account is not locked
- * and is considered to be in good standing.
- */
- public Date getLockTimestamp() {
- return lockTimestamp;
- }
-
- public void setLockTimestamp(Date lockTimestamp) {
- this.lockTimestamp = lockTimestamp;
- }
-
- /**
- * Returns whether or not this particular user account can expire due to inactivity. <p>Defaults
- * to <tt>true</tt> as almost all user accounts should expire due to inactivity.
- *
- * @return <tt>true</tt> if this user's sessions can timeout due to inactivity, <tt>false</tt>
- * otherwise.
- */
- public boolean isSessionTimeoutEnabled() {
- return sessionTimeoutEnabled;
- }
-
- public void setSessionTimeoutEnabled(boolean sessionTimeoutEnabled) {
- this.sessionTimeoutEnabled = sessionTimeoutEnabled;
- }
-
- /**
- * Returns whether or not this user account is locked, thereby preventing further log-ins.
- *
- * @return <tt>true</tt> if this user account is locked and will not be allowed to log-in,
- * <tt>false</tt>
- */
- public boolean isLocked() {
- return getLockTimestamp() != null;
- }
-
- /**
- * Convenience method for updating the state to locked.
- *
- * @param locked whether or not this user account will be locked.
- * @see #getLockTimestamp()
- */
- public void setLocked(boolean locked) {
- if (locked) {
- if (getLockTimestamp() == null) {
- setLockTimestamp(new Date());
- }
- } else {
- setLockTimestamp(null);
- }
- }
-
- public Set<Role> getUserRoles() {
- return roles;
- }
-
- public void setUserRoles(Set<Role> roles) {
- this.roles = roles;
- }
-
- public Role getRole(String name) {
- Collection<Role> roles = getUserRoles();
- if (roles != null && !roles.isEmpty()) {
- for (Role role : roles) {
- if (role.getName().equals(name)) {
- return role;
- }
- }
- }
- return null;
- }
-
- /**
- * Adds a Role to this user's collection of {@link #getRoles() roles}.
- *
- * <p>If the existing roles collection is <tt>null</tt>, a new collection will be created and
- * assigned to this User and then the Role will be added.
- *
- * @param r the Role to add/associate with this User
- */
- public void add(Role r) {
- Set<Role> roles = getUserRoles();
- if (roles == null) {
- roles = new LinkedHashSet<Role>();
- setUserRoles(roles);
- }
- roles.add(r);
- }
-
- public boolean removeRole(Role r) {
- Set<Role> roles = getUserRoles();
- return roles != null && roles.remove(r);
- }
-
- protected String getPrivateRoleName(PrincipalCollection principals) {
- return getClass().getName() + "_PRIVATE_ROLE_" + PrincipalCollection.class.getName();
- }
-
- protected Role createPrivateRole(PrincipalCollection principals) {
- String privateRoleName = getPrivateRoleName(principals);
- return new Role(privateRoleName, this);
- }
-
- public Set<Permission> getPermissions() {
- Set<Permission> permissions = new HashSet<Permission>();
- for (Role role : roles) {
- permissions.addAll(role.getPermissions());
- }
- return permissions;
- }
-
- public Set<String> getRolenames() {
- Set<String> rolenames = new HashSet<String>();
- for (Role role : roles) {
- rolenames.add(role.getName());
- }
- return rolenames;
- }
-
- public void addRole(String roleName) {
- Role existing = getRole(roleName);
- if (existing == null) {
- Role role = new Role(roleName);
- add(role);
- }
- }
-
- public void addRoles(Set<String> roleNames) {
- if (roleNames != null && !roleNames.isEmpty()) {
- for (String name : roleNames) {
- addRole(name);
- }
- }
- }
-
- public void addAll(Collection<Role> roles) {
- if (roles != null && !roles.isEmpty()) {
- Set<Role> existingRoles = getUserRoles();
- if (existingRoles == null) {
- existingRoles = new LinkedHashSet<Role>(roles.size());
- setUserRoles(existingRoles);
- }
- existingRoles.addAll(roles);
- }
- }
-
-
- public static boolean isValidPassword(String password) {
- return password != null && VALID_PASSWORD_PATTERN.matcher(password).matches();
- }
-
- public static boolean isValidUsername(String username) {
- return username != null && VALID_USERNAME_PATTERN.matcher(username).matches();
- }
-
-
- public StringBuffer toStringBuffer() {
- StringBuffer sb = super.toStringBuffer();
- sb.append(",username=").append(getUsername());
- sb.append(",password=<protected>");
- DateFormat df = DateFormat.getInstance();
- Date ts = getLastLoginTimestamp();
- if (ts != null) {
- sb.append(",lastLoginTimestamp=").append(df.format(ts));
- }
- ts = getLockTimestamp();
- if (ts != null) {
- sb.append(",lockTimestamp=").append(df.format(ts));
- }
- sb.append(",sessionTimeoutEnabled=").append(isSessionTimeoutEnabled());
-
- return sb;
- }
-
- public boolean onEquals(Object o) {
- if (o instanceof User) {
- User u = (User) o;
- return getUsername().equals(u.getUsername());
- }
-
- return false;
- }
-
- public int hashCode() {
- return getUsername().hashCode();
- }
-
- @Override
- @SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException"})
- public Object clone() {
- User clone = (User) super.clone();
- clone.setUsername(getUsername());
- clone.setPassword(getPassword());
- clone.setPasswordResetKey(getPasswordResetKey());
- clone.setPasswordResetKeyTimestamp(getPasswordResetKeyTimestamp());
- clone.setLastLoginTimestamp(getLastLoginTimestamp());
- clone.setLockTimestamp(getLockTimestamp());
- clone.setSessionTimeoutEnabled(isSessionTimeoutEnabled());
- return clone;
- }
-
- public static void main(String[] args) {
- String username = "s-ls";
- if (!isValidUsername(username)) {
- System.out.println("Not a valid username!");
- } else {
- System.out.println("Valid username.");
- }
- }
-
- /* ===========
- JSecurity Account implementations below here.
- =========== */
- public PrincipalCollection getPrincipals() {
- //The realm name must match the name of the configured realm.
- return new SimplePrincipalCollection(getId(), "DefaultRealm");
- }
-
- public Object getCredentials() {
- return getPassword();
- }
-
- public boolean isCredentialsExpired() {
- //if applications wanted to expire passwords after a certain amount of time, this method would calculate
- //true or false based on the current time and a passwordLastUpdateTimestamp;
-
- //this sample app doesn't use this feature, so just return false always:
- return false;
- }
-
- public Collection<String> getRoles() {
- return getRolenames();
- }
-
- public Collection<String> getStringPermissions() {
- // This model uses object permissions, so this method isn't implemented
- return null;
- }
-
- public Collection<Permission> getObjectPermissions() {
- Set<Permission> permissions = new HashSet<Permission>();
- for (Role role : getUserRoles()) {
- permissions.addAll(role.getPermissions());
- }
- return permissions;
- }
-}
-
-
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/eis/HibernateUserDAO.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/eis/HibernateUserDAO.java
deleted file mode 100644
index 373bebc..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/party/eis/HibernateUserDAO.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.party.eis;
-
-import org.jsecurity.samples.sprhib.eis.hibernate.PrimaryClassHibernateDAO;
-import org.jsecurity.samples.sprhib.party.User;
-
-/**
- * @author Les Hazlewood
- */
-public class HibernateUserDAO extends PrimaryClassHibernateDAO implements UserDAO {
-
- public HibernateUserDAO() {
- setPrimaryClass(User.class);
- }
-
- public User getUser(Long userId) {
- return (User) read(userId);
- }
-
- public User findUser(String username) {
- if (username == null) {
- String msg = "Username cannot be null.";
- throw new IllegalArgumentException(msg);
- }
- String query = "from User u where u.username = ?";
- return (User) findSingle(query, username);
- }
-
- /*public User findUserByEmail( String email ) {
- if ( email == null ) {
- String msg = "Email argument cannot be null.";
- throw new IllegalArgumentException( msg );
- }
- String query = "from User u where u.emailAddresses.text = ?";
- return (User)findSingle( query, email );
- }*/
-
-}
-
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/security/Role.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/security/Role.java
deleted file mode 100644
index 3fd725f..0000000
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/security/Role.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.jsecurity.samples.sprhib.security;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jsecurity.authz.Permission;
-import org.jsecurity.samples.sprhib.entity.Entity;
-import org.jsecurity.samples.sprhib.party.User;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Created on: Sep 16, 2005 4:00:20 PM
- *
- * @author Les Hazlewood
- */
-public class Role extends Entity {
-
- private static final Log log = LogFactory.getLog(Role.class);
-
- public static final String ROOT_ROLE_NAME = "root";
- public static final String PRIVATE_ROLE_NAME = "private";
-
- private String name;
-
- private String description;
-
- private User owner;
-
- private boolean isPrivate = false;
-
- private Set<Permission> permissions;
-
- public Role() {
- }
-
- public Role(String name) {
- this.name = name;
- }
-
- public Role(String name, User owner) {
- this.name = name;
- this.owner = owner;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- public boolean isPrivate() {
- return isPrivate;
- }
-
- public void setPrivate(boolean isPrivate) {
- this.isPrivate = isPrivate;
- }
-
- public User getOwner() {
- return owner;
- }
-
- public void setOwner(User owner) {
- this.owner = owner;
- }
-
- public Set<Permission> getPermissions() {
- return permissions;
- }
-
- public void setPermissions(Set<Permission> permissions) {
- this.permissions = permissions;
- }
-
- /**
- * Adds a Permission to this party's collection of
- * {@link #getPermissions() permissions}.
- *
- * <p>If the existing permissions collection is <tt>null</tt>,
- * a new collection will be created and assigned to this role and then the permission will
- * be added.
- *
- * <p>If the specified permission already exists in this role's collection, it will not
- * be added again.
- *
- * @param p the Permission to add/associate with this Role
- */
- public void add(Permission p) {
- Set<Permission> perms = getPermissions();
- if (perms == null) {
- perms = new HashSet<Permission>();
- setPermissions(perms);
- }
- perms.add(p);
- }
-
- public boolean remove(Permission p) {
- Set<Permission> perms = getPermissions();
- return perms != null && perms.remove(p);
- }
-
- public boolean isPermitted(Permission p) {
- Set<Permission> perms = getPermissions();
- if (perms != null && !perms.isEmpty()) {
- for (Permission perm : perms) {
- if (perm.implies(p)) {
- if (log.isTraceEnabled()) {
- String msg = "saved permission implies permission argument. Role [" +
- getName() + "] has permission";
- log.trace(msg);
- }
- return true;
- }
- }
- }
-
- if (log.isTraceEnabled()) {
- log.trace("No saved permissions implies the permission argument. Role [" +
- getName() + "] doesn't have the specified permission");
- }
-
- return false;
- }
-
- public boolean onEquals(Entity e) {
- if (e instanceof Role) {
- Role r = (Role) e;
- return getName().equals(r.getName()) &&
- (owner != null ? owner.equals(r.getOwner()) : r.getOwner() == null);
- }
-
- return false;
- }
-
- public int hashCode() {
- int result = name.hashCode();
- result = 29 * result + (owner != null ? owner.hashCode() : 0);
- return result;
- }
-
- public StringBuffer toStringBuffer() {
- StringBuffer sb = super.toStringBuffer();
- sb.append(",name=").append(getName());
- sb.append(",description=[").append(getDescription()).append("]");
- sb.append(",permissions={").append("<lazy property omitted>").append("}");
- return sb;
- }
-
- /**
- * Returns a shallow copy (i.e. the owner and Permission instances in the permissions
- * collection copied into a new list instead of being cloned themselves). This should be fine since permission
- * objects are immutable.
- */
- @Override
- @SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException"})
- public Object clone() {
- Role clone = (Role) super.clone();
- clone.setName(getName());
- clone.setDescription(getDescription());
- clone.setOwner(getOwner());
- Set<Permission> perms = getPermissions();
- if (perms != null && !perms.isEmpty()) {
- Set<Permission> permClones = new HashSet<Permission>(perms.size());
- for (Permission p : perms) {
- permClones.add(p);
- }
- clone.setPermissions(permClones);
- }
-
- return clone;
- }
-
- public void clearPermissions() {
- Set<Permission> perms = getPermissions();
- if (perms != null && !perms.isEmpty()) {
- permissions.clear();
- }
- }
-
-}
-
-
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/security/DefaultRealm.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/security/SampleRealm.java
similarity index 63%
rename from samples/spring-hibernate/src/org/jsecurity/samples/sprhib/security/DefaultRealm.java
rename to samples/spring-hibernate/src/org/jsecurity/samples/sprhib/security/SampleRealm.java
index 62e6526..607bea6 100644
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/security/DefaultRealm.java
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/security/SampleRealm.java
@@ -18,15 +18,17 @@
*/
package org.jsecurity.samples.sprhib.security;
-import org.jsecurity.authc.AuthenticationException;
-import org.jsecurity.authc.AuthenticationInfo;
-import org.jsecurity.authc.AuthenticationToken;
-import org.jsecurity.authc.UsernamePasswordToken;
+import org.jsecurity.authc.*;
+import org.jsecurity.authc.credential.Sha256CredentialsMatcher;
import org.jsecurity.authz.AuthorizationInfo;
+import org.jsecurity.authz.SimpleAuthorizationInfo;
import org.jsecurity.realm.AuthorizingRealm;
-import org.jsecurity.samples.sprhib.party.eis.UserDAO;
+import org.jsecurity.samples.sprhib.dao.UserDAO;
+import org.jsecurity.samples.sprhib.model.Role;
+import org.jsecurity.samples.sprhib.model.User;
import org.jsecurity.subject.PrincipalCollection;
-import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
/**
* The Spring/Hibernate sample application's one and only configured JSecurity Realm.
@@ -35,39 +37,47 @@
* in the implementation and named it a 'HibernateRealm' or something similar.</p>
*
* <p>But we've decided to make the calls to the database using a UserDAO, since a DAO would be used in other areas
- * of a 'real' application in addition to here. We felt it better to use that same DAO to show code re-use.
- * That is, in a real app, there is no need to duplicate Hibernate calls in the Realm implementation if you've already
- * got a User DAO (as most apps would). So, we just use that UserDAO here.</p>
- *
- * @author Les Hazlewood
+ * of a 'real' application in addition to here. We felt it better to use that same DAO to show code re-use.</p>
*/
-public class DefaultRealm extends AuthorizingRealm implements InitializingBean {
+@Component
+public class SampleRealm extends AuthorizingRealm {
protected UserDAO userDAO = null;
- public DefaultRealm() {
+ public SampleRealm() {
setName("DefaultRealm"); //This name must match the name in the User class's getPrincipals() method
+ setCredentialsMatcher(new Sha256CredentialsMatcher());
}
+ @Autowired
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
- public void afterPropertiesSet() throws Exception {
- if (this.userDAO == null) {
- throw new IllegalStateException("UserDAO property was not injected. Please check your Spring config.");
- }
- }
-
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
- return userDAO.findUser(token.getUsername());
+ User user = userDAO.findUser(token.getUsername());
+ if( user != null ) {
+ return new SimpleAuthenticationInfo(user.getId(), user.getPassword(), getName());
+ } else {
+ return null;
+ }
}
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
Long userId = (Long) principals.fromRealm(getName()).iterator().next();
- return userDAO.getUser(userId);
+ User user = userDAO.getUser(userId);
+ if( user != null ) {
+ SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
+ for( Role role : user.getRoles() ) {
+ info.addRole(role.getName());
+ info.addStringPermissions( role.getPermissions() );
+ }
+ return info;
+ } else {
+ return null;
+ }
}
}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/service/DefaultUserService.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/service/DefaultUserService.java
new file mode 100644
index 0000000..1485f9c
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/service/DefaultUserService.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.service;
+
+import org.jsecurity.SecurityUtils;
+import org.jsecurity.crypto.hash.Sha256Hash;
+import org.jsecurity.samples.sprhib.dao.UserDAO;
+import org.jsecurity.samples.sprhib.model.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * Default implementation of the {@link UserService} interface. This service implements
+ * operations related to User data.
+ */
+@Transactional
+@Service("userService")
+public class DefaultUserService implements UserService {
+
+ private UserDAO userDAO;
+
+ @Autowired
+ public void setUserDAO(UserDAO userDAO) {
+ this.userDAO = userDAO;
+ }
+
+ public User getCurrentUser() {
+ final Long currentUserId = (Long) SecurityUtils.getSubject().getPrincipal();
+ if( currentUserId != null ) {
+ return getUser(currentUserId);
+ } else {
+ return null;
+ }
+ }
+
+ public void createUser(String username, String email, String password) {
+ User user = new User();
+ user.setUsername(username);
+ user.setEmail(email);
+ user.setPassword( new Sha256Hash(password).toHex() );
+ userDAO.createUser( user );
+ }
+
+ public List<User> getAllUsers() {
+ return userDAO.getAllUsers();
+ }
+
+ public User getUser(Long userId) {
+ return userDAO.getUser(userId);
+ }
+
+ public void deleteUser(Long userId) {
+ userDAO.deleteUser( userId );
+ }
+
+ public void updateUser(User user) {
+ userDAO.updateUser( user );
+ }
+
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/entity/Identifiable.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/service/UserService.java
similarity index 64%
rename from samples/spring-hibernate/src/org/jsecurity/samples/sprhib/entity/Identifiable.java
rename to samples/spring-hibernate/src/org/jsecurity/samples/sprhib/service/UserService.java
index 71dc685..522393c 100644
--- a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/entity/Identifiable.java
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/service/UserService.java
@@ -16,18 +16,26 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.jsecurity.samples.sprhib.entity;
+package org.jsecurity.samples.sprhib.service;
+
+import org.jsecurity.samples.sprhib.model.User;
+
+import java.util.List;
/**
- * <p>This interface was borrowed from the <a href="http://code.google.com/p/pojodm">PojoDM Project</a>'s
- * <a href="http://code.google.com/p/pojodm/source/browse/trunk/src/org/pojodm/entity/Identifiable.java">Identifiable.java</a>
- * for a quick kickstart.</p>
- *
- * @author Les Hazlewood
- * @since Apr 5, 2008 2:46:56 PM
+ * A service interface for accessing and modifying user data in the system.
*/
-public interface Identifiable {
+public interface UserService {
- Long getId();
+ User getCurrentUser();
+ void createUser(String username, String email, String password);
+
+ List<User> getAllUsers();
+
+ User getUser(Long userId);
+
+ void deleteUser(Long userId);
+
+ void updateUser(User user);
}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/CurrentUserInterceptor.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/CurrentUserInterceptor.java
new file mode 100644
index 0000000..bbe83b6
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/CurrentUserInterceptor.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+import org.jsecurity.samples.sprhib.model.User;
+import org.jsecurity.samples.sprhib.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A Spring MVC interceptor that adds the currentUser into the request as a request attribute
+ * before the JSP is rendered. This operation is assumed to be fast because the User should be
+ * cached in the Hibernate second-level cache.
+ */
+@Component
+public class CurrentUserInterceptor extends HandlerInterceptorAdapter {
+
+ private UserService userService;
+
+ @Autowired
+ public void setUserService(UserService userService) {
+ this.userService = userService;
+ }
+
+ @Override
+ public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
+ // Add the current user into the request
+ User currentUser = userService.getCurrentUser();
+ if( currentUser != null ) {
+ httpServletRequest.setAttribute( "currentUser", currentUser );
+ }
+ }
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/EditUserCommand.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/EditUserCommand.java
new file mode 100644
index 0000000..92e65d6
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/EditUserCommand.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+import org.jsecurity.crypto.hash.Sha256Hash;
+import org.jsecurity.samples.sprhib.model.User;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * Command binding object for editing a user.
+ */
+public class EditUserCommand {
+
+ private Long userId;
+ private String username;
+ private String email;
+ private String password;
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public void updateUser(User user) {
+ Assert.isTrue( userId.equals( user.getId() ), "User ID of command must match the user being updated." );
+ user.setUsername( getUsername() );
+ user.setEmail( getEmail() );
+ if( StringUtils.hasText(getPassword()) ) {
+ user.setPassword( new Sha256Hash(getPassword()).toHex() );
+ }
+ }
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/EditUserValidator.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/EditUserValidator.java
new file mode 100644
index 0000000..5f78cd0
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/EditUserValidator.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+import org.jsecurity.util.StringUtils;
+import org.springframework.validation.Errors;
+import org.springframework.validation.ValidationUtils;
+import org.springframework.validation.Validator;
+
+import java.util.regex.Pattern;
+
+/**
+ * Validator when editing a user.
+ */
+public class EditUserValidator implements Validator {
+
+ private static final String SIMPLE_EMAIL_REGEX = "[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}";
+
+ public boolean supports(Class aClass) {
+ return EditUserCommand.class.isAssignableFrom(aClass);
+ }
+
+ public void validate(Object o, Errors errors) {
+ EditUserCommand command = (EditUserCommand)o;
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username", "error.username.empty", "Please specify a username.");
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "error.email.empty", "Please specify an email address.");
+ if( StringUtils.hasText( command.getEmail() ) && !Pattern.matches( SIMPLE_EMAIL_REGEX, command.getEmail().toUpperCase() ) ) {
+ errors.rejectValue( "email", "error.email.invalid", "Please enter a valid email address." );
+ }
+ }
+
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/HomeController.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/HomeController.java
new file mode 100644
index 0000000..4630299
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/HomeController.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+import org.jsecurity.samples.sprhib.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * Web controller used when loading the home page.
+ */
+@Controller
+public class HomeController {
+
+ private UserService userService;
+
+ @Autowired
+ public void setUserService(UserService userService) {
+ this.userService = userService;
+ }
+
+ @RequestMapping("/home")
+ public void viewHome(Model model) {
+ model.addAttribute( "users", userService.getAllUsers() );
+ }
+
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/LoginCommand.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/LoginCommand.java
new file mode 100644
index 0000000..8ff353d
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/LoginCommand.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+/**
+ * Command binding object for logging in.
+ */
+public class LoginCommand {
+
+ private String username;
+
+ private String password;
+
+ private boolean rememberMe;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public boolean isRememberMe() {
+ return rememberMe;
+ }
+
+ public void setRememberMe(boolean rememberMe) {
+ this.rememberMe = rememberMe;
+ }
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/LoginValidator.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/LoginValidator.java
new file mode 100644
index 0000000..a116a38
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/LoginValidator.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+import org.springframework.validation.Errors;
+import org.springframework.validation.ValidationUtils;
+import org.springframework.validation.Validator;
+
+/**
+ * Validator for login.
+ */
+public class LoginValidator implements Validator {
+ public boolean supports(Class aClass) {
+ return LoginCommand.class.isAssignableFrom(aClass);
+ }
+
+ public void validate(Object o, Errors errors) {
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username", "error.username.empty", "Please specify a username.");
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "error.password.empty", "Please specify a password.");
+ }
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/ManageUsersController.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/ManageUsersController.java
new file mode 100644
index 0000000..f43b0e0
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/ManageUsersController.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+import org.jsecurity.authz.annotation.RequiresPermissions;
+import org.jsecurity.samples.sprhib.model.User;
+import org.jsecurity.samples.sprhib.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.util.Assert;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * Web MVC controller that handles operations related to managing users, such as editing them and deleting them.
+ */
+@Controller
+public class ManageUsersController {
+
+ private EditUserValidator editUserValidator = new EditUserValidator();
+
+ private UserService userService;
+
+ @Autowired
+ public void setUserService(UserService userService) {
+ this.userService = userService;
+ }
+
+ @RequestMapping("/manageUsers")
+ @RequiresPermissions("user:manage")
+ public void manageUsers(Model model) {
+ model.addAttribute("users", userService.getAllUsers());
+ }
+
+ @RequestMapping(value="/editUser",method= RequestMethod.GET)
+ @RequiresPermissions("user:edit")
+ public String showEditUserForm(Model model, @RequestParam Long userId, @ModelAttribute EditUserCommand command) {
+
+ User user = userService.getUser( userId );
+ command.setUserId(userId);
+ command.setUsername(user.getUsername());
+ command.setEmail(user.getEmail());
+ return "editUser";
+ }
+
+ @RequestMapping(value="/editUser",method= RequestMethod.POST)
+ @RequiresPermissions("user:edit")
+ public String editUser(Model model, @RequestParam Long userId, @ModelAttribute EditUserCommand command, BindingResult errors) {
+ editUserValidator.validate( command, errors );
+
+ if( errors.hasErrors() ) {
+ return "editUser";
+ }
+
+ User user = userService.getUser( userId );
+ command.updateUser( user );
+
+ userService.updateUser( user );
+
+ return "redirect:/s/manageUsers";
+ }
+
+ @RequestMapping("/deleteUser")
+ @RequiresPermissions("user:delete")
+ public String deleteUser(@RequestParam Long userId) {
+ Assert.isTrue( userId != 1, "Cannot delete admin user" );
+ userService.deleteUser( userId );
+ return "redirect:/s/manageUsers";
+ }
+
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SecurityController.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SecurityController.java
new file mode 100644
index 0000000..0ef19d7
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SecurityController.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+import org.jsecurity.SecurityUtils;
+import org.jsecurity.authc.AuthenticationException;
+import org.jsecurity.authc.UsernamePasswordToken;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+/**
+ * Web MVC controller that handles security-related web requests, such as login and logout.
+ */
+@Controller
+public class SecurityController {
+
+ private LoginValidator loginValidator = new LoginValidator();
+
+ @RequestMapping(value="/login",method= RequestMethod.GET)
+ public String showLoginForm(Model model, @ModelAttribute LoginCommand command ) {
+ return "login";
+ }
+
+ @RequestMapping(value="/login",method= RequestMethod.POST)
+ public String login(Model model, @ModelAttribute LoginCommand command, BindingResult errors) {
+ loginValidator.validate(command, errors);
+
+ if( errors.hasErrors() ) {
+ return showLoginForm(model, command);
+ }
+
+ UsernamePasswordToken token = new UsernamePasswordToken(command.getUsername(), command.getPassword(), command.isRememberMe());
+ try {
+ SecurityUtils.getSubject().login(token);
+ } catch (AuthenticationException e) {
+ errors.reject( "error.login.generic", "Invalid username or password. Please try again." );
+ }
+
+ if( errors.hasErrors() ) {
+ return showLoginForm(model, command);
+ } else {
+ return "redirect:/s/home";
+ }
+ }
+
+ @RequestMapping("/logout")
+ public String logout() {
+ SecurityUtils.getSubject().logout();
+ return "redirect:/";
+ }
+
+
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SignupCommand.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SignupCommand.java
new file mode 100644
index 0000000..4e31400
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SignupCommand.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+/**
+ * Command binding object for signing up for a new account.
+ */
+public class SignupCommand {
+
+ private String username;
+
+ private String email;
+
+ private String password;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SignupController.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SignupController.java
new file mode 100644
index 0000000..94d0783
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SignupController.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+import org.jsecurity.SecurityUtils;
+import org.jsecurity.authc.UsernamePasswordToken;
+import org.jsecurity.samples.sprhib.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+/**
+ * Web MVC controller that handles signup requests.
+ */
+@Controller
+public class SignupController {
+
+ private SignupValidator signupValidator = new SignupValidator();
+
+ private UserService userService;
+
+ @Autowired
+ public void setUserService(UserService userService) {
+ this.userService = userService;
+ }
+
+ @RequestMapping(value="/signup",method= RequestMethod.GET)
+ public String showSignupForm(Model model, @ModelAttribute SignupCommand command) {
+ return "signup";
+ }
+
+ @RequestMapping(value="/signup",method= RequestMethod.POST)
+ public String showSignupForm(Model model, @ModelAttribute SignupCommand command, BindingResult errors) {
+ signupValidator.validate(command, errors);
+
+ if( errors.hasErrors() ) {
+ return showSignupForm(model, command);
+ }
+
+ // Create the user
+ userService.createUser( command.getUsername(), command.getEmail(), command.getPassword() );
+
+ // Login the newly created user
+ SecurityUtils.getSubject().login(new UsernamePasswordToken(command.getUsername(), command.getPassword()));
+
+ return "redirect:/s/home";
+ }
+
+}
diff --git a/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SignupValidator.java b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SignupValidator.java
new file mode 100644
index 0000000..0e7f27f
--- /dev/null
+++ b/samples/spring-hibernate/src/org/jsecurity/samples/sprhib/web/SignupValidator.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.jsecurity.samples.sprhib.web;
+
+import org.jsecurity.util.StringUtils;
+import org.springframework.validation.Errors;
+import org.springframework.validation.ValidationUtils;
+import org.springframework.validation.Validator;
+
+import java.util.regex.Pattern;
+
+/**
+ * Validator for the signup form.
+ */
+public class SignupValidator implements Validator {
+
+ private static final String SIMPLE_EMAIL_REGEX = "[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}";
+
+ public boolean supports(Class aClass) {
+ return SignupCommand.class.isAssignableFrom(aClass);
+ }
+
+ public void validate(Object o, Errors errors) {
+ SignupCommand command = (SignupCommand)o;
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username", "error.username.empty", "Please specify a username.");
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "error.email.empty", "Please specify an email address.");
+ if( StringUtils.hasText( command.getEmail() ) && !Pattern.matches( SIMPLE_EMAIL_REGEX, command.getEmail().toUpperCase() ) ) {
+ errors.rejectValue( "email", "error.email.invalid", "Please enter a valid email address." );
+ }
+ ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "error.password.empty", "Please specify a password.");
+ }
+}
diff --git a/samples/spring-hibernate/web/WEB-INF/applicationContext.xml b/samples/spring-hibernate/web/WEB-INF/applicationContext.xml
new file mode 100644
index 0000000..b25e833
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/applicationContext.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xmlns:tx="http://www.springframework.org/schema/tx"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
+
+ <!-- Enable annotation configuration -->
+ <context:annotation-config/>
+
+ <!-- Scan sample packages for Spring annotations -->
+ <context:component-scan base-package="org.jsecurity.samples.sprhib.dao"/>
+ <context:component-scan base-package="org.jsecurity.samples.sprhib.security"/>
+ <context:component-scan base-package="org.jsecurity.samples.sprhib.service"/>
+
+ <!-- Spring AOP auto-proxy creation (required to support JSecurity annotations) -->
+ <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
+
+
+ <!-- Sample RDBMS data source that would exist in any application. Sample is just using an in-memory HSQLDB
+ instance. Change to your application's settings for a real app. -->
+ <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+ <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
+ <property name="url" value="jdbc:hsqldb:mem:jsecurity-spring-hibernate"/>
+ <property name="username" value="sa"/>
+ </bean>
+
+ <!-- Hibernate SessionFactory -->
+ <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
+ <property name="dataSource" ref="dataSource"/>
+ <!-- Because we're using an in-memory database for demo purposes (which is lost every time the app
+ shuts down), we have to ensure that the HSQLDB DDL is run each time the app starts. The
+ DDL is auto-generated based on the *.hbm.xml mapping definitions below. -->
+ <property name="schemaUpdate" value="true"/>
+ <!-- Scan packages for JPA annotations -->
+ <property name="packagesToScan" value="org.jsecurity.samples.sprhib.model"/>
+ <property name="hibernateProperties">
+ <props>
+ <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
+ <prop key="hibernate.jdbc.fetch_size">100</prop>
+ <prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
+ </props>
+ </property>
+ <property name="eventListeners">
+ <map>
+ <entry key="merge">
+ <bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
+ </entry>
+ </map>
+ </property>
+ </bean>
+
+ <!-- Transaction support beans -->
+ <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
+ <property name="sessionFactory" ref="sessionFactory"/>
+ </bean>
+
+ <tx:annotation-driven/>
+
+
+ <!-- =========================================================
+ JSecurity Components
+ ========================================================= -->
+
+ <!-- JSecurity's main business-tier object for web-enabled applications
+ (use org.jsecurity.mgt.DefaultSecurityManager instead when there is no web environment)-->
+ <bean id="securityManager" class="org.jsecurity.web.DefaultWebSecurityManager">
+ <!-- Single realm app (realm configured next, below). If you have multiple realms, use the 'realms'
+ property instead. -->
+ <property name="realm" ref="sampleRealm"/>
+ <!-- Uncomment this next property if you want heterogenous session access or clusterable/distributable
+ sessions. The default value is 'http' which uses the Servlet container's HttpSession as the underlying
+ Session implementation.
+ <property name="sessionMode" value="jsecurity"/> -->
+ </bean>
+
+
+ <!-- Post processor that automatically invokes init() and destroy() methods -->
+ <bean id="lifecycleBeanPostProcessor" class="org.jsecurity.spring.LifecycleBeanPostProcessor"/>
+
+</beans>
diff --git a/samples/spring-hibernate/web/WEB-INF/classes/ehcache.xml b/samples/spring-hibernate/web/WEB-INF/classes/ehcache.xml
new file mode 100644
index 0000000..3009bc8
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/classes/ehcache.xml
@@ -0,0 +1,56 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+<ehcache>
+
+ <diskStore path="java.io.tmpdir/jsecurity-spring-hibernate-ehcache"/>
+
+
+ <defaultCache
+ maxElementsInMemory="1000"
+ eternal="false"
+ timeToLiveSeconds="600"
+ overflowToDisk="true"
+ diskPersistent="false"
+ />
+
+ <!--=================================================================
+ Hibernate Object Caches
+ =================================================================-->
+
+ <cache name="org.jsecurity.samples.sprhib.model.Role"
+ maxElementsInMemory="100"
+ timeToLiveSeconds="0"
+ overflowToDisk="true"/>
+
+ <cache name="org.jsecurity.samples.sprhib.model.Role.permissions"
+ maxElementsInMemory="100"
+ timeToLiveSeconds="0"
+ overflowToDisk="true"/>
+
+ <cache name="org.jsecurity.samples.sprhib.model.User"
+ maxElementsInMemory="1000"
+ timeToLiveSeconds="3600"
+ overflowToDisk="true"/>
+
+ <cache name="org.jsecurity.samples.sprhib.model.User.roles"
+ maxElementsInMemory="1000"
+ timeToLiveSeconds="3600"
+ overflowToDisk="true"/>
+
+</ehcache>
\ No newline at end of file
diff --git a/samples/spring-hibernate/web/WEB-INF/classes/hibernate.cfg.xml b/samples/spring-hibernate/web/WEB-INF/classes/hibernate.cfg.xml
new file mode 100644
index 0000000..2050a9d
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/classes/hibernate.cfg.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD//EN"
+ "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<!-- This file is largely provided for IDE/tool support, and is NOT used at runtime -->
+
+<hibernate-configuration>
+ <session-factory>
+ <!-- DB schema will be updated if needed -->
+ <property name="hbm2ddl.auto">update</property>
+
+ <mapping class="org.jsecurity.samples.sprhib.model.Role"/>
+ <mapping class="org.jsecurity.samples.sprhib.model.User"/>
+
+ </session-factory>
+</hibernate-configuration>
\ No newline at end of file
diff --git a/samples/spring-hibernate/web/WEB-INF/classes/log4j.properties b/samples/spring-hibernate/web/WEB-INF/classes/log4j.properties
new file mode 100644
index 0000000..54ffb3f
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/classes/log4j.properties
@@ -0,0 +1,39 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+log4j.rootLogger=INFO, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
+
+# General Apache libraries
+log4j.logger.org.apache=WARN
+
+# Spring
+log4j.logger.org.springframework=WARN
+
+# Hibernate
+log4j.logger.org.hibernate=WARN
+
+# Default JSecurity logging
+log4j.logger.org.jsecurity=TRACE
+
+# Disable verbose logging
+log4j.logger.org.jsecurity.util.ThreadContext=WARN
+log4j.logger.org.jsecurity.cache.ehcache.EhCache=WARN
diff --git a/samples/spring-hibernate/web/WEB-INF/jsp/editUser.jsp b/samples/spring-hibernate/web/WEB-INF/jsp/editUser.jsp
new file mode 100644
index 0000000..c6f7f01
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/jsp/editUser.jsp
@@ -0,0 +1,52 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
+
+<html>
+<head>
+ <title>JSecurity Spring-Hibernate Sample Application</title>
+ <link rel="stylesheet" type="text/css" href="<c:url value="/styles/sample.css"/>"/>
+</head>
+<body>
+ <div id="box">
+ <div class="title">JSecurity Sample App - Edit User</div>
+
+ <div class="content">
+ <form:form modelAttribute="editUserCommand">
+
+ <form:errors path="*" element="div" cssClass="errors"/>
+ <div><div class="form-label">Username:</div><form:input path="username"/></div>
+ <div><div class="form-label">Email:</div><form:input path="email"/></div>
+ <div><div class="form-label">Password:</div><form:password path="password"/></div>
+ <div><input type="button" onclick="document.location.href='<c:url value="/s/manageUsers"/>'" value="Cancel"/> <input type="submit" value="Save Changes"/></div>
+ </form:form>
+
+ <p>Only edit the password field if you want to change the user's password. Otherwise leave password blank.</p>
+
+ </div>
+
+ </div>
+
+ <script type="text/javascript">
+ document.getElementById('username').focus();
+ </script>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/samples/spring-hibernate/web/WEB-INF/jsp/home.jsp b/samples/spring-hibernate/web/WEB-INF/jsp/home.jsp
new file mode 100644
index 0000000..06e99ac
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/jsp/home.jsp
@@ -0,0 +1,55 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="jsec" uri="http://www.jsecurity.org/tags" %>
+
+<html>
+<head>
+ <title>JSecurity Spring-Hibernate Sample Application</title>
+ <link rel="stylesheet" type="text/css" href="<c:url value="/styles/sample.css"/>"/>
+</head>
+<body>
+
+<div id="bigbox">
+ <div class="title clearfix"><div style="float: left">JSecurity Sample App - Home</div><div class="info" >Logged in as ${currentUser.username} (<a href="<c:url value="/s/logout"/>">Logout</a>)</div></div>
+
+
+ <div class="content">
+
+ <p>Users in the system:</p>
+ <ul>
+ <c:forEach var="user" items="${users}">
+ <li>${user.username} - ${user.email}</li>
+ </c:forEach>
+ </ul>
+
+ <p>
+ <jsec:hasPermission name="user:manage">
+ Since you are logged in as the admin user, you can <a href="<c:url value="/s/manageUsers"/>">manage site users</a>.
+ </jsec:hasPermission>
+ <jsec:lacksPermission name="user:manage">
+ Since you are not logged in as the admin user, you can't manage site users.
+ </jsec:lacksPermission>
+ </p>
+ </div>
+
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/samples/spring-hibernate/web/WEB-INF/jsp/login.jsp b/samples/spring-hibernate/web/WEB-INF/jsp/login.jsp
new file mode 100644
index 0000000..95c6766
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/jsp/login.jsp
@@ -0,0 +1,56 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
+
+<html>
+<head>
+ <title>JSecurity Spring-Hibernate Sample Application</title>
+ <link rel="stylesheet" type="text/css" href="<c:url value="/styles/sample.css"/>"/>
+</head>
+<body>
+ <div id="box">
+ <div class="title">JSecurity Sample App - Login</div>
+
+ <div class="content">
+ <form:form modelAttribute="loginCommand">
+
+ <form:errors path="*" element="div" cssClass="errors"/>
+
+ <div><div class="form-label">Username:</div><form:input path="username"/></div>
+ <div><div class="form-label">Password:</div><form:password path="password"/></div>
+ <div><form:checkbox path="rememberMe"/> Remember Me</div>
+ <div><input type="submit" value="Login"/></div>
+ </form:form>
+
+ <div>Don't have an account? <a href="<c:url value="/s/signup"/>">Sign up</a></div>
+ </div>
+ </div>
+
+ <p>
+ Users created through the signup form have the role "user". You can also log in as admin/admin, which has the
+ "admin" role.
+ </p>
+
+ <script type="text/javascript">
+ document.getElementById('username').focus();
+ </script>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/samples/spring-hibernate/web/WEB-INF/jsp/manageUsers.jsp b/samples/spring-hibernate/web/WEB-INF/jsp/manageUsers.jsp
new file mode 100644
index 0000000..99f0677
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/jsp/manageUsers.jsp
@@ -0,0 +1,57 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="jsec" uri="http://www.jsecurity.org/tags" %>
+
+<html>
+<head>
+ <title>JSecurity Spring-Hibernate Sample Application</title>
+ <link rel="stylesheet" type="text/css" href="<c:url value="/styles/sample.css"/>"/>
+</head>
+<body>
+
+<div id="bigbox">
+ <div class="title clearfix"><div style="float: left">JSecurity Sample App - Manage Users</div><div class="info" >Logged in as ${currentUser.username} (<a href="<c:url value="/s/logout"/>">Logout</a>)</div></div>
+
+
+ <div class="content">
+
+ <table id="manageUsers">
+ <tr>
+ <th>Username</th>
+ <th>Email</th>
+ <th>Actions</th>
+ </tr>
+ <c:forEach var="user" items="${users}">
+ <tr>
+ <td>${user.username}</td>
+ <td>${user.email}</td>
+ <td><a href="<c:url value="/s/editUser?userId=${user.id}"/>">Edit</a><c:if test="${user.id ne 1}"> | <a href="<c:url value="/s/deleteUser?userId=${user.id}"/>">Delete</a></c:if>
+ </td>
+ </tr>
+ </c:forEach>
+ </table>
+
+ <p>Return to <a href="<c:url value="/s/home"/>">Home</a></p>
+ </div>
+
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/samples/spring-hibernate/web/WEB-INF/jsp/signup.jsp b/samples/spring-hibernate/web/WEB-INF/jsp/signup.jsp
new file mode 100644
index 0000000..565e435
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/jsp/signup.jsp
@@ -0,0 +1,49 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
+
+<html>
+<head>
+ <title>JSecurity Spring-Hibernate Sample Application</title>
+ <link rel="stylesheet" type="text/css" href="<c:url value="/styles/sample.css"/>"/>
+</head>
+<body>
+ <div id="box">
+ <div class="title">JSecurity Sample App - Signup</div>
+
+ <div class="content">
+ <form:form modelAttribute="signupCommand">
+
+ <form:errors path="*" element="div" cssClass="errors"/>
+
+ <div><div class="form-label">Username:</div><form:input path="username"/></div>
+ <div><div class="form-label">Email:</div><form:input path="email"/></div>
+ <div><div class="form-label">Password:</div><form:password path="password"/></div>
+ <div><input type="button" onclick="document.location.href='<c:url value="/s/login"/>'" value="Cancel"/> <input type="submit" value="Signup"/></div>
+ </form:form>
+ </div>
+ </div>
+
+ <script type="text/javascript">
+ document.getElementById('username').focus();
+ </script>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/samples/spring-hibernate/web/WEB-INF/sprhib-servlet.xml b/samples/spring-hibernate/web/WEB-INF/sprhib-servlet.xml
new file mode 100644
index 0000000..fd4ae4b
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/sprhib-servlet.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context-2.5.xsd">
+
+ <!-- Enable annotation component scanning and autowiring of web package -->
+ <context:annotation-config/>
+ <context:component-scan base-package="org.jsecurity.samples.sprhib.web"/>
+
+ <!-- Required for security annotations to work in this servlet -->
+ <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
+ <bean class="org.jsecurity.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>
+
+
+ <!-- Enable annotation-based controllers using @Controller annotations -->
+ <bean id="annotationUrlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
+ <property name="interceptors" ref="currentUserInterceptor"/>
+ </bean>
+
+ <bean id="annotationMethodHandlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
+
+ <!-- All views are JSPs loaded from /WEB-INF/jsp -->
+ <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
+ <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
+ <property name="prefix" value="/WEB-INF/jsp/"/>
+ <property name="suffix" value=".jsp"/>
+ </bean>
+
+</beans>
\ No newline at end of file
diff --git a/samples/spring-hibernate/web/WEB-INF/web.xml b/samples/spring-hibernate/web/WEB-INF/web.xml
new file mode 100644
index 0000000..0a0f39d
--- /dev/null
+++ b/samples/spring-hibernate/web/WEB-INF/web.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+<web-app version="2.4"
+ xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+ <!-- ===================================================================
+ - Context parameters
+ - =================================================================== -->
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>
+ /WEB-INF/applicationContext.xml
+ </param-value>
+ </context-param>
+
+ <!--
+ - Key of the system property that should specify the root directory of this
+ - web app. Applied by WebAppRootListener or Log4jConfigListener.
+ -->
+ <context-param>
+ <param-name>webAppRootKey</param-name>
+ <param-value>jsecurity-spring-hibernate-sample.webapp.root</param-value>
+ </context-param>
+
+ <!-- ===================================================================
+ - Servlet listeners
+ - =================================================================== -->
+ <listener>
+ <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
+ </listener>
+ <listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+ </listener>
+
+ <!-- ===================================================================
+ - Filters
+ - =================================================================== -->
+ <filter>
+ <filter-name>openSessionInViewFilter</filter-name>
+ <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
+ </filter>
+
+ <filter>
+ <filter-name>JSecurityFilter</filter-name>
+ <filter-class>org.jsecurity.spring.SpringJSecurityFilter</filter-class>
+ <init-param>
+ <param-name>config</param-name>
+ <param-value>
+
+ # The JSecurityFilter configuration is very powerful and flexible, while still remaining succinct.
+ # Please read the comprehensive example, with full comments and explanations, in the JavaDoc:
+ #
+ # http://www.jsecurity.org/api/org/jsecurity/web/servlet/JSecurityFilter.html
+
+ # If you'd prefer to not have this configuration in web.xml, you can create a file called jsecurity.ini
+ # in the root of your classpath and JSecurity will automatically pick it up.
+
+ [filters]
+ # Override the authentication filter to pass thru so we can handle login logic in our controller
+ authc = org.jsecurity.web.filter.authc.PassThruAuthenticationFilter
+ jsecurity.loginUrl = /s/login
+ jsecurity.unauthorizedUrl = /unauthorized.jsp
+ authc.successUrl = /s/home
+
+ [urls]
+ /s/signup=anon
+ /s/manageUsers=perms[user:manage]
+ /s/**=authc
+ </param-value>
+ </init-param>
+
+ </filter>
+
+ <filter-mapping>
+ <filter-name>openSessionInViewFilter</filter-name>
+ <url-pattern>/s/*</url-pattern>
+ </filter-mapping>
+
+ <filter-mapping>
+ <filter-name>JSecurityFilter</filter-name>
+ <url-pattern>/s/*</url-pattern>
+ </filter-mapping>
+
+ <!-- ===================================================================
+ - Servlets
+ - =================================================================== -->
+ <servlet>
+ <servlet-name>sprhib</servlet-name>
+ <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>sprhib</servlet-name>
+ <url-pattern>/s/*</url-pattern>
+ </servlet-mapping>
+
+
+ <!-- ===================================================================
+ - Welcome file list
+ - =================================================================== -->
+ <welcome-file-list>
+ <welcome-file>index.jsp</welcome-file>
+ </welcome-file-list>
+
+ <error-page>
+ <error-code>401</error-code>
+ <location>/unauthorized.jsp</location>
+ </error-page>
+
+</web-app>
diff --git a/samples/spring-hibernate/web/index.jsp b/samples/spring-hibernate/web/index.jsp
new file mode 100644
index 0000000..56e49ec
--- /dev/null
+++ b/samples/spring-hibernate/web/index.jsp
@@ -0,0 +1,22 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+
+<%-- Redirect to index page --%>
+<c:redirect url="/s/home"/>
\ No newline at end of file
diff --git a/samples/spring-hibernate/web/styles/sample.css b/samples/spring-hibernate/web/styles/sample.css
new file mode 100644
index 0000000..d227599
--- /dev/null
+++ b/samples/spring-hibernate/web/styles/sample.css
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+body { background: #f6f6f6}
+body, td, th { font-family:"Lucida Grande","Lucida Sans Unicode",Arial,Verdana,sans-serif; color: #333; font-size: 12px; }
+#box { width: 500px; }
+#bigbox { width: 940px; }
+#bigbox, #box { margin: 30px; padding: 0; border: thin black solid; background: #fff}
+#bigbox .title, #box .title { display: block; margin: 0 0 5px 0; padding: 5px 5px 5px 15px; background: #ddd; font-size: 18px}
+#bigbox .title .info { float: right; padding-right: 10px; font-size: 12px}
+
+.errors { color: red; padding: 10px 0 10px 0; }
+.form-label { float: left; width: 100px;}
+
+.content { padding: 10px;}
+.content div { padding: 5px; 0 5px 0 }
+
+#manageUsers { width: 800px }
+#manageUsers th { text-align: left }
+
+a:active, a:visited, a:link { color: #6666DD; text-decoration: none; }
+a:hover { color: #6666FF; text-decoration: underline; }
+
+.clearfix:after {content:".";display:block;height:0;clear:both;visibility:hidden;}
+.clearfix {display:inline-block;}
+* html .clearfix {height:1%;}
+.clearfix {display:block;}
\ No newline at end of file
diff --git a/samples/spring-hibernate/web/unauthorized.jsp b/samples/spring-hibernate/web/unauthorized.jsp
new file mode 100644
index 0000000..b46b28d
--- /dev/null
+++ b/samples/spring-hibernate/web/unauthorized.jsp
@@ -0,0 +1,29 @@
+<%--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ --%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<html>
+<head>
+ <title>JSecurity Spring-Hibernate Sample Application</title>
+ <link rel="stylesheet" type="text/css" href="<c:url value="/styles/sample.css"/>"/>
+</head>
+<body>
+<h3>Unauthorized</h3>
+<p>You are not authorized to access the requested page. Please return to the <a href="<c:url value="/s/home"/>">homepage</a>.</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/web/src/org/jsecurity/web/attr/CookieAttribute.java b/web/src/org/jsecurity/web/attr/CookieAttribute.java
index d23a365..d5d4e0a 100644
--- a/web/src/org/jsecurity/web/attr/CookieAttribute.java
+++ b/web/src/org/jsecurity/web/attr/CookieAttribute.java
@@ -170,6 +170,29 @@
return path;
}
+
+ /**
+ * Returns the Cookie's calculated path setting. If {@link Cookie#getPath() path} <tt>null</tt>, then the
+ * <tt>request</tt>'s {@link javax.servlet.http.HttpServletRequest#getContextPath() context path}
+ * will be returned. If getContextPath() is the empty string or null then the ROOT_PATH constant is returned.
+ * <p/>
+ * <p>The default is <code>null</code>.</p>
+ *
+ * @return the path to be used as the path when the cookie is created or removed.
+ */
+ public String calculatePath(HttpServletRequest request) {
+ String calculatePath = getPath() != null ? getPath() : request.getContextPath();
+
+ //fix for http://issues.apache.org/jira/browse/JSEC-34:
+ calculatePath = StringUtils.clean(calculatePath);
+ if (calculatePath == null) {
+ calculatePath = ROOT_PATH;
+ }
+ log.trace ("calculatePath: returning=" + calculatePath);
+ return calculatePath;
+ }
+
+
/**
* Sets the Cookie's {@link Cookie#getPath() path} setting. If the argument is <tt>null</tt>, the <tt>request</tt>'s
* {@link javax.servlet.http.HttpServletRequest#getContextPath() context path} will be used.
@@ -263,7 +286,7 @@
String name = getName();
int maxAge = getMaxAge();
- String path = getPath() != null ? getPath() : request.getContextPath();
+ String path = calculatePath(request);
//fix for http://issues.apache.org/jira/browse/JSEC-34:
path = StringUtils.clean(path);
@@ -280,6 +303,7 @@
}
response.addCookie(cookie);
+
if (log.isTraceEnabled()) {
log.trace("Added Cookie [" + name + "] to path [" + path + "] with value [" +
stringValue + "] to the HttpServletResponse.");
@@ -289,13 +313,17 @@
public void removeValue(ServletRequest servletRequest, ServletResponse response) {
HttpServletRequest request = toHttp(servletRequest);
Cookie cookie = getCookie(request, getName());
+
if (cookie != null) {
cookie.setMaxAge(0);
+ cookie.setValue("forgetme");
//JSEC-94: Must set the path on the outgoing cookie (some browsers don't retain it from the
//retrieved cookie?)
- cookie.setPath(getPath() == null ? request.getContextPath() : getPath());
+ // my testing shows none of these browsers will remove cookie if setPath() is not invoked: FF3, Chrome, IE7, Safari windows
+ cookie.setPath(calculatePath(request));
cookie.setSecure(isSecure());
toHttp(response).addCookie(cookie);
+ log.trace("Removed cookie[" + getName() + "] with path [" + calculatePath(request) + "] from HttpServletResponse.");
}
}
}
diff --git a/web/src/org/jsecurity/web/filter/PathConfigProcessor.java b/web/src/org/jsecurity/web/filter/PathConfigProcessor.java
index 1eb6cf0..5c84b2f 100644
--- a/web/src/org/jsecurity/web/filter/PathConfigProcessor.java
+++ b/web/src/org/jsecurity/web/filter/PathConfigProcessor.java
@@ -18,6 +18,8 @@
*/
package org.jsecurity.web.filter;
+import javax.servlet.Filter;
+
/**
* A PathConfigProcessor processes configuration entries on a per path (per url) basis.
*
@@ -28,5 +30,5 @@
//TODO - complete JavaDoc
- void processPathConfig(String path, String config);
+ Filter processPathConfig(String path, String config);
}
diff --git a/web/src/org/jsecurity/web/filter/PathMatchingFilter.java b/web/src/org/jsecurity/web/filter/PathMatchingFilter.java
index ab0173c..32ef50a 100644
--- a/web/src/org/jsecurity/web/filter/PathMatchingFilter.java
+++ b/web/src/org/jsecurity/web/filter/PathMatchingFilter.java
@@ -26,6 +26,7 @@
import org.jsecurity.web.WebUtils;
import org.jsecurity.web.servlet.AdviceFilter;
+import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.LinkedHashMap;
@@ -76,14 +77,16 @@
*
* @param path the application context path to match for executing this filter.
* @param config the specified for <em>this particular filter only</em> for the given <code>path</code>
+ * @return this configured filter.
*/
- public void processPathConfig(String path, String config) {
+ public Filter processPathConfig(String path, String config) {
String[] values = null;
if (config != null) {
values = split(config);
}
this.appliedPaths.put(path, values);
+ return this;
}
/**
diff --git a/web/test/org/jsecurity/web/attr/CookieAttributeTest.java b/web/test/org/jsecurity/web/attr/CookieAttributeTest.java
index 6855bc3..5c284ae 100644
--- a/web/test/org/jsecurity/web/attr/CookieAttributeTest.java
+++ b/web/test/org/jsecurity/web/attr/CookieAttributeTest.java
@@ -55,7 +55,7 @@
expect(mockRequest.getCookies()).andReturn(cookies);
//no path set on the cookie, so we expect to retrieve it from the context path
- expect(mockRequest.getContextPath()).andReturn("/somepath");
+ expect(mockRequest.getContextPath()).andReturn("/somepath").times(2);
mockResponse.addCookie(cookie);
replay(mockRequest);
replay(mockResponse);
@@ -121,4 +121,29 @@
});
return null;
}
+
+ @Test
+ //Verifies fix for JSEC-64
+ public void testRemoveValueWithNullContext() throws Exception {
+
+ Cookie cookie = new Cookie("test", "blah");
+ cookie.setMaxAge(2351234); //doesn't matter what the time is
+ Cookie[] cookies = new Cookie[]{cookie};
+
+ expect(mockRequest.getCookies()).andReturn(cookies);
+ //no path set on the cookie, so we expect to retrieve it from the context path
+ expect(mockRequest.getContextPath()).andReturn(null).times(2);
+ mockResponse.addCookie(cookie);
+ replay(mockRequest);
+ replay(mockResponse);
+
+ cookieAttribute.removeValue(mockRequest, mockResponse);
+
+ verify(mockRequest);
+ verify(mockResponse);
+
+ assertTrue(cookie.getMaxAge() == 0);
+ assertTrue(cookie.getPath().equals("/"));
+ }
+
}