From 1dc67ea43972f7cf38cc717189f1ab715394283a Mon Sep 17 00:00:00 2001 From: Sh1bari Date: Thu, 2 Jul 2026 02:03:33 +0300 Subject: [PATCH 1/2] feat: expose programmatic auth wiring --- .../sdk/server/auth/AuthenticatedUser.java | 20 +++++++++++++- .../sdk/server/auth/UserAttributes.java | 12 +++++++++ .../AuthorizationRequestHandlerDecorator.java | 21 ++++++++++----- .../sdk/server/tasks/InMemoryTaskStore.java | 26 +++++++++++++------ 4 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 server-common/src/main/java/org/a2aproject/sdk/server/auth/UserAttributes.java diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/auth/AuthenticatedUser.java b/server-common/src/main/java/org/a2aproject/sdk/server/auth/AuthenticatedUser.java index 255b2020a..03a81d53f 100644 --- a/server-common/src/main/java/org/a2aproject/sdk/server/auth/AuthenticatedUser.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/auth/AuthenticatedUser.java @@ -1,10 +1,23 @@ package org.a2aproject.sdk.server.auth; +import org.jspecify.annotations.Nullable; import org.a2aproject.sdk.util.Assert; -public record AuthenticatedUser(String username) implements User { +import java.util.Map; + +public record AuthenticatedUser( + String username, + Map attributes +) implements User { + + public AuthenticatedUser(String username) { + this(username, Map.of()); + } + public AuthenticatedUser { Assert.checkNotNullParam("username", username); + Assert.checkNotNullParam("attributes", attributes); + attributes = Map.copyOf(attributes); } @Override @@ -16,4 +29,9 @@ public boolean isAuthenticated() { public String getUsername() { return username; } + + @Override + public @Nullable Object getAttribute(String key) { + return attributes.get(key); + } } diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/auth/UserAttributes.java b/server-common/src/main/java/org/a2aproject/sdk/server/auth/UserAttributes.java new file mode 100644 index 000000000..5d63e2211 --- /dev/null +++ b/server-common/src/main/java/org/a2aproject/sdk/server/auth/UserAttributes.java @@ -0,0 +1,12 @@ +package org.a2aproject.sdk.server.auth; + +public final class UserAttributes { + + public static final String AUTHORITIES = "authorities"; + public static final String SCOPES = "scopes"; + public static final String TENANT_ID = "tenantId"; + public static final String CLIENT_ID = "clientId"; + + private UserAttributes() { + } +} diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/AuthorizationRequestHandlerDecorator.java b/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/AuthorizationRequestHandlerDecorator.java index b570410f2..366b55d50 100644 --- a/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/AuthorizationRequestHandlerDecorator.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/AuthorizationRequestHandlerDecorator.java @@ -1,8 +1,5 @@ package org.a2aproject.sdk.server.requesthandlers; -import java.util.concurrent.Flow; -import java.util.concurrent.atomic.AtomicBoolean; - import jakarta.annotation.PostConstruct; import jakarta.annotation.Priority; import jakarta.decorator.Decorator; @@ -10,10 +7,10 @@ import jakarta.enterprise.inject.Any; import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; - import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; import org.a2aproject.sdk.server.ServerCallContext; import org.a2aproject.sdk.server.auth.TaskAuthorizationProvider; +import org.a2aproject.sdk.server.auth.TaskOperation; import org.a2aproject.sdk.spec.A2AError; import org.a2aproject.sdk.spec.CancelTaskParams; import org.a2aproject.sdk.spec.DeleteTaskPushNotificationConfigParams; @@ -32,9 +29,11 @@ import org.a2aproject.sdk.spec.TaskPushNotificationConfig; import org.a2aproject.sdk.spec.TaskQueryParams; import org.a2aproject.sdk.spec.TaskStatusUpdateEvent; -import org.a2aproject.sdk.server.auth.TaskOperation; import org.jspecify.annotations.Nullable; +import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicBoolean; + @Decorator @Priority(50) public class AuthorizationRequestHandlerDecorator implements RequestHandler { @@ -53,7 +52,17 @@ public class AuthorizationRequestHandlerDecorator implements RequestHandler { public AuthorizationRequestHandlerDecorator() { } - AuthorizationRequestHandlerDecorator(RequestHandler delegate, + /** + * Creates an authorization decorator programmatically. + * + *

This constructor is intended for integrations with + * non-CDI runtimes such as Spring Framework.

+ * + * @param delegate request handler being protected + * @param authorizationProvider task authorization provider; + * {@code null} disables authorization + */ + public AuthorizationRequestHandlerDecorator(RequestHandler delegate, @Nullable TaskAuthorizationProvider authorizationProvider) { this.delegate = delegate; this.authorizationProvider = authorizationProvider; diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/InMemoryTaskStore.java b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/InMemoryTaskStore.java index ddfbde45b..925c950cb 100644 --- a/server-common/src/main/java/org/a2aproject/sdk/server/tasks/InMemoryTaskStore.java +++ b/server-common/src/main/java/org/a2aproject/sdk/server/tasks/InMemoryTaskStore.java @@ -1,15 +1,9 @@ package org.a2aproject.sdk.server.tasks; -import java.util.Comparator; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Any; import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; - import org.a2aproject.sdk.jsonrpc.common.wrappers.ListTasksResult; import org.a2aproject.sdk.server.ServerCallContext; import org.a2aproject.sdk.server.auth.TaskAuthorizationProvider; @@ -17,10 +11,15 @@ import org.a2aproject.sdk.spec.Artifact; import org.a2aproject.sdk.spec.ListTasksParams; import org.a2aproject.sdk.spec.Message; -import org.a2aproject.sdk.util.PageToken; import org.a2aproject.sdk.spec.Task; +import org.a2aproject.sdk.util.PageToken; import org.jspecify.annotations.Nullable; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + /** * In-memory implementation of {@link TaskStore} and {@link TaskStateProvider}. *

@@ -105,7 +104,18 @@ public InMemoryTaskStore(@Any Instance authorizationP : null; } - InMemoryTaskStore(@Nullable TaskAuthorizationProvider authorizationProvider) { + /** + * Creates an in-memory task store with optional + * task-level authorization. + * + *

This constructor supports programmatic wiring + * in non-CDI runtimes such as Spring Framework.

+ * + * @param authorizationProvider provider used to filter + * tasks during list operations; + * {@code null} permits all tasks + */ + public InMemoryTaskStore(@Nullable TaskAuthorizationProvider authorizationProvider) { this.authorizationProvider = authorizationProvider; } From 51f83e978e1b22ff4a89dbffb8feac598a4dfa70 Mon Sep 17 00:00:00 2001 From: Vladimir Krasnov <109070155+Sh1bari@users.noreply.github.com> Date: Thu, 2 Jul 2026 14:28:41 +0300 Subject: [PATCH 2/2] Delete userAttributes --- .../a2aproject/sdk/server/auth/UserAttributes.java | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 server-common/src/main/java/org/a2aproject/sdk/server/auth/UserAttributes.java diff --git a/server-common/src/main/java/org/a2aproject/sdk/server/auth/UserAttributes.java b/server-common/src/main/java/org/a2aproject/sdk/server/auth/UserAttributes.java deleted file mode 100644 index 5d63e2211..000000000 --- a/server-common/src/main/java/org/a2aproject/sdk/server/auth/UserAttributes.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.a2aproject.sdk.server.auth; - -public final class UserAttributes { - - public static final String AUTHORITIES = "authorities"; - public static final String SCOPES = "scopes"; - public static final String TENANT_ID = "tenantId"; - public static final String CLIENT_ID = "clientId"; - - private UserAttributes() { - } -}