Write and Publish a Tutorial!
Do you have good notes or papers written by you and seeking for a
platform to publish? We provide the platform to publish your tutorials
in your name. If you wish to publish your tutorial in your name to
help the readers, Please contact us by sending an email to
publish@tools4testing.com or publish@java4coding.com The main way that
others learn about your work is through your published tutorials. If
you don’t publish, it will be as if you never did the work. Your notes
can help the readers only when you share it.
Delegating SecurityContext to self-managed threads in Spring Security
In coding, sometimes we take charge and start threads without the framework's knowledge, known as "self-managed threads." But what about the security context in these cases?
Spring Security provides handy tools to seamlessly transfer the security context to these new threads. When the usual methods fall short, DelegatingSecurityContextRunnable and DelegatingSecurityContextCallable step in. These extend Runnable and Callable, respectively, making sure the security context travels safely to new threads.
Spring Security also offers specialized executors like DelegatingSecurityContextExecutorService, ensuring security context transfer in thread pools. Need to schedule tasks? DelegatingSecurityContextScheduledExecutorService has your back.
In a nutshell, these tools ensure that your self-managed threads navigate securely through the security context, maintaining integrity along the way.
Here's a glance at Spring Security's stalwart defenders in the realm of thread safety:
DelegatingSecurityContextExecutor: Enhances the Executor interface, ensuring security context propagation within thread pools.
DelegatingSecurityContextExecutorService: Elevates the ExecutorService interface, shielding thread pools with secure context propagation.
DelegatingSecurityContextScheduledExecutorService: Bolsters the ScheduledExecutorService interface, enabling scheduled task execution with fortified security context propagation.
DelegatingSecurityContextRunnable: A sentinel of Runnable tasks, ensuring security context propagation without return values.
DelegatingSecurityContextCallable: The guardian of Callable tasks, guaranteeing security context propagation with eventual return values.
package com.java4coding;
import lombok.extern.slf4j.Slf4j; import org.springframework.security.concurrent.DelegatingSecurityContextCallable; import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService; import org.springframework.security.concurrent.DelegatingSecurityContextRunnable; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
@RestController @Slf4j public class DemoController {
/* You can use DelegatingSecurityContextRunnable following the execution of the task when there is no value expected. */ @GetMapping(value = "/hello") public String sayHello() throws ExecutionException, InterruptedException { Runnable task = () -> { SecurityContext context = SecurityContextHolder.getContext(); log.info(context.getAuthentication().getName()); }; ExecutorService executorService = Executors.newCachedThreadPool(); try { var contextTask = new DelegatingSecurityContextRunnable(task); executorService.submit(contextTask); return "Hi, Task submitted to run asynchronously - no return value "; } finally { executorService.shutdown(); } }
/* You can use DelegatingSecurityContextCallable following the execution of the task when return value expected. */ @GetMapping(value = "/hi") public String sayHi() throws ExecutionException, InterruptedException { Callable<String> task = () -> { SecurityContext context = SecurityContextHolder.getContext(); return context.getAuthentication().getName(); }; ExecutorService executorService = Executors.newCachedThreadPool(); try { var contextTask = new DelegatingSecurityContextCallable<>(task); return "Hi, " + executorService.submit(contextTask).get() + "!"; } finally { executorService.shutdown(); } }
/* DelegatingSecurityContextExecutorService decorates an ExecutorService and propagates the security context details to the next thread before submitting the task. */ @GetMapping(value = "/hurray") public String sayHurray() throws ExecutionException, InterruptedException { Callable<String> task = () -> { SecurityContext context = SecurityContextHolder.getContext(); return context.getAuthentication().getName(); }; ExecutorService executorService = Executors.newCachedThreadPool(); executorService = new DelegatingSecurityContextExecutorService(executorService); try { return "Hurray, " + executorService.submit(task).get() + "!"; } finally { executorService.shutdown(); } } } |