diff --git a/core/core.gradle b/core/core.gradle index 7b986e138d..74499bc79b 100644 --- a/core/core.gradle +++ b/core/core.gradle @@ -19,7 +19,8 @@ dependencies { testCompile 'commons-collections:commons-collections:3.2', "org.springframework:spring-test:$springVersion", - "org.slf4j:jcl-over-slf4j:$slf4jVersion" + "org.slf4j:jcl-over-slf4j:$slf4jVersion", + powerMockDependencies testRuntime "hsqldb:hsqldb:$hsqlVersion", "cglib:cglib-nodep:$cglibVersion" diff --git a/core/src/main/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextSupport.java b/core/src/main/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextSupport.java new file mode 100644 index 0000000000..85b3c784f8 --- /dev/null +++ b/core/src/main/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextSupport.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import java.util.concurrent.Callable; + +import org.springframework.security.core.context.SecurityContext; + +/** + * An internal support class that wraps {@link Callable} with {@link DelegatingSecurityContextCallable} and + * {@link Runnable} with {@link DelegatingSecurityContextRunnable} + * + * @author Rob Winch + * @since 3.2 + */ +abstract class AbstractDelegatingSecurityContextSupport { + + private final SecurityContext securityContext; + + /** + * Creates a new {@link AbstractDelegatingSecurityContextSupport} that uses the specified {@link SecurityContext}. + * + * @param securityContext the {@link SecurityContext} to use for each {@link DelegatingSecurityContextRunnable} and + * each {@link DelegatingSecurityContextCallable} or null to default to the current {@link SecurityContext}. + */ + AbstractDelegatingSecurityContextSupport(SecurityContext securityContext) { + this.securityContext = securityContext; + } + + protected final Runnable wrap(Runnable delegate) { + return DelegatingSecurityContextRunnable.create(delegate, securityContext); + } + + protected final Callable wrap(Callable delegate) { + return DelegatingSecurityContextCallable.create(delegate, securityContext); + } +} diff --git a/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextCallable.java b/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextCallable.java new file mode 100644 index 0000000000..278b529a37 --- /dev/null +++ b/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextCallable.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import java.util.concurrent.Callable; + +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.Assert; + +/** + * Wraps a delegate {@link Callable} with logic for setting up a {@link SecurityContext} before invoking the delegate + * {@link Callable} and then removing the {@link SecurityContext} after the delegate has completed. + * + * @author Rob Winch + * @since 3.2 + */ +public final class DelegatingSecurityContextCallable implements Callable { + + private final Callable delegate; + + private final SecurityContext securityContext; + + /** + * Creates a new {@link DelegatingSecurityContextCallable} with a specific {@link SecurityContext}. + * @param delegate the delegate {@link DelegatingSecurityContextCallable} to run with the specified + * {@link SecurityContext}. Cannot be null. + * @param securityContext the {@link SecurityContext} to establish for the delegate {@link Callable}. Cannot be + * null. + */ + public DelegatingSecurityContextCallable(Callable delegate, SecurityContext securityContext) { + Assert.notNull(delegate, "delegate cannot be null"); + Assert.notNull(securityContext, "securityContext cannot be null"); + this.delegate = delegate; + this.securityContext = securityContext; + } + + /** + * Creates a new {@link DelegatingSecurityContextCallable} with the {@link SecurityContext} from the + * {@link SecurityContextHolder}. + * @param delegate the delegate {@link Callable} to run under the current {@link SecurityContext}. Cannot be null. + */ + public DelegatingSecurityContextCallable(Callable delegate) { + this(delegate, SecurityContextHolder.getContext()); + } + + public V call() throws Exception { + try { + SecurityContextHolder.setContext(securityContext); + return delegate.call(); + } + finally { + SecurityContextHolder.clearContext(); + } + } + + /** + * Creates a {@link DelegatingSecurityContextCallable} and with the given {@link Callable} and + * {@link SecurityContext}, but if the securityContext is null will defaults to the current {@link SecurityContext} + * on the {@link SecurityContextHolder} + * + * @param delegate the delegate {@link DelegatingSecurityContextCallable} to run with the specified + * {@link SecurityContext}. Cannot be null. + * @param securityContext the {@link SecurityContext} to establish for the delegate {@link Callable}. If null, + * defaults to {@link SecurityContextHolder#getContext()} + * @return + */ + public static Callable create(Callable delegate, SecurityContext securityContext) { + return securityContext == null ? new DelegatingSecurityContextCallable(delegate) + : new DelegatingSecurityContextCallable(delegate, securityContext); + } +} diff --git a/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextExecutor.java b/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextExecutor.java new file mode 100644 index 0000000000..3cc27db0c5 --- /dev/null +++ b/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextExecutor.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import java.util.concurrent.Executor; + +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.Assert; + +/** + * An {@link Executor} which wraps each {@link Runnable} in a {@link DelegatingSecurityContextRunnable}. + * + * @author Rob Winch + * @since 3.2 + */ +public class DelegatingSecurityContextExecutor extends AbstractDelegatingSecurityContextSupport implements Executor { + private final Executor delegate; + + /** + * Creates a new {@link DelegatingSecurityContextExecutor} that uses the specified {@link SecurityContext}. + * + * @param delegateExecutor the {@link Executor} to delegate to. Cannot be null. + * @param securityContext the {@link SecurityContext} to use for each {@link DelegatingSecurityContextRunnable} or + * null to default to the current {@link SecurityContext} + */ + public DelegatingSecurityContextExecutor(Executor delegateExecutor, SecurityContext securityContext) { + super(securityContext); + Assert.notNull(delegateExecutor, "delegateExecutor cannot be null"); + this.delegate = delegateExecutor; + } + + /** + * Creates a new {@link DelegatingSecurityContextExecutor} that uses the current {@link SecurityContext} from the + * {@link SecurityContextHolder} at the time the task is submitted. + * + * @param delegate the {@link Executor} to delegate to. Cannot be null. + */ + public DelegatingSecurityContextExecutor(Executor delegate) { + this(delegate, null); + } + + public final void execute(Runnable task) { + task = wrap(task); + delegate.execute(task); + } + + protected final Executor getDelegateExecutor() { + return delegate; + } +} \ No newline at end of file diff --git a/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextExecutorService.java b/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextExecutorService.java new file mode 100644 index 0000000000..8dd5a6b3ea --- /dev/null +++ b/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextExecutorService.java @@ -0,0 +1,135 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.springframework.core.task.TaskExecutor; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * An {@link ExecutorService} which wraps each {@link Runnable} in a {@link DelegatingSecurityContextRunnable} and each + * {@link Callable} in a {@link DelegatingSecurityContextCallable}. + * + * @author Rob Winch + * @since 3.2 + */ +public class DelegatingSecurityContextExecutorService extends DelegatingSecurityContextExecutor implements + ExecutorService { + /** + * Creates a new {@link DelegatingSecurityContextExecutorService} that uses the specified {@link SecurityContext}. + * + * @param delegateExecutorService the {@link ExecutorService} to delegate to. Cannot be null. + * @param securityContext the {@link SecurityContext} to use for each {@link DelegatingSecurityContextRunnable} and + * each {@link DelegatingSecurityContextCallable}. + */ + public DelegatingSecurityContextExecutorService(ExecutorService delegateExecutorService, + SecurityContext securityContext) { + super(delegateExecutorService, securityContext); + } + + /** + * Creates a new {@link DelegatingSecurityContextExecutorService} that uses the current {@link SecurityContext} from + * the {@link SecurityContextHolder}. + * + * @param delegateTaskExecutor the {@link TaskExecutor} to delegate to. Cannot be null. + */ + public DelegatingSecurityContextExecutorService(ExecutorService delegate) { + this(delegate, null); + } + + public final void shutdown() { + getDelegate().shutdown(); + } + + public final List shutdownNow() { + return getDelegate().shutdownNow(); + } + + public final boolean isShutdown() { + return getDelegate().isShutdown(); + } + + public final boolean isTerminated() { + return getDelegate().isTerminated(); + } + + public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + return getDelegate().awaitTermination(timeout, unit); + } + + public final Future submit(Callable task) { + task = wrap(task); + return getDelegate().submit(task); + } + + public final Future submit(Runnable task, T result) { + task = wrap(task); + return getDelegate().submit(task, result); + } + + public final Future submit(Runnable task) { + task = wrap(task); + return getDelegate().submit(task); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public final List invokeAll(Collection tasks) throws InterruptedException { + tasks = createTasks(tasks); + return getDelegate().invokeAll(tasks); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public final List invokeAll(Collection tasks, long timeout, TimeUnit unit) + throws InterruptedException { + tasks = createTasks(tasks); + return getDelegate().invokeAll(tasks, timeout, unit); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public final Object invokeAny(Collection tasks) throws InterruptedException, ExecutionException { + tasks = createTasks(tasks); + return getDelegate().invokeAny(tasks); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public final Object invokeAny(Collection tasks, long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + tasks = createTasks(tasks); + return getDelegate().invokeAny(tasks, timeout, unit); + } + + private Collection> createTasks(Collection> tasks) { + if (tasks == null) { + return null; + } + List> results = new ArrayList>(tasks.size()); + for (Callable task : tasks) { + results.add(wrap(task)); + } + return results; + } + + private ExecutorService getDelegate() { + return (ExecutorService) getDelegateExecutor(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextRunnable.java b/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextRunnable.java new file mode 100644 index 0000000000..c9371af44f --- /dev/null +++ b/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextRunnable.java @@ -0,0 +1,78 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.Assert; + +/** + * Wraps a delegate {@link Runnable} with logic for setting up a {@link SecurityContext} before invoking the delegate + * {@link Runnable} and then removing the {@link SecurityContext} after the delegate has completed. + * + * @author Rob Winch + * @since 3.2 + */ +public final class DelegatingSecurityContextRunnable implements Runnable { + + private final Runnable delegate; + + private final SecurityContext securityContext; + + /** + * Creates a new {@link DelegatingSecurityContextRunnable} with a specific {@link SecurityContext}. + * @param delegate the delegate {@link Runnable} to run with the specified {@link SecurityContext}. Cannot be null. + * @param securityContext the {@link SecurityContext} to establish for the delegate {@link Runnable}. Cannot be + * null. + */ + public DelegatingSecurityContextRunnable(Runnable delegate, SecurityContext securityContext) { + Assert.notNull(delegate, "delegate cannot be null"); + Assert.notNull(securityContext, "securityContext cannot be null"); + this.delegate = delegate; + this.securityContext = securityContext; + } + + /** + * Creates a new {@link DelegatingSecurityContextRunnable} with the {@link SecurityContext} from the + * {@link SecurityContextHolder}. + * @param delegate the delegate {@link Runnable} to run under the current {@link SecurityContext}. Cannot be null. + */ + public DelegatingSecurityContextRunnable(Runnable delegate) { + this(delegate, SecurityContextHolder.getContext()); + } + + public void run() { + try { + SecurityContextHolder.setContext(securityContext); + delegate.run(); + } + finally { + SecurityContextHolder.clearContext(); + } + } + + /** + * Factory method for creating a {@link DelegatingSecurityContextRunnable}. + * + * @param delegate the original {@link Runnable} that will be delegated to after establishing a + * {@link SecurityContext} on the {@link SecurityContextHolder}. Cannot have null. + * @param securityContext the {@link SecurityContext} to establish before invoking the delegate {@link Runnable}. If + * null, the current {@link SecurityContext} from the {@link SecurityContextHolder} will be used. + * @return + */ + public static Runnable create(Runnable delegate, SecurityContext securityContext) { + Assert.notNull(delegate, "delegate cannot be null"); + return securityContext == null ? new DelegatingSecurityContextRunnable(delegate) + : new DelegatingSecurityContextRunnable(delegate, securityContext); + } +} diff --git a/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextScheduledExecutorService.java b/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextScheduledExecutorService.java new file mode 100644 index 0000000000..94f61396ef --- /dev/null +++ b/core/src/main/java/org/springframework/security/concurrent/DelegatingSecurityContextScheduledExecutorService.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.springframework.core.task.TaskExecutor; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * An {@link ScheduledExecutorService} which wraps each {@link Runnable} in a {@link DelegatingSecurityContextRunnable} + * and each {@link Callable} in a {@link DelegatingSecurityContextCallable}. + * + * @author Rob Winch + * @since 3.2 + */ +public final class DelegatingSecurityContextScheduledExecutorService extends DelegatingSecurityContextExecutorService + implements ScheduledExecutorService { + /** + * Creates a new {@link DelegatingSecurityContextScheduledExecutorService} that uses the specified + * {@link SecurityContext}. + * + * @param delegateScheduledExecutorService the {@link ScheduledExecutorService} to delegate to. Cannot be null. + * @param securityContext the {@link SecurityContext} to use for each {@link DelegatingSecurityContextRunnable} and + * each {@link DelegatingSecurityContextCallable}. + */ + public DelegatingSecurityContextScheduledExecutorService(ScheduledExecutorService delegateScheduledExecutorService, + SecurityContext securityContext) { + super(delegateScheduledExecutorService, securityContext); + } + + /** + * Creates a new {@link DelegatingSecurityContextScheduledExecutorService} that uses the current + * {@link SecurityContext} from the {@link SecurityContextHolder}. + * + * @param delegateTaskExecutor the {@link TaskExecutor} to delegate to. Cannot be null. + */ + public DelegatingSecurityContextScheduledExecutorService(ScheduledExecutorService delegate) { + this(delegate, null); + } + + public final ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + command = wrap(command); + return getDelegate().schedule(command, delay, unit); + } + + public final ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { + callable = wrap(callable); + return getDelegate().schedule(callable, delay, unit); + } + + public final ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + command = wrap(command); + return getDelegate().scheduleAtFixedRate(command, initialDelay, period, unit); + } + + public final ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, + TimeUnit unit) { + command = wrap(command); + return getDelegate().scheduleWithFixedDelay(command, initialDelay, delay, unit); + } + + private ScheduledExecutorService getDelegate() { + return (ScheduledExecutorService) getDelegateExecutor(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/springframework/security/scheduling/DelegatingSecurityContextSchedulingTaskExecutor.java b/core/src/main/java/org/springframework/security/scheduling/DelegatingSecurityContextSchedulingTaskExecutor.java new file mode 100644 index 0000000000..40fc4bfb0a --- /dev/null +++ b/core/src/main/java/org/springframework/security/scheduling/DelegatingSecurityContextSchedulingTaskExecutor.java @@ -0,0 +1,62 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.scheduling; + +import java.util.concurrent.Callable; + +import org.springframework.core.task.AsyncTaskExecutor; +import org.springframework.scheduling.SchedulingTaskExecutor; +import org.springframework.security.concurrent.DelegatingSecurityContextCallable; +import org.springframework.security.concurrent.DelegatingSecurityContextRunnable; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.task.DelegatingSecurityContextAsyncTaskExecutor; + +/** + * An {@link SchedulingTaskExecutor} which wraps each {@link Runnable} in a {@link DelegatingSecurityContextRunnable} and each + * {@link Callable} in a {@link DelegatingSecurityContextCallable}. + * + * @author Rob Winch + * @since 3.2 + */ +public class DelegatingSecurityContextSchedulingTaskExecutor extends DelegatingSecurityContextAsyncTaskExecutor + implements SchedulingTaskExecutor { + + /** + * Creates a new {@link DelegatingSecurityContextSchedulingTaskExecutor} that uses the specified {@link SecurityContext}. + * + * @param delegateSchedulingTaskExecutor the {@link SchedulingTaskExecutor} to delegate to. Cannot be null. + * @param securityContext the {@link SecurityContext} to use for each {@link DelegatingSecurityContextRunnable} and + * {@link DelegatingSecurityContextCallable} + */ + public DelegatingSecurityContextSchedulingTaskExecutor(SchedulingTaskExecutor delegateSchedulingTaskExecutor, + SecurityContext securityContext) { + super(delegateSchedulingTaskExecutor, securityContext); + } + + /** + * Creates a new {@link DelegatingSecurityContextSchedulingTaskExecutor} that uses the current {@link SecurityContext}. + * + * @param delegateAsyncTaskExecutor the {@link AsyncTaskExecutor} to delegate to. Cannot be null. + */ + public DelegatingSecurityContextSchedulingTaskExecutor(SchedulingTaskExecutor delegateAsyncTaskExecutor) { + this(delegateAsyncTaskExecutor, null); + } + + public boolean prefersShortLivedTasks() { + return getDelegate().prefersShortLivedTasks(); + } + + private SchedulingTaskExecutor getDelegate() { + return (SchedulingTaskExecutor) getDelegateExecutor(); + } +} diff --git a/core/src/main/java/org/springframework/security/task/DelegatingSecurityContextAsyncTaskExecutor.java b/core/src/main/java/org/springframework/security/task/DelegatingSecurityContextAsyncTaskExecutor.java new file mode 100644 index 0000000000..8e08ec30df --- /dev/null +++ b/core/src/main/java/org/springframework/security/task/DelegatingSecurityContextAsyncTaskExecutor.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.task; + +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +import org.springframework.core.task.AsyncTaskExecutor; +import org.springframework.security.concurrent.DelegatingSecurityContextCallable; +import org.springframework.security.concurrent.DelegatingSecurityContextRunnable; +import org.springframework.security.core.context.SecurityContext; + +/** + * An {@link AsyncTaskExecutor} which wraps each {@link Runnable} in a {@link DelegatingSecurityContextRunnable} and each + * {@link Callable} in a {@link DelegatingSecurityContextCallable}. + * + * @author Rob Winch + * @since 3.2 + */ +public class DelegatingSecurityContextAsyncTaskExecutor extends DelegatingSecurityContextTaskExecutor implements + AsyncTaskExecutor { + + /** + * Creates a new {@link DelegatingSecurityContextAsyncTaskExecutor} that uses the specified {@link SecurityContext}. + * + * @param delegateAsyncTaskExecutor the {@link AsyncTaskExecutor} to delegate to. Cannot be null. + * @param securityContext the {@link SecurityContext} to use for each {@link DelegatingSecurityContextRunnable} and + * {@link DelegatingSecurityContextCallable} + */ + public DelegatingSecurityContextAsyncTaskExecutor(AsyncTaskExecutor delegateAsyncTaskExecutor, + SecurityContext securityContext) { + super(delegateAsyncTaskExecutor, securityContext); + } + + /** + * Creates a new {@link DelegatingSecurityContextAsyncTaskExecutor} that uses the current {@link SecurityContext}. + * + * @param delegateAsyncTaskExecutor the {@link AsyncTaskExecutor} to delegate to. Cannot be null. + */ + public DelegatingSecurityContextAsyncTaskExecutor(AsyncTaskExecutor delegateAsyncTaskExecutor) { + this(delegateAsyncTaskExecutor, null); + } + + public final void execute(Runnable task, long startTimeout) { + task = wrap(task); + getDelegate().execute(task, startTimeout); + } + + public final Future submit(Runnable task) { + task = wrap(task); + return getDelegate().submit(task); + } + + public final Future submit(Callable task) { + task = wrap(task); + return getDelegate().submit(task); + } + + private AsyncTaskExecutor getDelegate() { + return (AsyncTaskExecutor) getDelegateExecutor(); + } +} diff --git a/core/src/main/java/org/springframework/security/task/DelegatingSecurityContextTaskExecutor.java b/core/src/main/java/org/springframework/security/task/DelegatingSecurityContextTaskExecutor.java new file mode 100644 index 0000000000..bd6023ed52 --- /dev/null +++ b/core/src/main/java/org/springframework/security/task/DelegatingSecurityContextTaskExecutor.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.task; + +import org.springframework.core.task.TaskExecutor; +import org.springframework.security.concurrent.DelegatingSecurityContextExecutor; +import org.springframework.security.concurrent.DelegatingSecurityContextRunnable; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * An {@link TaskExecutor} which wraps each {@link Runnable} in a {@link DelegatingSecurityContextRunnable}. + * + * @author Rob Winch + * @since 3.2 + */ +public class DelegatingSecurityContextTaskExecutor extends DelegatingSecurityContextExecutor implements TaskExecutor { + /** + * Creates a new {@link DelegatingSecurityContextTaskExecutor} that uses the specified {@link SecurityContext}. + * + * @param delegateTaskExecutor the {@link TaskExecutor} to delegate to. Cannot be null. + * @param securityContext the {@link SecurityContext} to use for each {@link DelegatingSecurityContextRunnable} + */ + public DelegatingSecurityContextTaskExecutor(TaskExecutor delegateTaskExecutor, SecurityContext securityContext) { + super(delegateTaskExecutor, securityContext); + } + + /** + * Creates a new {@link DelegatingSecurityContextTaskExecutor} that uses the current {@link SecurityContext} from + * the {@link SecurityContextHolder}. + * + * @param delegateTaskExecutor the {@link TaskExecutor} to delegate to. Cannot be null. + */ + public DelegatingSecurityContextTaskExecutor(TaskExecutor delegate) { + this(delegate, null); + } +} \ No newline at end of file diff --git a/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextExecutorServiceTests.java b/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextExecutorServiceTests.java new file mode 100644 index 0000000000..f9d455b6ef --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextExecutorServiceTests.java @@ -0,0 +1,161 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; + + +/** + * Abstract class for testing {@link DelegatingSecurityContextExecutorService} which allows customization of + * how {@link DelegatingSecurityContextExecutorService} and its mocks are created. + * + * @author Rob Winch + * @since 3.2 + * @see CurrentDelegatingSecurityContextExecutorServiceTests + * @see ExplicitDelegatingSecurityContextExecutorServiceTests + */ +public abstract class AbstractDelegatingSecurityContextExecutorServiceTests extends AbstractDelegatingSecurityContextExecutorTests { + @Mock + private Future expectedFutureObject; + @Mock + private Object resultArg; + + protected DelegatingSecurityContextExecutorService executor; + + @Before + public final void setUpExecutorService() { + executor = create(); + } + + @Test(expected = IllegalArgumentException.class) + public void constructorNullDelegate() { + new DelegatingSecurityContextExecutorService(null); + } + + @Test + public void shutdown() { + executor.shutdown(); + verify(delegate).shutdown(); + } + + @Test + public void shutdownNow() { + List result = executor.shutdownNow(); + verify(delegate).shutdownNow(); + assertThat(result).isEqualTo(delegate.shutdownNow()).isNotNull(); + } + + @Test + public void isShutdown() { + boolean result = executor.isShutdown(); + verify(delegate).isShutdown(); + assertThat(result).isEqualTo(delegate.isShutdown()).isNotNull(); + } + + @Test + public void isTerminated() { + boolean result = executor.isTerminated(); + verify(delegate).isTerminated(); + assertThat(result).isEqualTo(delegate.isTerminated()).isNotNull(); + } + + @Test + public void awaitTermination() throws InterruptedException { + boolean result = executor.awaitTermination(1, TimeUnit.SECONDS); + verify(delegate).awaitTermination(1, TimeUnit.SECONDS); + assertThat(result).isEqualTo(delegate.awaitTermination(1, TimeUnit.SECONDS)).isNotNull(); + } + + @Test + public void submitCallable() throws Exception { + when(delegate.submit(wrappedCallable)).thenReturn(expectedFutureObject); + Future result = executor.submit(callable); + verify(delegate).submit(wrappedCallable); + assertThat(result).isEqualTo(expectedFutureObject); + } + + @Test + public void submitRunnableWithResult() throws Exception { + when(delegate.submit(wrappedRunnable, resultArg)).thenReturn(expectedFutureObject); + Future result = executor.submit(runnable, resultArg); + verify(delegate).submit(wrappedRunnable, resultArg); + assertThat(result).isEqualTo(expectedFutureObject); + } + + @Test + @SuppressWarnings("unchecked") + public void submitRunnable() throws Exception { + when((Future)delegate.submit(wrappedRunnable)).thenReturn(expectedFutureObject); + Future result = executor.submit(runnable); + verify(delegate).submit(wrappedRunnable); + assertThat(result).isEqualTo(expectedFutureObject); + } + + @Test + @SuppressWarnings("unchecked") + public void invokeAll() throws Exception { + List> exectedResult = Arrays.asList(expectedFutureObject); + List> wrappedCallables = Arrays.asList(wrappedCallable); + when(delegate.invokeAll(wrappedCallables)).thenReturn(exectedResult); + List> result = executor.invokeAll(Arrays.asList(callable)); + verify(delegate).invokeAll(wrappedCallables); + assertThat(result).isEqualTo(exectedResult); + } + + @Test + @SuppressWarnings("unchecked") + public void invokeAllTimeout() throws Exception { + List> exectedResult = Arrays.asList(expectedFutureObject); + List> wrappedCallables = Arrays.asList(wrappedCallable); + when(delegate.invokeAll(wrappedCallables, 1, TimeUnit.SECONDS)).thenReturn(exectedResult); + List> result = executor.invokeAll(Arrays.asList(callable), 1, TimeUnit.SECONDS); + verify(delegate).invokeAll(wrappedCallables, 1, TimeUnit.SECONDS); + assertThat(result).isEqualTo(exectedResult); + } + + @Test + @SuppressWarnings("unchecked") + public void invokeAny() throws Exception { + List> exectedResult = Arrays.asList(expectedFutureObject); + List> wrappedCallables = Arrays.asList(wrappedCallable); + when(delegate.invokeAny(wrappedCallables)).thenReturn(exectedResult); + Object result = executor.invokeAny(Arrays.asList(callable)); + verify(delegate).invokeAny(wrappedCallables); + assertThat(result).isEqualTo(exectedResult); + } + + @Test + @SuppressWarnings("unchecked") + public void invokeAnyTimeout() throws Exception { + List> exectedResult = Arrays.asList(expectedFutureObject); + List> wrappedCallables = Arrays.asList(wrappedCallable); + when(delegate.invokeAny(wrappedCallables, 1, TimeUnit.SECONDS)).thenReturn(exectedResult); + Object result = executor.invokeAny(Arrays.asList(callable), 1, TimeUnit.SECONDS); + verify(delegate).invokeAny(wrappedCallables, 1, TimeUnit.SECONDS); + assertThat(result).isEqualTo(exectedResult); + } + + protected abstract DelegatingSecurityContextExecutorService create(); +} \ No newline at end of file diff --git a/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextExecutorTests.java b/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextExecutorTests.java new file mode 100644 index 0000000000..14209baa7b --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextExecutorTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import static org.mockito.Mockito.verify; + +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; + +import org.junit.Test; +import org.mockito.Mock; + +/** + * Abstract class for testing {@link DelegatingSecurityContextExecutor} which allows customization of + * how {@link DelegatingSecurityContextExecutor} and its mocks are created. + * + * @author Rob Winch + * @since 3.2 + * @see CurrentDelegatingSecurityContextExecutorTests + * @see ExplicitDelegatingSecurityContextExecutorTests + */ +public abstract class AbstractDelegatingSecurityContextExecutorTests extends AbstractDelegatingSecurityContextTestSupport { + @Mock + protected ScheduledExecutorService delegate; + + private DelegatingSecurityContextExecutor executor; + + // --- constructor --- + + @Test(expected = IllegalArgumentException.class) + public void constructorNullDelegate() { + new DelegatingSecurityContextExecutor(null); + } + + // --- execute --- + + @Test + public void execute() { + executor = create(); + executor.execute(runnable); + verify(getExecutor()).execute(wrappedRunnable); + } + + protected Executor getExecutor() { + return delegate; + } + + protected abstract DelegatingSecurityContextExecutor create(); +} diff --git a/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextScheduledExecutorServiceTests.java b/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextScheduledExecutorServiceTests.java new file mode 100644 index 0000000000..9088a50753 --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextScheduledExecutorServiceTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; + +/** + * Abstract class for testing {@link DelegatingSecurityContextScheduledExecutorService} which allows customization of + * how {@link DelegatingSecurityContextScheduledExecutorService} and its mocks are created. + * + * @author Rob Winch + * @since 3.2 + * @see CurrentDelegatingSecurityContextScheduledExecutorServiceTests + * @see ExplicitDelegatingSecurityContextScheduledExecutorServiceTests + */ +public abstract class AbstractDelegatingSecurityContextScheduledExecutorServiceTests extends + AbstractDelegatingSecurityContextExecutorServiceTests { + @Mock + private ScheduledFuture expectedResult; + + private DelegatingSecurityContextScheduledExecutorService executor; + + @Before + public final void setUpExecutor() { + executor = create(); + } + + @Test + @SuppressWarnings("unchecked") + public void scheduleRunnable() { + when((ScheduledFuture)delegate.schedule(wrappedRunnable, 1, TimeUnit.SECONDS)).thenReturn(expectedResult); + ScheduledFuture result = executor.schedule(runnable, 1, TimeUnit.SECONDS); + assertThat(result).isEqualTo(expectedResult); + verify(delegate).schedule(wrappedRunnable, 1, TimeUnit.SECONDS); + } + + @Test + public void scheduleCallable() { + when((ScheduledFuture)delegate.schedule(wrappedCallable, 1, TimeUnit.SECONDS)).thenReturn(expectedResult); + ScheduledFuture result = executor.schedule(callable, 1, TimeUnit.SECONDS); + assertThat(result).isEqualTo(expectedResult); + verify(delegate).schedule(wrappedCallable, 1, TimeUnit.SECONDS); + } + + @Test + @SuppressWarnings("unchecked") + public void scheduleAtFixedRate() { + when((ScheduledFuture)delegate.scheduleAtFixedRate(wrappedRunnable, 1, 2, TimeUnit.SECONDS)).thenReturn(expectedResult); + ScheduledFuture result = executor.scheduleAtFixedRate(runnable, 1, 2, TimeUnit.SECONDS); + assertThat(result).isEqualTo(expectedResult); + verify(delegate).scheduleAtFixedRate(wrappedRunnable, 1, 2, TimeUnit.SECONDS); + } + + @Test + @SuppressWarnings("unchecked") + public void scheduleWithFixedDelay() { + when((ScheduledFuture)delegate.scheduleWithFixedDelay(wrappedRunnable, 1, 2, TimeUnit.SECONDS)).thenReturn(expectedResult); + ScheduledFuture result = executor.scheduleWithFixedDelay(runnable, 1, 2, TimeUnit.SECONDS); + assertThat(result).isEqualTo(expectedResult); + verify(delegate).scheduleWithFixedDelay(wrappedRunnable, 1, 2, TimeUnit.SECONDS); + } + + @Override + protected abstract DelegatingSecurityContextScheduledExecutorService create(); +} diff --git a/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextTestSupport.java b/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextTestSupport.java new file mode 100644 index 0000000000..f0bc8f597c --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/AbstractDelegatingSecurityContextTestSupport.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import static org.mockito.Matchers.eq; +import static org.powermock.api.mockito.PowerMockito.doReturn; +import static org.powermock.api.mockito.PowerMockito.spy; + +import java.util.concurrent.Callable; + +import org.junit.After; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * Abstract base class for testing classes that extend {@link AbstractDelegatingSecurityContextSupport} + * + * @author Rob Winch + * @since 3.2 + * + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({ DelegatingSecurityContextRunnable.class, DelegatingSecurityContextCallable.class }) +public abstract class AbstractDelegatingSecurityContextTestSupport { + @Mock + protected SecurityContext securityContext; + + @Mock + protected SecurityContext currentSecurityContext; + + @Captor + protected ArgumentCaptor securityContextCaptor; + + @Mock + protected Callable callable; + + @Mock + protected Callable wrappedCallable; + + @Mock + protected Runnable runnable; + + @Mock + protected Runnable wrappedRunnable; + + public final void explicitSecurityContextPowermockSetup() throws Exception { + spy(DelegatingSecurityContextCallable.class); + doReturn(wrappedCallable).when(DelegatingSecurityContextCallable.class, "create", eq(callable), + securityContextCaptor.capture()); + spy(DelegatingSecurityContextRunnable.class); + doReturn(wrappedRunnable).when(DelegatingSecurityContextRunnable.class, "create", eq(runnable), + securityContextCaptor.capture()); + } + + public final void currentSecurityContextPowermockSetup() throws Exception { + spy(DelegatingSecurityContextCallable.class); + doReturn(wrappedCallable).when(DelegatingSecurityContextCallable.class, "create", callable, null); + spy(DelegatingSecurityContextRunnable.class); + doReturn(wrappedRunnable).when(DelegatingSecurityContextRunnable.class, "create", runnable, null); + } + + @Before + public final void setContext() { + SecurityContextHolder.setContext(currentSecurityContext); + } + + @After + public final void clearContext() { + SecurityContextHolder.clearContext(); + } +} diff --git a/core/src/test/java/org/springframework/security/concurrent/CurrentDelegatingSecurityContextExecutorServiceTests.java b/core/src/test/java/org/springframework/security/concurrent/CurrentDelegatingSecurityContextExecutorServiceTests.java new file mode 100644 index 0000000000..1d6be8db07 --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/CurrentDelegatingSecurityContextExecutorServiceTests.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import org.junit.Before; + +/** + * Tests using the current {@link SecurityContext} on {@link DelegatingSecurityContextExecutorService} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class CurrentDelegatingSecurityContextExecutorServiceTests extends AbstractDelegatingSecurityContextExecutorServiceTests{ + + @Before + public void setUp() throws Exception { + super.currentSecurityContextPowermockSetup(); + } + + @Override + protected DelegatingSecurityContextExecutorService create() { + return new DelegatingSecurityContextExecutorService(delegate); + } +} \ No newline at end of file diff --git a/core/src/test/java/org/springframework/security/concurrent/CurrentDelegatingSecurityContextExecutorTests.java b/core/src/test/java/org/springframework/security/concurrent/CurrentDelegatingSecurityContextExecutorTests.java new file mode 100644 index 0000000000..1d6f5e3045 --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/CurrentDelegatingSecurityContextExecutorTests.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import org.junit.Before; + +/** + * Tests using the current {@link SecurityContext} on {@link DelegatingSecurityContextExecutor} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class CurrentDelegatingSecurityContextExecutorTests extends + AbstractDelegatingSecurityContextExecutorTests { + + @Before + public void setUp() throws Exception { + super.currentSecurityContextPowermockSetup(); + } + + @Override + protected DelegatingSecurityContextExecutor create() { + return new DelegatingSecurityContextExecutor(getExecutor()); + } +} diff --git a/core/src/test/java/org/springframework/security/concurrent/CurrentDelegatingSecurityContextScheduledExecutorServiceTests.java b/core/src/test/java/org/springframework/security/concurrent/CurrentDelegatingSecurityContextScheduledExecutorServiceTests.java new file mode 100644 index 0000000000..4126f94a8b --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/CurrentDelegatingSecurityContextScheduledExecutorServiceTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import org.junit.Before; + +/** + * Tests using the current {@link SecurityContext} on {@link DelegatingSecurityContextScheduledExecutorService} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class CurrentDelegatingSecurityContextScheduledExecutorServiceTests extends + AbstractDelegatingSecurityContextScheduledExecutorServiceTests { + + @Before + public void setUp() throws Exception { + this.currentSecurityContextPowermockSetup(); + } + + @Override + protected DelegatingSecurityContextScheduledExecutorService create() { + return new DelegatingSecurityContextScheduledExecutorService(delegate); + } + +} diff --git a/core/src/test/java/org/springframework/security/concurrent/DelegatingSecurityContextCallableTests.java b/core/src/test/java/org/springframework/security/concurrent/DelegatingSecurityContextCallableTests.java new file mode 100644 index 0000000000..e6d336c383 --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/DelegatingSecurityContextCallableTests.java @@ -0,0 +1,134 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.concurrent.Callable; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.internal.stubbing.answers.Returns; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * + * @author Rob Winch + * @since 3.2 + */ +@RunWith(MockitoJUnitRunner.class) +public class DelegatingSecurityContextCallableTests { + @Mock + private Callable delegate; + @Mock + private SecurityContext securityContext; + @Mock + private Object callableResult; + + private Callable callable; + + @Before + @SuppressWarnings("serial") + public void setUp() throws Exception { + when(delegate.call()).thenAnswer(new Returns(callableResult) { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + assertThat(SecurityContextHolder.getContext()).isEqualTo(securityContext); + return super.answer(invocation); + } + }); + } + + @After + public void tearDown() { + SecurityContextHolder.clearContext(); + } + + // --- constructor --- + + @Test(expected = IllegalArgumentException.class) + public void constructorNullDelegate() { + new DelegatingSecurityContextCallable(null); + } + + @Test(expected = IllegalArgumentException.class) + public void constructorNullDelegateNonNullSecurityContext() { + new DelegatingSecurityContextCallable(null, securityContext); + } + + @Test(expected = IllegalArgumentException.class) + public void constructorNullDelegateAndSecurityContext() { + new DelegatingSecurityContextCallable(null, null); + } + + @Test(expected = IllegalArgumentException.class) + public void constructorNullSecurityContext() { + new DelegatingSecurityContextCallable(delegate, null); + } + + // --- call --- + + @Test + public void call() throws Exception { + callable = new DelegatingSecurityContextCallable(delegate, securityContext); + assertWrapped(callable.call()); + } + + @Test + public void callDefaultSecurityContext() throws Exception { + SecurityContextHolder.setContext(securityContext); + callable = new DelegatingSecurityContextCallable(delegate); + SecurityContextHolder.clearContext(); // ensure callable is what sets up the SecurityContextHolder + assertWrapped(callable.call()); + } + + // --- create --- + + @Test(expected = IllegalArgumentException.class) + public void createNullDelegate() { + DelegatingSecurityContextCallable.create(null, securityContext); + } + + @Test(expected = IllegalArgumentException.class) + public void createNullDelegateAndSecurityContext() { + DelegatingSecurityContextRunnable.create(null, null); + } + + @Test + public void createNullSecurityContext() throws Exception { + SecurityContextHolder.setContext(securityContext); + callable = DelegatingSecurityContextCallable.create(delegate, null); + SecurityContextHolder.clearContext(); // ensure callable is what sets up the SecurityContextHolder + assertWrapped(callable.call()); + } + + @Test + public void create() throws Exception { + callable = DelegatingSecurityContextCallable.create(delegate, securityContext); + assertWrapped(callable.call()); + } + + private void assertWrapped(Object actualResult) throws Exception { + assertThat(actualResult).isEqualTo(callableResult); + verify(delegate).call(); + assertThat(SecurityContextHolder.getContext()).isEqualTo(SecurityContextHolder.createEmptyContext()); + } +} \ No newline at end of file diff --git a/core/src/test/java/org/springframework/security/concurrent/DelegatingSecurityContextRunnableTests.java b/core/src/test/java/org/springframework/security/concurrent/DelegatingSecurityContextRunnableTests.java new file mode 100644 index 0000000000..0eb31c94d4 --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/DelegatingSecurityContextRunnableTests.java @@ -0,0 +1,134 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * + * @author Rob Winch + * @since 3.2 + */ +@RunWith(MockitoJUnitRunner.class) +public class DelegatingSecurityContextRunnableTests { + @Mock + private Runnable delegate; + @Mock + private SecurityContext securityContext; + @Mock + private Object callableResult; + + private Runnable runnable; + + @Before + public void setUp() throws Exception { + doAnswer(new Answer() { + public Object answer(InvocationOnMock invocation) throws Throwable { + assertThat(SecurityContextHolder.getContext()).isEqualTo(securityContext); + return null; + } + }) + .when(delegate).run(); + } + + @After + public void tearDown() { + SecurityContextHolder.clearContext(); + } + + // --- constructor --- + + @Test(expected = IllegalArgumentException.class) + public void constructorNullDelegate() { + new DelegatingSecurityContextRunnable(null); + } + + @Test(expected = IllegalArgumentException.class) + public void constructorNullDelegateNonNullSecurityContext() { + new DelegatingSecurityContextRunnable(null, securityContext); + } + + @Test(expected = IllegalArgumentException.class) + public void constructorNullDelegateAndSecurityContext() { + new DelegatingSecurityContextRunnable(null, null); + } + + @Test(expected = IllegalArgumentException.class) + public void constructorNullSecurityContext() { + new DelegatingSecurityContextRunnable(delegate, null); + } + + // --- run --- + + @Test + public void call() throws Exception { + runnable = new DelegatingSecurityContextRunnable(delegate, securityContext); + runnable.run(); + assertWrapped(); + } + + @Test + public void callDefaultSecurityContext() throws Exception { + SecurityContextHolder.setContext(securityContext); + runnable = new DelegatingSecurityContextRunnable(delegate); + SecurityContextHolder.clearContext(); // ensure runnable is what sets up the SecurityContextHolder + runnable.run(); + assertWrapped(); + } + + // --- create --- + + @Test(expected = IllegalArgumentException.class) + public void createNullDelegate() { + DelegatingSecurityContextRunnable.create(null, securityContext); + } + + @Test(expected = IllegalArgumentException.class) + public void createNullDelegateAndSecurityContext() { + DelegatingSecurityContextRunnable.create(null, null); + } + + @Test + public void createNullSecurityContext() { + SecurityContextHolder.setContext(securityContext); + runnable = DelegatingSecurityContextRunnable.create(delegate, null); + SecurityContextHolder.clearContext(); // ensure runnable is what sets up the SecurityContextHolder + runnable.run(); + assertWrapped(); + } + + @Test + public void create() { + runnable = DelegatingSecurityContextRunnable.create(delegate, securityContext); + runnable.run(); + assertWrapped(); + } + + private void assertWrapped() { + verify(delegate).run(); + assertThat(SecurityContextHolder.getContext()).isEqualTo(SecurityContextHolder.createEmptyContext()); + } +} \ No newline at end of file diff --git a/core/src/test/java/org/springframework/security/concurrent/DelegatingSecurityContextSupportTests.java b/core/src/test/java/org/springframework/security/concurrent/DelegatingSecurityContextSupportTests.java new file mode 100644 index 0000000000..a36ce7a8a3 --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/DelegatingSecurityContextSupportTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import static org.fest.assertions.Assertions.assertThat; + +import org.junit.Test; +import org.springframework.security.core.context.SecurityContext; + +/** + * + * @author Rob Winch + * @since 3.2 + * + */ +public class DelegatingSecurityContextSupportTests extends AbstractDelegatingSecurityContextTestSupport { + private AbstractDelegatingSecurityContextSupport support; + + @Test + public void wrapCallable() throws Exception { + explicitSecurityContextPowermockSetup(); + support = new ConcreteDelegatingSecurityContextSupport(securityContext); + assertThat(support.wrap(callable)).isSameAs(wrappedCallable); + assertThat(securityContextCaptor.getValue()).isSameAs(securityContext); + } + + @Test + public void wrapCallableNullSecurityContext() throws Exception { + currentSecurityContextPowermockSetup(); + support = new ConcreteDelegatingSecurityContextSupport(null); + assertThat(support.wrap(callable)).isSameAs(wrappedCallable); + } + + @Test + public void wrapRunnable() throws Exception { + explicitSecurityContextPowermockSetup(); + support = new ConcreteDelegatingSecurityContextSupport(securityContext); + assertThat(support.wrap(runnable)).isSameAs(wrappedRunnable); + assertThat(securityContextCaptor.getValue()).isSameAs(securityContext); + } + + @Test + public void wrapRunnableNullSecurityContext() throws Exception { + currentSecurityContextPowermockSetup(); + support = new ConcreteDelegatingSecurityContextSupport(null); + assertThat(support.wrap(runnable)).isSameAs(wrappedRunnable); + } + + private static class ConcreteDelegatingSecurityContextSupport extends AbstractDelegatingSecurityContextSupport { + public ConcreteDelegatingSecurityContextSupport(SecurityContext securityContext) { + super(securityContext); + } + } +} \ No newline at end of file diff --git a/core/src/test/java/org/springframework/security/concurrent/ExplicitDelegatingSecurityContextExecutorServiceTests.java b/core/src/test/java/org/springframework/security/concurrent/ExplicitDelegatingSecurityContextExecutorServiceTests.java new file mode 100644 index 0000000000..1e536e63f8 --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/ExplicitDelegatingSecurityContextExecutorServiceTests.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import org.junit.Before; + +/** + * Tests Explicitly specifying the {@link SecurityContext} on {@link DelegatingSecurityContextExecutorService} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class ExplicitDelegatingSecurityContextExecutorServiceTests extends AbstractDelegatingSecurityContextExecutorServiceTests{ + + @Before + public void setUp() throws Exception { + super.explicitSecurityContextPowermockSetup(); + } + + @Override + protected DelegatingSecurityContextExecutorService create() { + return new DelegatingSecurityContextExecutorService(delegate,securityContext); + } +} \ No newline at end of file diff --git a/core/src/test/java/org/springframework/security/concurrent/ExplicitDelegatingSecurityContextExecutorTests.java b/core/src/test/java/org/springframework/security/concurrent/ExplicitDelegatingSecurityContextExecutorTests.java new file mode 100644 index 0000000000..ba3a6891a9 --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/ExplicitDelegatingSecurityContextExecutorTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import org.junit.Before; +import org.springframework.security.core.context.SecurityContext; + +/** + * Tests Explicitly specifying the {@link SecurityContext} on {@link DelegatingSecurityContextExecutor} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class ExplicitDelegatingSecurityContextExecutorTests extends + AbstractDelegatingSecurityContextExecutorTests { + + @Before + public void setUp() throws Exception { + super.explicitSecurityContextPowermockSetup(); + } + + @Override + protected DelegatingSecurityContextExecutor create() { + return new DelegatingSecurityContextExecutor(getExecutor(), securityContext); + } +} diff --git a/core/src/test/java/org/springframework/security/concurrent/ExplicitDelegatingSecurityContextScheduledExecutorServiceTests.java b/core/src/test/java/org/springframework/security/concurrent/ExplicitDelegatingSecurityContextScheduledExecutorServiceTests.java new file mode 100644 index 0000000000..c4cfff8edf --- /dev/null +++ b/core/src/test/java/org/springframework/security/concurrent/ExplicitDelegatingSecurityContextScheduledExecutorServiceTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.concurrent; + +import org.junit.Before; +import org.springframework.security.core.context.SecurityContext; + +/** + * Tests Explicitly specifying the {@link SecurityContext} on {@link DelegatingSecurityContextScheduledExecutorService} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class ExplicitDelegatingSecurityContextScheduledExecutorServiceTests extends + AbstractDelegatingSecurityContextScheduledExecutorServiceTests { + + @Before + public void setUp() throws Exception { + this.explicitSecurityContextPowermockSetup(); + } + + @Override + protected DelegatingSecurityContextScheduledExecutorService create() { + return new DelegatingSecurityContextScheduledExecutorService(delegate, securityContext); + } +} \ No newline at end of file diff --git a/core/src/test/java/org/springframework/security/scheduling/AbstractSecurityContextSchedulingTaskExecutorTests.java b/core/src/test/java/org/springframework/security/scheduling/AbstractSecurityContextSchedulingTaskExecutorTests.java new file mode 100644 index 0000000000..5e232ca586 --- /dev/null +++ b/core/src/test/java/org/springframework/security/scheduling/AbstractSecurityContextSchedulingTaskExecutorTests.java @@ -0,0 +1,39 @@ +package org.springframework.security.scheduling; + +import static org.mockito.Mockito.verify; + +import org.junit.Test; +import org.mockito.Mock; +import org.springframework.scheduling.SchedulingTaskExecutor; +import org.springframework.security.task.AbstractDelegatingSecurityContextAsyncTaskExecutorTests; + +/** + * Abstract class for testing {@link DelegatingSecurityContextSchedulingTaskExecutor} which allows customization of + * how {@link DelegatingSecurityContextSchedulingTaskExecutor} and its mocks are created. + * + * @author Rob Winch + * @since 3.2 + * @see CurrentSecurityContextSchedulingTaskExecutorTests + * @see ExplicitSecurityContextSchedulingTaskExecutorTests + */ +public abstract class AbstractSecurityContextSchedulingTaskExecutorTests extends + AbstractDelegatingSecurityContextAsyncTaskExecutorTests { + + @Mock + protected SchedulingTaskExecutor taskExecutorDelegate; + + private DelegatingSecurityContextSchedulingTaskExecutor executor; + + @Test + public void prefersShortLivedTasks() { + executor = create(); + executor.prefersShortLivedTasks(); + verify(taskExecutorDelegate).prefersShortLivedTasks(); + } + + protected SchedulingTaskExecutor getExecutor() { + return taskExecutorDelegate; + } + + protected abstract DelegatingSecurityContextSchedulingTaskExecutor create(); +} diff --git a/core/src/test/java/org/springframework/security/scheduling/CurrentSecurityContextSchedulingTaskExecutorTests.java b/core/src/test/java/org/springframework/security/scheduling/CurrentSecurityContextSchedulingTaskExecutorTests.java new file mode 100644 index 0000000000..5a908464b0 --- /dev/null +++ b/core/src/test/java/org/springframework/security/scheduling/CurrentSecurityContextSchedulingTaskExecutorTests.java @@ -0,0 +1,23 @@ +package org.springframework.security.scheduling; + +import org.junit.Before; +import org.springframework.security.core.context.SecurityContext; + +/** + * Tests using the current {@link SecurityContext} on {@link DelegatingSecurityContextSchedulingTaskExecutor} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class CurrentSecurityContextSchedulingTaskExecutorTests extends AbstractSecurityContextSchedulingTaskExecutorTests { + + @Before + public void setUp() throws Exception { + currentSecurityContextPowermockSetup(); + } + + protected DelegatingSecurityContextSchedulingTaskExecutor create() { + return new DelegatingSecurityContextSchedulingTaskExecutor(taskExecutorDelegate); + } +} diff --git a/core/src/test/java/org/springframework/security/scheduling/ExplicitSecurityContextSchedulingTaskExecutorTests.java b/core/src/test/java/org/springframework/security/scheduling/ExplicitSecurityContextSchedulingTaskExecutorTests.java new file mode 100644 index 0000000000..a9b3b5ca15 --- /dev/null +++ b/core/src/test/java/org/springframework/security/scheduling/ExplicitSecurityContextSchedulingTaskExecutorTests.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.scheduling; + +import org.junit.Before; +import org.springframework.security.core.context.SecurityContext; + +/** + * Tests Explicitly specifying the {@link SecurityContext} on {@link DelegatingSecurityContextSchedulingTaskExecutor} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class ExplicitSecurityContextSchedulingTaskExecutorTests extends AbstractSecurityContextSchedulingTaskExecutorTests { + + @Before + public void setUp() throws Exception { + explicitSecurityContextPowermockSetup(); + } + + protected DelegatingSecurityContextSchedulingTaskExecutor create() { + return new DelegatingSecurityContextSchedulingTaskExecutor(taskExecutorDelegate, securityContext); + } +} diff --git a/core/src/test/java/org/springframework/security/task/AbstractDelegatingSecurityContextAsyncTaskExecutorTests.java b/core/src/test/java/org/springframework/security/task/AbstractDelegatingSecurityContextAsyncTaskExecutorTests.java new file mode 100644 index 0000000000..a5c2cca828 --- /dev/null +++ b/core/src/test/java/org/springframework/security/task/AbstractDelegatingSecurityContextAsyncTaskExecutorTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.task; + +import static org.mockito.Mockito.verify; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.springframework.core.task.AsyncTaskExecutor; +import org.springframework.security.concurrent.AbstractDelegatingSecurityContextExecutorTests; + +/** + * Abstract class for testing {@link DelegatingSecurityContextAsyncTaskExecutor} which allows customization of + * how {@link DelegatingSecurityContextAsyncTaskExecutor} and its mocks are created. + * + * @author Rob Winch + * @since 3.2 + * @see CurrentDelegatingSecurityContextAsyncTaskExecutorTests + * @see ExplicitDelegatingSecurityContextAsyncTaskExecutorTests + */ +public abstract class AbstractDelegatingSecurityContextAsyncTaskExecutorTests extends AbstractDelegatingSecurityContextExecutorTests { + @Mock + protected AsyncTaskExecutor taskExecutorDelegate; + + private DelegatingSecurityContextAsyncTaskExecutor executor; + + @Before + public final void setUpExecutor() { + executor = create(); + } + + @Test + public void executeStartTimeout() { + executor.execute(runnable, 1); + verify(getExecutor()).execute(wrappedRunnable, 1); + } + + @Test + public void submit() { + executor.submit(runnable); + verify(getExecutor()).submit(wrappedRunnable); + } + + @Test + public void submitCallable() { + executor.submit(callable); + verify(getExecutor()).submit(wrappedCallable); + } + + protected AsyncTaskExecutor getExecutor() { + return taskExecutorDelegate; + } + + protected abstract DelegatingSecurityContextAsyncTaskExecutor create(); +} diff --git a/core/src/test/java/org/springframework/security/task/CurrentDelegatingSecurityContextAsyncTaskExecutorTests.java b/core/src/test/java/org/springframework/security/task/CurrentDelegatingSecurityContextAsyncTaskExecutorTests.java new file mode 100644 index 0000000000..c98192f8c4 --- /dev/null +++ b/core/src/test/java/org/springframework/security/task/CurrentDelegatingSecurityContextAsyncTaskExecutorTests.java @@ -0,0 +1,26 @@ +package org.springframework.security.task; + +import org.junit.Before; + + +/** + * Tests using the current {@link SecurityContext} on {@link DelegatingSecurityContextAsyncTaskExecutor} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class CurrentDelegatingSecurityContextAsyncTaskExecutorTests extends + AbstractDelegatingSecurityContextAsyncTaskExecutorTests { + + @Before + public void setUp() throws Exception { + currentSecurityContextPowermockSetup(); + } + + @Override + protected DelegatingSecurityContextAsyncTaskExecutor create() { + return new DelegatingSecurityContextAsyncTaskExecutor(taskExecutorDelegate); + } + +} diff --git a/core/src/test/java/org/springframework/security/task/CurrentDelegatingSecurityContextTaskExecutorTests.java b/core/src/test/java/org/springframework/security/task/CurrentDelegatingSecurityContextTaskExecutorTests.java new file mode 100644 index 0000000000..4683f79226 --- /dev/null +++ b/core/src/test/java/org/springframework/security/task/CurrentDelegatingSecurityContextTaskExecutorTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.task; + +import java.util.concurrent.Executor; + +import org.junit.Before; +import org.mockito.Mock; +import org.springframework.core.task.TaskExecutor; +import org.springframework.security.concurrent.DelegatingSecurityContextExecutor; +import org.springframework.security.concurrent.AbstractDelegatingSecurityContextExecutorTests; + + +/** + * Tests using the current {@link SecurityContext} on {@link DelegatingSecurityContextExecutor} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class CurrentDelegatingSecurityContextTaskExecutorTests extends AbstractDelegatingSecurityContextExecutorTests { + @Mock + private TaskExecutor taskExecutorDelegate; + + @Before + public void setUp() throws Exception { + currentSecurityContextPowermockSetup(); + } + + protected Executor getExecutor() { + return taskExecutorDelegate; + } + + protected DelegatingSecurityContextExecutor create() { + return new DelegatingSecurityContextTaskExecutor(taskExecutorDelegate); + } +} diff --git a/core/src/test/java/org/springframework/security/task/ExplicitDelegatingSecurityContextAsyncTaskExecutorTests.java b/core/src/test/java/org/springframework/security/task/ExplicitDelegatingSecurityContextAsyncTaskExecutorTests.java new file mode 100644 index 0000000000..47fbd88396 --- /dev/null +++ b/core/src/test/java/org/springframework/security/task/ExplicitDelegatingSecurityContextAsyncTaskExecutorTests.java @@ -0,0 +1,26 @@ +package org.springframework.security.task; + +import org.junit.Before; + + +/** + * Tests using an explicit {@link SecurityContext} on {@link DelegatingSecurityContextAsyncTaskExecutor} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class ExplicitDelegatingSecurityContextAsyncTaskExecutorTests extends + AbstractDelegatingSecurityContextAsyncTaskExecutorTests { + + @Before + public void setUp() throws Exception { + explicitSecurityContextPowermockSetup(); + } + + @Override + protected DelegatingSecurityContextAsyncTaskExecutor create() { + return new DelegatingSecurityContextAsyncTaskExecutor(taskExecutorDelegate, securityContext); + } + +} diff --git a/core/src/test/java/org/springframework/security/task/ExplicitDelegatingSecurityContextTaskExecutorTests.java b/core/src/test/java/org/springframework/security/task/ExplicitDelegatingSecurityContextTaskExecutorTests.java new file mode 100644 index 0000000000..d60347c3c4 --- /dev/null +++ b/core/src/test/java/org/springframework/security/task/ExplicitDelegatingSecurityContextTaskExecutorTests.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.springframework.security.task; + +import java.util.concurrent.Executor; + +import org.junit.Before; +import org.mockito.Mock; +import org.springframework.core.task.TaskExecutor; +import org.springframework.security.concurrent.DelegatingSecurityContextExecutor; +import org.springframework.security.concurrent.AbstractDelegatingSecurityContextExecutorTests; + + +/** + * Tests using the an explicit {@link SecurityContext} on {@link DelegatingSecurityContextExecutor} + * + * @author Rob Winch + * @since 3.2 + * + */ +public class ExplicitDelegatingSecurityContextTaskExecutorTests extends AbstractDelegatingSecurityContextExecutorTests { + @Mock + private TaskExecutor taskExecutorDelegate; + + + @Before + public void setUp() throws Exception { + explicitSecurityContextPowermockSetup(); + } + + protected Executor getExecutor() { + return taskExecutorDelegate; + } + + protected DelegatingSecurityContextExecutor create() { + return new DelegatingSecurityContextTaskExecutor(taskExecutorDelegate, securityContext); + } +}