Class AuthorizedTasks

java.lang.Object
org.gcube.common.security.AuthorizedTasks

public class AuthorizedTasks extends Object
Utility class for executing code within a specific Secret (authorization context).

It manages the SecretManagerProvider thread-local: it sets the required secret before the task runs and always restores the previous one in a finally block, preventing secrets from leaking across scopes.

Use-case matrix

Use-case matrix
ThreadSecretMethodNotes
Same thread Same (current) — no switch needed none — just invoke the method directly No AuthorizedTasks involvement needed.
Same thread Different (explicit) executeSafely(task, secret) Inline context switch. Previous secret is always restored in finally.
Different thread / pool Same as calling thread (current) bind(task) → then new Thread(...).start() or executor.submit(...) Captures the current secret at bind-time and injects it when the task runs.
Different thread / pool Different (explicit) bind(task, secret) → then new Thread(...).start() or executor.submit(...) Binds an explicit secret to the task. Useful when the child thread must run under a different identity than the calling thread (e.g. a service sending a social notification with its own catalogue credentials while the HTTP thread is running under the end-user token).
Different thread — fire-and-forget Different (explicit) runAsync(task, secret) Convenience shortcut: creates a new Thread, binds the explicit secret, starts it, and returns the Thread in case the caller needs to join() it. Equivalent to new Thread(bind(task, secret)).start().

Examples

Case 1 — same thread, inline context switch (different secret)


 Secret secret = ContextProvider.get().container().authorizationProvider()
         .getSecretForContext(targetContext);
 AuthorizedTasks.executeSafely(() -> {
     // runs on the current thread with 'secret' active
 }, secret);
 

Case 2 — different thread, propagate the current secret


 // bind() captures SecretManagerProvider.get() now (calling thread)
 new Thread(AuthorizedTasks.bind(() -> {
     // runs on the new thread with the calling thread's secret
 })).start();
 

Case 3 — different thread, explicit (different) secret (bind)


 Secret catalogueSecret = Utils.getCatalogueSecret();
 new Thread(AuthorizedTasks.bind(() -> {
     // runs on the new thread with catalogueSecret active, not the caller's secret
 }, catalogueSecret)).start();
 

Case 4 — different thread, fire-and-forget with explicit secret (runAsync)


 Secret catalogueSecret = Utils.getCatalogueSecret();
 AuthorizedTasks.runAsync(socialPost, catalogueSecret);
 

MDC and request ID propagation

bind() — in both variants — propagates only the Secret. When the task runs on a different thread, the SLF4J MDC and any InheritableThreadLocal-based request-ID holder are not automatically available because:

  • Logback's LogbackMDCAdapter (v1.2.x+) uses a plain ThreadLocal — MDC is never inherited by child threads.
  • An InheritableThreadLocal request-ID is inherited by new Thread(...), but not by pooled threads (created once at pool initialisation, not at task-submission time).
MDC propagation will be addressed organically when a dedicated RequestIdProvider and ContextPropagatingExecutorService are introduced.
  • Constructor Details

    • AuthorizedTasks

      public AuthorizedTasks()
  • Method Details

    • bind

      public static <V> Callable<V> bind(Callable<V> task)
      Binds a Callable task to the current authorization context. This method captures the current secret from SecretManagerProvider and returns a new Callable that will automatically set that secret before executing the original task and reset it afterward. This is useful for delegating tasks to a different thread or for asynchronous execution while maintaining the correct authorization context.
      Type Parameters:
      V - The return type of the task.
      Parameters:
      task - The original Callable task to be bound.
      Returns:
      An equivalent Callable task bound to the current authorization context.
    • bind

      public static Runnable bind(Runnable task)
      Binds a Runnable task to the current authorization context. Similar to the bind(Callable) method, this captures the current secret and returns a new Runnable that will set the secret before execution and reset it upon completion.
      Parameters:
      task - The original Runnable task to be bound.
      Returns:
      An equivalent Runnable task bound to the current authorization context.
    • bind

      public static <V> Callable<V> bind(Callable<V> task, Secret secret)
      Binds a Callable task to an explicit Secret for deferred execution on a different thread.

      Use this variant when the child thread must run under a different identity than the calling thread — for example when a service needs to perform an operation using its own service credentials while the current thread is running under an end-user token.

      The returned Callable is not automatically submitted anywhere; the caller is responsible for handing it to a new Thread(...), an ExecutorService, or similar.

      Type Parameters:
      V - The return type of the task.
      Parameters:
      task - The original Callable task to be bound.
      secret - The explicit Secret to activate when the task runs.
      Returns:
      An equivalent Callable bound to the given secret.
    • bind

      public static Runnable bind(Runnable task, Secret secret)
      Binds a Runnable task to an explicit Secret for deferred execution on a different thread.

      Use this variant when the child thread must run under a different identity than the calling thread — for example when a service needs to perform an operation using its own service credentials while the current thread is running under an end-user token.

      The returned Runnable is not automatically submitted anywhere; the caller is responsible for handing it to a new Thread(...), an ExecutorService, or similar.

      Example — social post sent with the catalogue's own credentials:

      
       Secret catalogueSecret = Utils.getCatalogueSecret();
       new Thread(AuthorizedTasks.bind(socialPost, catalogueSecret)).start();
       
      Parameters:
      task - The original Runnable task to be bound.
      secret - The explicit Secret to activate when the task runs.
      Returns:
      An equivalent Runnable bound to the given secret.
    • runAsync

      public static Thread runAsync(Runnable task, Secret secret)
      Creates a new Thread, binds the given Runnable to the provided Secret, starts it immediately, and returns the thread.

      This is a convenience shortcut for the common fire-and-forget pattern:

      
       new Thread(AuthorizedTasks.bind(task, secret)).start();
       

      The returned Thread can be used to join() if the caller needs to wait for completion.

      Parameters:
      task - The Runnable task to execute asynchronously.
      secret - The explicit Secret to activate when the task runs.
      Returns:
      The started Thread.
    • executeSafely

      public static void executeSafely(Runnable task, Secret secret)
      Executes a Runnable task immediately within a specific secret context. This method temporarily sets a specified secret, executes the task, and then restores the previous secret, guaranteeing that the original secret is always put back in place, even if the task throws an exception.
      Parameters:
      task - The Runnable task to be executed.
      secret - The Secret that must be used during the execution of the task.
    • executeSafely

      public static <T> T executeSafely(Callable<T> task, Secret secret) throws Throwable
      Executes a Callable task immediately within a specific secret context. Similar to the executeSafely(Runnable) method, this sets a specified secret, executes the Callable task, and restores the previous secret. It also handles propagating any exceptions thrown by the task.
      Type Parameters:
      T - The return type of the task.
      Parameters:
      task - The Callable task to be executed.
      secret - The Secret that must be used during the execution of the task.
      Returns:
      The result of the Callable task.
      Throws:
      Throwable - if the task execution throws an exception.