diff --git a/core/src/test/java/org/springframework/security/context/SecurityContextHolderTests.java b/core/src/test/java/org/springframework/security/context/SecurityContextHolderTests.java
index bb1f3c8cc8..f07945ec3e 100644
--- a/core/src/test/java/org/springframework/security/context/SecurityContextHolderTests.java
+++ b/core/src/test/java/org/springframework/security/context/SecurityContextHolderTests.java
@@ -15,14 +15,10 @@
package org.springframework.security.context;
-import junit.framework.ComparisonFailure;
import junit.framework.TestCase;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-import java.util.Random;
-
-
/**
* Tests {@link SecurityContextHolder}.
*
@@ -30,193 +26,13 @@ import java.util.Random;
* @version $Id$
*/
public class SecurityContextHolderTests extends TestCase {
- //~ Static fields/initializers =====================================================================================
-
- private static int errors = 0;
-
- private static final int NUM_OPS = 5;
- private static final int NUM_THREADS = 5;
-
- //~ Constructors ===================================================================================================
-
- public SecurityContextHolderTests() {
- super();
- }
-
- public SecurityContextHolderTests(String arg0) {
- super(arg0);
- }
//~ Methods ========================================================================================================
- private void loadStartAndWaitForThreads(boolean topLevelThread, String prefix, int createThreads,
- boolean expectAllThreadsToUseIdenticalAuthentication, boolean expectChildrenToShareAuthenticationWithParent) {
- Thread[] threads = new Thread[createThreads];
- errors = 0;
-
- if (topLevelThread) {
- // PARENT (TOP-LEVEL) THREAD CREATION
- if (expectChildrenToShareAuthenticationWithParent) {
- // An InheritableThreadLocal
- for (int i = 0; i < threads.length; i++) {
- if ((i % 2) == 0) {
- // Don't inject auth into current thread; neither current thread or child will have authentication
- threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, true, null);
- } else {
- // Inject auth into current thread, but not child; current thread will have auth, child will also have auth
- threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, true,
- prefix + "Auth_Parent_" + i);
- }
- }
- } else if (expectAllThreadsToUseIdenticalAuthentication) {
- // A global
- SecurityContextHolder.getContext()
- .setAuthentication(new UsernamePasswordAuthenticationToken("GLOBAL_USERNAME",
- "pass"));
-
- for (int i = 0; i < threads.length; i++) {
- if ((i % 2) == 0) {
- // Don't inject auth into current thread;both current thread and child will have same authentication
- threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, true, true,
- "GLOBAL_USERNAME");
- } else {
- // Inject auth into current thread; current thread will have auth, child will also have auth
- threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, true, true, "GLOBAL_USERNAME");
- }
- }
- } else {
- // A standard ThreadLocal
- for (int i = 0; i < threads.length; i++) {
- if ((i % 2) == 0) {
- // Don't inject auth into current thread; neither current thread or child will have authentication
- threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, false, null);
- } else {
- // Inject auth into current thread, but not child; current thread will have auth, child will not have auth
- threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, false,
- prefix + "Auth_Parent_" + i);
- }
- }
- }
- } else {
- // CHILD THREAD CREATION
- if (expectChildrenToShareAuthenticationWithParent || expectAllThreadsToUseIdenticalAuthentication) {
- // The children being created are all expected to have security (ie an InheritableThreadLocal/global AND auth was injected into parent)
- for (int i = 0; i < threads.length; i++) {
- String expectedUsername = prefix;
-
- if (expectAllThreadsToUseIdenticalAuthentication) {
- expectedUsername = "GLOBAL_USERNAME";
- }
-
- // Don't inject auth into current thread; the current thread will obtain auth from its parent
- // NB: As topLevelThread = true, no further child threads will be created
- threads[i] = makeThread(prefix + "->child->Inherited_Auth_Child_" + i, false, false,
- expectAllThreadsToUseIdenticalAuthentication, false, expectedUsername);
- }
- } else {
- // The children being created are NOT expected to have security (ie not an InheritableThreadLocal OR auth was not injected into parent)
- for (int i = 0; i < threads.length; i++) {
- // Don't inject auth into current thread; neither current thread or child will have authentication
- // NB: As topLevelThread = true, no further child threads will be created
- threads[i] = makeThread(prefix + "->child->Unauth_Child_" + i, false, false, false, false, null);
- }
- }
- }
-
- // Start and execute the threads
- startAndRun(threads);
- }
-
- public static void main(String[] args) {
- junit.textui.TestRunner.run(SecurityContextHolderTests.class);
- }
-
- private Thread makeThread(final String threadIdentifier, final boolean topLevelThread,
- final boolean injectAuthIntoCurrentThread, final boolean expectAllThreadsToUseIdenticalAuthentication,
- final boolean expectChildrenToShareAuthenticationWithParent, final String expectedUsername) {
- final Random rnd = new Random();
-
- Thread t = new Thread(new Runnable() {
- public void run() {
- if (injectAuthIntoCurrentThread) {
- // Set authentication in this thread
- SecurityContextHolder.getContext()
- .setAuthentication(new UsernamePasswordAuthenticationToken(
- expectedUsername, "pass"));
-
- //System.out.println(threadIdentifier + " - set to " + SecurityContextHolder.getContext().getAuthentication());
- } else {
- //System.out.println(threadIdentifier + " - not set (currently " + SecurityContextHolder.getContext().getAuthentication() + ")");
- }
-
- // Do some operations in current thread, checking authentication is as expected in the current thread (ie another thread doesn't change it)
- for (int i = 0; i < NUM_OPS; i++) {
- String currentUsername = (SecurityContextHolder.getContext().getAuthentication() == null)
- ? null : SecurityContextHolder.getContext().getAuthentication().getName();
-
- if ((i % 7) == 0) {
- System.out.println(threadIdentifier + " at " + i + " username " + currentUsername);
- }
-
- try {
- TestCase.assertEquals("Failed on iteration " + i + "; Authentication was '"
- + currentUsername + "' but principal was expected to contain username '"
- + expectedUsername + "'", expectedUsername, currentUsername);
- } catch (ComparisonFailure err) {
- errors++;
- throw err;
- }
-
- try {
- Thread.sleep(rnd.nextInt(250));
- } catch (InterruptedException ignore) {}
- }
-
- // Load some children threads, checking the authentication is as expected in the children (ie another thread doesn't change it)
- if (topLevelThread) {
- // Make four children, but we don't want the children to have any more children (so anti-nature, huh?)
- if (injectAuthIntoCurrentThread && expectChildrenToShareAuthenticationWithParent) {
- loadStartAndWaitForThreads(false, threadIdentifier, 4,
- expectAllThreadsToUseIdenticalAuthentication, true);
- } else {
- loadStartAndWaitForThreads(false, threadIdentifier, 4,
- expectAllThreadsToUseIdenticalAuthentication, false);
- }
- }
- }
- }, threadIdentifier);
-
- return t;
- }
-
public final void setUp() throws Exception {
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}
- private void startAndRun(Thread[] threads) {
- // Start them up
- for (int i = 0; i < threads.length; i++) {
- threads[i].start();
- }
-
- // Wait for them to finish
- while (stillRunning(threads)) {
- try {
- Thread.sleep(250);
- } catch (InterruptedException ignore) {}
- }
- }
-
- private boolean stillRunning(Thread[] threads) {
- for (int i = 0; i < threads.length; i++) {
- if (threads[i].isAlive()) {
- return true;
- }
- }
-
- return false;
- }
-
public void testContextHolderGetterSetterClearer() {
SecurityContext sc = new SecurityContextImpl();
sc.setAuthentication(new UsernamePasswordAuthenticationToken("Foobar", "pass"));
@@ -240,34 +56,4 @@ public class SecurityContextHolderTests extends TestCase {
assertTrue(true);
}
}
-
- public void testSynchronizationCustomStrategyLoading() {
- SecurityContextHolder.setStrategyName(InheritableThreadLocalSecurityContextHolderStrategy.class.getName());
- assertTrue(new SecurityContextHolder().toString()
- .lastIndexOf("SecurityContextHolder[strategy='org.springframework.security.context.InheritableThreadLocalSecurityContextHolderStrategy'") != -1);
- loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
- assertEquals("Thread errors detected; review log output for details", 0, errors);
- }
-
- public void testSynchronizationGlobal() throws Exception {
- SecurityContextHolder.clearContext();
- SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
- loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, true, false);
- assertEquals("Thread errors detected; review log output for details", 0, errors);
- }
-
- public void testSynchronizationInheritableThreadLocal()
- throws Exception {
- SecurityContextHolder.clearContext();
- SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
- loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
- assertEquals("Thread errors detected; review log output for details", 0, errors);
- }
-
- public void testSynchronizationThreadLocal() throws Exception {
- SecurityContextHolder.clearContext();
- SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
- loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, false);
- assertEquals("Thread errors detected; review log output for details", 0, errors);
- }
}
diff --git a/sandbox/itest/misc/pom.xml b/sandbox/itest/misc/pom.xml
new file mode 100644
index 0000000000..9c1830162f
--- /dev/null
+++ b/sandbox/itest/misc/pom.xml
@@ -0,0 +1,29 @@
+
+
+ 4.0.0
+
+ org.springframework.security
+ spring-security-itest
+ 2.0.4-SNAPSHOT
+
+ spring-security-itest-misc
+ Spring Security - Miscellaneous Integration Tests
+ jar
+
+
+
+ org.springframework
+ spring-test
+ 2.5.5
+ test
+
+
+
+
diff --git a/sandbox/itest/misc/src/main/resources/log4j.properties b/sandbox/itest/misc/src/main/resources/log4j.properties
new file mode 100644
index 0000000000..e5340c70b2
--- /dev/null
+++ b/sandbox/itest/misc/src/main/resources/log4j.properties
@@ -0,0 +1,8 @@
+log4j.rootCategory=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
+
+log4j.category.org.mortbay.log=INFO
+log4j.category.org.springframework.security=DEBUG
\ No newline at end of file
diff --git a/core/src/test/java/org/springframework/security/concurrent/SessionRegistryImplMultithreadedTests.java b/sandbox/itest/misc/src/test/java/org/springframework/security/concurrent/SessionRegistryImplMultithreadedTests.java
similarity index 100%
rename from core/src/test/java/org/springframework/security/concurrent/SessionRegistryImplMultithreadedTests.java
rename to sandbox/itest/misc/src/test/java/org/springframework/security/concurrent/SessionRegistryImplMultithreadedTests.java
diff --git a/sandbox/itest/misc/src/test/java/org/springframework/security/context/SecurityContextHolderMTTests.java b/sandbox/itest/misc/src/test/java/org/springframework/security/context/SecurityContextHolderMTTests.java
new file mode 100644
index 0000000000..51bd8ba770
--- /dev/null
+++ b/sandbox/itest/misc/src/test/java/org/springframework/security/context/SecurityContextHolderMTTests.java
@@ -0,0 +1,216 @@
+package org.springframework.security.context;
+
+import java.util.Random;
+
+import junit.framework.ComparisonFailure;
+import junit.framework.TestCase;
+
+
+
+import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
+
+/**
+ * Multi-threaded tests for SecurityContextHolder
+ *
+ * @author Ben Alex
+ * @Author Luke Taylor
+ */
+public class SecurityContextHolderMTTests extends TestCase{
+ private int errors = 0;
+
+ private static final int NUM_OPS = 25;
+ private static final int NUM_THREADS = 25;
+
+ public final void setUp() throws Exception {
+ SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
+ }
+
+ public void testSynchronizationCustomStrategyLoading() {
+ SecurityContextHolder.setStrategyName(InheritableThreadLocalSecurityContextHolderStrategy.class.getName());
+ assertTrue(new SecurityContextHolder().toString()
+ .lastIndexOf("SecurityContextHolder[strategy='org.springframework.security.context.InheritableThreadLocalSecurityContextHolderStrategy'") != -1);
+ loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
+ assertEquals("Thread errors detected; review log output for details", 0, errors);
+ }
+
+ public void testSynchronizationGlobal() throws Exception {
+ SecurityContextHolder.clearContext();
+ SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
+ loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, true, false);
+ assertEquals("Thread errors detected; review log output for details", 0, errors);
+ }
+
+ public void testSynchronizationInheritableThreadLocal()
+ throws Exception {
+ SecurityContextHolder.clearContext();
+ SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
+ loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, true);
+ assertEquals("Thread errors detected; review log output for details", 0, errors);
+ }
+
+ public void testSynchronizationThreadLocal() throws Exception {
+ SecurityContextHolder.clearContext();
+ SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
+ loadStartAndWaitForThreads(true, "Main_", NUM_THREADS, false, false);
+ assertEquals("Thread errors detected; review log output for details", 0, errors);
+ }
+
+ private void startAndRun(Thread[] threads) {
+ // Start them up
+ for (int i = 0; i < threads.length; i++) {
+ threads[i].start();
+ }
+
+ // Wait for them to finish
+ while (stillRunning(threads)) {
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException ignore) {}
+ }
+ }
+
+ private boolean stillRunning(Thread[] threads) {
+ for (int i = 0; i < threads.length; i++) {
+ if (threads[i].isAlive()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void loadStartAndWaitForThreads(boolean topLevelThread, String prefix, int createThreads,
+ boolean expectAllThreadsToUseIdenticalAuthentication, boolean expectChildrenToShareAuthenticationWithParent) {
+ Thread[] threads = new Thread[createThreads];
+ errors = 0;
+
+ if (topLevelThread) {
+ // PARENT (TOP-LEVEL) THREAD CREATION
+ if (expectChildrenToShareAuthenticationWithParent) {
+ // An InheritableThreadLocal
+ for (int i = 0; i < threads.length; i++) {
+ if ((i % 2) == 0) {
+ // Don't inject auth into current thread; neither current thread or child will have authentication
+ threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, true, null);
+ } else {
+ // Inject auth into current thread, but not child; current thread will have auth, child will also have auth
+ threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, true,
+ prefix + "Auth_Parent_" + i);
+ }
+ }
+ } else if (expectAllThreadsToUseIdenticalAuthentication) {
+ // A global
+ SecurityContextHolder.getContext()
+ .setAuthentication(new UsernamePasswordAuthenticationToken("GLOBAL_USERNAME",
+ "pass"));
+
+ for (int i = 0; i < threads.length; i++) {
+ if ((i % 2) == 0) {
+ // Don't inject auth into current thread;both current thread and child will have same authentication
+ threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, true, true,
+ "GLOBAL_USERNAME");
+ } else {
+ // Inject auth into current thread; current thread will have auth, child will also have auth
+ threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, true, true, "GLOBAL_USERNAME");
+ }
+ }
+ } else {
+ // A standard ThreadLocal
+ for (int i = 0; i < threads.length; i++) {
+ if ((i % 2) == 0) {
+ // Don't inject auth into current thread; neither current thread or child will have authentication
+ threads[i] = makeThread(prefix + "Unauth_Parent_" + i, true, false, false, false, null);
+ } else {
+ // Inject auth into current thread, but not child; current thread will have auth, child will not have auth
+ threads[i] = makeThread(prefix + "Auth_Parent_" + i, true, true, false, false,
+ prefix + "Auth_Parent_" + i);
+ }
+ }
+ }
+ } else {
+ // CHILD THREAD CREATION
+ if (expectChildrenToShareAuthenticationWithParent || expectAllThreadsToUseIdenticalAuthentication) {
+ // The children being created are all expected to have security (ie an InheritableThreadLocal/global AND auth was injected into parent)
+ for (int i = 0; i < threads.length; i++) {
+ String expectedUsername = prefix;
+
+ if (expectAllThreadsToUseIdenticalAuthentication) {
+ expectedUsername = "GLOBAL_USERNAME";
+ }
+
+ // Don't inject auth into current thread; the current thread will obtain auth from its parent
+ // NB: As topLevelThread = true, no further child threads will be created
+ threads[i] = makeThread(prefix + "->child->Inherited_Auth_Child_" + i, false, false,
+ expectAllThreadsToUseIdenticalAuthentication, false, expectedUsername);
+ }
+ } else {
+ // The children being created are NOT expected to have security (ie not an InheritableThreadLocal OR auth was not injected into parent)
+ for (int i = 0; i < threads.length; i++) {
+ // Don't inject auth into current thread; neither current thread or child will have authentication
+ // NB: As topLevelThread = true, no further child threads will be created
+ threads[i] = makeThread(prefix + "->child->Unauth_Child_" + i, false, false, false, false, null);
+ }
+ }
+ }
+
+ // Start and execute the threads
+ startAndRun(threads);
+ }
+
+ private Thread makeThread(final String threadIdentifier, final boolean topLevelThread,
+ final boolean injectAuthIntoCurrentThread, final boolean expectAllThreadsToUseIdenticalAuthentication,
+ final boolean expectChildrenToShareAuthenticationWithParent, final String expectedUsername) {
+ final Random rnd = new Random();
+
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ if (injectAuthIntoCurrentThread) {
+ // Set authentication in this thread
+ SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
+ expectedUsername, "pass"));
+
+ //System.out.println(threadIdentifier + " - set to " + SecurityContextHolder.getContext().getAuthentication());
+ } else {
+ //System.out.println(threadIdentifier + " - not set (currently " + SecurityContextHolder.getContext().getAuthentication() + ")");
+ }
+
+ // Do some operations in current thread, checking authentication is as expected in the current thread (ie another thread doesn't change it)
+ for (int i = 0; i < NUM_OPS; i++) {
+ String currentUsername = (SecurityContextHolder.getContext().getAuthentication() == null)
+ ? null : SecurityContextHolder.getContext().getAuthentication().getName();
+
+ if ((i % 7) == 0) {
+ System.out.println(threadIdentifier + " at " + i + " username " + currentUsername);
+ }
+
+ try {
+ assertEquals("Failed on iteration " + i + "; Authentication was '"
+ + currentUsername + "' but principal was expected to contain username '"
+ + expectedUsername + "'", expectedUsername, currentUsername);
+ } catch (ComparisonFailure err) {
+ errors++;
+ throw err;
+ }
+
+ try {
+ Thread.sleep(rnd.nextInt(250));
+ } catch (InterruptedException ignore) {}
+ }
+
+ // Load some children threads, checking the authentication is as expected in the children (ie another thread doesn't change it)
+ if (topLevelThread) {
+ // Make four children, but we don't want the children to have any more children (so anti-nature, huh?)
+ if (injectAuthIntoCurrentThread && expectChildrenToShareAuthenticationWithParent) {
+ loadStartAndWaitForThreads(false, threadIdentifier, 4,
+ expectAllThreadsToUseIdenticalAuthentication, true);
+ } else {
+ loadStartAndWaitForThreads(false, threadIdentifier, 4,
+ expectAllThreadsToUseIdenticalAuthentication, false);
+ }
+ }
+ }
+ }, threadIdentifier);
+
+ return t;
+ }
+}
diff --git a/sandbox/itest/pom.xml b/sandbox/itest/pom.xml
index 9e2696a5a8..f6e5a315a8 100644
--- a/sandbox/itest/pom.xml
+++ b/sandbox/itest/pom.xml
@@ -15,7 +15,7 @@
web
-
+ misc
@@ -36,7 +36,7 @@
org.springframework
spring
- 2.5.4
+ 2.5.5
commons-logging