diff --git a/credentials/src/main/java/com/epam/aidial/core/credentials/service/ResourceCredentialsService.java b/credentials/src/main/java/com/epam/aidial/core/credentials/service/ResourceCredentialsService.java index e41287e65..f625c6d9d 100644 --- a/credentials/src/main/java/com/epam/aidial/core/credentials/service/ResourceCredentialsService.java +++ b/credentials/src/main/java/com/epam/aidial/core/credentials/service/ResourceCredentialsService.java @@ -229,7 +229,7 @@ public ResourceCredentials getRefreshedResourceCredentials(CredentialsLocator cr * Resolves the owner's USER-level credential only, with auto-refresh — and no fallback to * GLOBAL/APPLICATION levels. Used by the on-behalf-of (OBO) retrieval path, which must fail closed * rather than silently serve a shared/app-level identity. Returns {@code null} when the owner has no - * USER-level credential for the scope (the locator must carry only a USER bucket, but the userSub + * USER-level credential for the scope (the locator must carry only a USER bucket, but the owner user-id * match is enforced defensively here too). * *
When a credential exists but the owner did not grant offline-usage consent, it is returned as
@@ -239,7 +239,7 @@ public ResourceCredentials getRefreshedResourceCredentials(CredentialsLocator cr
@Nullable
public ResourceCredentials getRefreshedUserCredentials(CredentialsLocator credentialsLocator,
ResourceAuthSettings authSettings,
- String ownerSub) {
+ String ownerUserId) {
if (authSettings.getAuthenticationType() == AuthenticationType.NONE) {
return null;
}
@@ -252,7 +252,7 @@ public ResourceCredentials getRefreshedUserCredentials(CredentialsLocator creden
ResourceCredentials stored = getResourceCredentials(userDescriptor);
if (stored == null
|| !stored.getCredentialsLevel().equals(CredentialsLevel.USER)
- || !Objects.equals(ownerSub, stored.getUserId())) {
+ || !Objects.equals(ownerUserId, stored.getUserId())) {
return null;
}
// Gate consent BEFORE refreshing: an OBO probe against a non-consented credential must not rotate the
@@ -267,7 +267,7 @@ public ResourceCredentials getRefreshedUserCredentials(CredentialsLocator creden
// window — accepted, since revocation via sign-out normally deletes the credential outright.)
if (userCredentials != null
&& userCredentials.getCredentialsLevel().equals(CredentialsLevel.USER)
- && Objects.equals(ownerSub, userCredentials.getUserId())
+ && Objects.equals(ownerUserId, userCredentials.getUserId())
&& userCredentials.isOfflineUsageConsent()) {
return userCredentials;
}
diff --git a/docs/open_api_core.yaml b/docs/open_api_core.yaml
index 027858a39..b439815bd 100644
--- a/docs/open_api_core.yaml
+++ b/docs/open_api_core.yaml
@@ -13192,7 +13192,7 @@ components:
OboCredentialsRequest:
type: object
properties:
- ownerSub:
+ ownerUserId:
type: string
url:
type: string
diff --git a/server/src/main/java/com/epam/aidial/core/server/controller/ExternalServiceCredentialsController.java b/server/src/main/java/com/epam/aidial/core/server/controller/ExternalServiceCredentialsController.java
index 74da25651..ec2880c8a 100644
--- a/server/src/main/java/com/epam/aidial/core/server/controller/ExternalServiceCredentialsController.java
+++ b/server/src/main/java/com/epam/aidial/core/server/controller/ExternalServiceCredentialsController.java
@@ -288,12 +288,12 @@ public Future> getOboCredentials() {
}
ExternalService externalService = resolveExternalServiceDefinition(
- app.application, scope[0], scope[1], request.getOwnerSub());
+ app.application, scope[0], scope[1], request.getOwnerUserId());
ResourceAuthSettings authSettings = externalService.getAuthSettings();
CredentialsLocator locator = CredentialsLocatorFactory.fromExternalServiceScopeForOwner(
- request.getUrl(), request.getOwnerSub(), context);
+ request.getUrl(), request.getOwnerUserId(), context);
ResourceCredentials credentials = resourceCredentialsService.getRefreshedUserCredentials(
- locator, authSettings, request.getOwnerSub());
+ locator, authSettings, request.getOwnerUserId());
// Fail closed: no fallback to APP/GLOBAL. Missing owner credential ⇒ 404.
if (credentials == null) {
@@ -304,12 +304,12 @@ public Future> getOboCredentials() {
}
ExternalServiceCredentialsResponse response = toCredentialsResponse(credentials, request.getUrl());
- ExternalServiceAuditLog.oboRetrieval(context, scope[0], scope[1], request.getOwnerSub(), null);
+ ExternalServiceAuditLog.oboRetrieval(context, scope[0], scope[1], request.getOwnerUserId(), null);
return response;
} catch (RuntimeException e) {
// Audit failures too — including a malformed url that fails scope parsing (best-effort ids).
String[] scope = safeParseScope(request.getUrl());
- ExternalServiceAuditLog.oboRetrieval(context, scope[0], scope[1], request.getOwnerSub(), e);
+ ExternalServiceAuditLog.oboRetrieval(context, scope[0], scope[1], request.getOwnerUserId(), e);
throw e;
}
}))
@@ -353,13 +353,13 @@ private ResolvedExternalService resolveExternalService(String scopeId) {
/**
* Canonical external-service definition resolver. Resolves the admin/inline definition first; when the
* app permits it ({@code allow_user_external_services}) and no inline definition exists, falls back to a
- * user-authored definition in the owner's bucket. {@code ownerSub} is the credential
+ * user-authored definition in the owner's bucket. {@code ownerUserId} is the credential
* owner on the OBO path; {@code null} on caller-scoped paths, where the caller is the owner.
*/
- private ResolvedExternalService resolveExternalService(String scopeId, @Nullable String ownerSub) {
+ private ResolvedExternalService resolveExternalService(String scopeId, @Nullable String ownerUserId) {
String[] parts = CredentialsLocatorFactory.parseExternalServiceScope(scopeId);
ResolvedApplication app = resolveApplication(parts[0]);
- ExternalService externalService = resolveExternalServiceDefinition(app.application, parts[0], parts[1], ownerSub);
+ ExternalService externalService = resolveExternalServiceDefinition(app.application, parts[0], parts[1], ownerUserId);
return new ResolvedExternalService(app.application, externalService, app.applicationDescriptor, app.staticApp);
}
@@ -384,11 +384,11 @@ private ResolvedApplication resolveApplication(String appPart) {
}
private ExternalService resolveExternalServiceDefinition(Application application, String appPart,
- String externalServiceId, @Nullable String ownerSub) {
+ String externalServiceId, @Nullable String ownerUserId) {
ExternalService externalService = application.getExternalServices() == null
? null : application.getExternalServices().get(externalServiceId);
if (externalService == null && application.isAllowUserExternalServices()) {
- String owner = ownerSub != null ? ownerSub : context.getUserId();
+ String owner = ownerUserId != null ? ownerUserId : context.getUserId();
if (owner != null) {
externalService = userExternalServiceService.get(owner, appPart, externalServiceId);
}
diff --git a/server/src/main/java/com/epam/aidial/core/server/data/OboCredentialsRequest.java b/server/src/main/java/com/epam/aidial/core/server/data/OboCredentialsRequest.java
index d967aac43..0d71528f1 100644
--- a/server/src/main/java/com/epam/aidial/core/server/data/OboCredentialsRequest.java
+++ b/server/src/main/java/com/epam/aidial/core/server/data/OboCredentialsRequest.java
@@ -10,7 +10,7 @@ public class OboCredentialsRequest {
@NotBlank(message = "url should be specified")
private String url;
- @NotBlank(message = "owner_sub should be specified")
- @JsonAlias({"ownerSub", "owner_sub"})
- private String ownerSub;
+ @NotBlank(message = "owner_user_id should be specified")
+ @JsonAlias({"ownerUserId", "owner_user_id"})
+ private String ownerUserId;
}
diff --git a/server/src/main/java/com/epam/aidial/core/server/log/ExternalServiceAuditLog.java b/server/src/main/java/com/epam/aidial/core/server/log/ExternalServiceAuditLog.java
index 6d10eca62..e284aea20 100644
--- a/server/src/main/java/com/epam/aidial/core/server/log/ExternalServiceAuditLog.java
+++ b/server/src/main/java/com/epam/aidial/core/server/log/ExternalServiceAuditLog.java
@@ -32,7 +32,7 @@ private ExternalServiceAuditLog() {
/** One event per OBO retrieval outcome; {@code error} is {@code null} on success. */
public static void oboRetrieval(ProxyContext context, String applicationId, String externalServiceId,
- String ownerSub, RuntimeException error) {
+ String ownerUserId, RuntimeException error) {
String outcome = switch (error) {
case null -> "SUCCESS";
case ConsentRequiredException ignored -> "CONSENT_REQUIRED";
@@ -41,9 +41,9 @@ public static void oboRetrieval(ProxyContext context, String applicationId, Stri
default -> "ERROR";
};
// reason echoes only the exception message, never a response body or secret — keep it that way.
- AUDIT.info("event=obo_credential_retrieval outcome={} actor={} owner_sub={} application_id={} "
+ AUDIT.info("event=obo_credential_retrieval outcome={} actor={} owner_user_id={} application_id={} "
+ "external_service_id={} trace_id={}{}",
- outcome, actorEvidence(context), sanitizeToken(ownerSub), sanitizeToken(applicationId),
+ outcome, actorEvidence(context), sanitizeToken(ownerUserId), sanitizeToken(applicationId),
sanitizeToken(externalServiceId), context.getTraceId(),
error == null ? "" : " reason=\"%s\"".formatted(sanitizeReason(error.getMessage())));
}
diff --git a/server/src/main/java/com/epam/aidial/core/server/service/UserExternalServiceService.java b/server/src/main/java/com/epam/aidial/core/server/service/UserExternalServiceService.java
index 1f6721f11..9ae24fff1 100644
--- a/server/src/main/java/com/epam/aidial/core/server/service/UserExternalServiceService.java
+++ b/server/src/main/java/com/epam/aidial/core/server/service/UserExternalServiceService.java
@@ -30,7 +30,7 @@
/**
* User-authored external-service definitions: each is its own resource in the author's
- * bucket at {@code Users/{ownerSub}/external_services/applications/{app_id}/{id}}. Isolation rides on
+ * bucket at {@code Users/{ownerUserId}/external_services/applications/{app_id}/{id}}. Isolation rides on
* bucket ownership; the {@code client_secret} is encrypted under the owner's CEK.
*/
@RequiredArgsConstructor
@@ -42,18 +42,18 @@ public class UserExternalServiceService {
private final ResourceAuthSettingsEncryptionService secretEncryptionService;
private final EncryptionService bucketEncryptionService;
- public ResourceDescriptor descriptor(String ownerSub, String appPart, String serviceId) {
- requireOwner(ownerSub);
+ public ResourceDescriptor descriptor(String ownerUserId, String appPart, String serviceId) {
+ requireOwner(ownerUserId);
ExternalServiceValidation.validateServiceId(serviceId);
- String bucketLocation = BucketBuilder.USER_BUCKET_PATTERN.formatted(ownerSub);
+ String bucketLocation = BucketBuilder.USER_BUCKET_PATTERN.formatted(ownerUserId);
String bucketName = bucketEncryptionService.encrypt(bucketLocation);
List