mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 09:12:14 +00:00
SEC-904: Moved multi-threaded tests into sandbox
This commit is contained in:
parent
479693ced7
commit
2cda6242c8
@ -15,14 +15,10 @@
|
|||||||
|
|
||||||
package org.springframework.security.context;
|
package org.springframework.security.context;
|
||||||
|
|
||||||
import junit.framework.ComparisonFailure;
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link SecurityContextHolder}.
|
* Tests {@link SecurityContextHolder}.
|
||||||
*
|
*
|
||||||
@ -30,193 +26,13 @@ import java.util.Random;
|
|||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public class SecurityContextHolderTests extends TestCase {
|
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 ========================================================================================================
|
//~ 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 {
|
public final void setUp() throws Exception {
|
||||||
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
|
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() {
|
public void testContextHolderGetterSetterClearer() {
|
||||||
SecurityContext sc = new SecurityContextImpl();
|
SecurityContext sc = new SecurityContextImpl();
|
||||||
sc.setAuthentication(new UsernamePasswordAuthenticationToken("Foobar", "pass"));
|
sc.setAuthentication(new UsernamePasswordAuthenticationToken("Foobar", "pass"));
|
||||||
@ -240,34 +56,4 @@ public class SecurityContextHolderTests extends TestCase {
|
|||||||
assertTrue(true);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
29
sandbox/itest/misc/pom.xml
Normal file
29
sandbox/itest/misc/pom.xml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-itest</artifactId>
|
||||||
|
<version>2.0.4-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>spring-security-itest-misc</artifactId>
|
||||||
|
<name>Spring Security - Miscellaneous Integration Tests</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<version>2.5.5</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!--
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
-->
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
8
sandbox/itest/misc/src/main/resources/log4j.properties
Normal file
8
sandbox/itest/misc/src/main/resources/log4j.properties
Normal file
@ -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
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@
|
|||||||
<modules>
|
<modules>
|
||||||
<module>web</module>
|
<module>web</module>
|
||||||
<!-- module>webflow</module-->
|
<!-- module>webflow</module-->
|
||||||
<!--module>context</module-->
|
<module>misc</module>
|
||||||
</modules>
|
</modules>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring</artifactId>
|
<artifactId>spring</artifactId>
|
||||||
<version>2.5.4</version>
|
<version>2.5.5</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>commons-logging</groupId>
|
<groupId>commons-logging</groupId>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user