From 578fe8f476070da1c05672edb5b07e897fd529c1 Mon Sep 17 00:00:00 2001 From: "Zimin A.N." Date: Mon, 4 May 2026 17:40:43 +0300 Subject: [PATCH] =?UTF-8?q?feat(auth):=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B6=D0=BA=D0=B0=20colon-separated=20=D1=80=D0=BE=D0=BB?= =?UTF-8?q?=D0=B5=D0=B9=20(=D0=90=D0=BB=D1=8C=D1=82=D1=83=D0=BC-style)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Альтум выдаёт роли формата "ordinis:client:public" / "ordinis:client:internal" / "ordinis:client:restricted" в realm_access.roles. Старая версия ScopeContext обрабатывала только "-" / "_" разделители + ORDINIS- префикс — colon-роли приводили к fallback на PUBLIC. Теперь normalizeRoleToScope: - strips "ORDINIS:" (как и "ORDINIS-" / "ORDINIS_") - берёт сегмент после последнего из "-", "_", ":" Совместимо с прежними форматами. + 2 unit-теста (всего 13 в ScopeContextTest). --- .../terravault/ordinis/auth/ScopeContext.java | 12 ++++++++---- .../ordinis/auth/ScopeContextTest.java | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/ordinis-auth/src/main/java/cloud/nstart/terravault/ordinis/auth/ScopeContext.java b/ordinis-auth/src/main/java/cloud/nstart/terravault/ordinis/auth/ScopeContext.java index 7e7ea8c..c9f1e90 100644 --- a/ordinis-auth/src/main/java/cloud/nstart/terravault/ordinis/auth/ScopeContext.java +++ b/ordinis-auth/src/main/java/cloud/nstart/terravault/ordinis/auth/ScopeContext.java @@ -101,14 +101,18 @@ public class ScopeContext { * Маппинг имени роли в scope. Поддерживает: * "ordinis-public" / "public" → PUBLIC * "ORDINIS_INTERNAL" → INTERNAL - * суффикс после "-" или "_": "x-RESTRICTED" → RESTRICTED + * "ordinis:client:public" → PUBLIC (Альтум-style colon-separated) + * суффикс после "-", "_" или ":": "x:RESTRICTED" → RESTRICTED * просто "PUBLIC"|"INTERNAL"|"RESTRICTED" */ private static String normalizeRoleToScope(String role) { if (role == null) return null; - String s = role.trim().toUpperCase().replace("ORDINIS-", "").replace("ORDINIS_", ""); - int dash = Math.max(s.lastIndexOf('-'), s.lastIndexOf('_')); - if (dash >= 0) s = s.substring(dash + 1); + String s = role.trim().toUpperCase() + .replace("ORDINIS-", "") + .replace("ORDINIS_", "") + .replace("ORDINIS:", ""); + int sep = Math.max(Math.max(s.lastIndexOf('-'), s.lastIndexOf('_')), s.lastIndexOf(':')); + if (sep >= 0) s = s.substring(sep + 1); return s; } diff --git a/ordinis-auth/src/test/java/cloud/nstart/terravault/ordinis/auth/ScopeContextTest.java b/ordinis-auth/src/test/java/cloud/nstart/terravault/ordinis/auth/ScopeContextTest.java index 52eee89..e21b17d 100644 --- a/ordinis-auth/src/test/java/cloud/nstart/terravault/ordinis/auth/ScopeContextTest.java +++ b/ordinis-auth/src/test/java/cloud/nstart/terravault/ordinis/auth/ScopeContextTest.java @@ -58,6 +58,24 @@ class ScopeContextTest { .containsExactlyInAnyOrder(DataScope.PUBLIC, DataScope.INTERNAL); } + @Test + void mapsAltumColonSeparatedRoles() { + // Альтум-style: realm role "ordinis:client:public" → DataScope.PUBLIC. + setJwtWithRealmRoles(List.of( + "ordinis:client:public", + "ordinis:client:internal", + "ordinis:client:restricted")); + assertThat(new ScopeContext(propsNoQuery).currentScopes()) + .containsExactlyInAnyOrder(DataScope.PUBLIC, DataScope.INTERNAL, DataScope.RESTRICTED); + } + + @Test + void mapsMixedColonAndDashRoles() { + setJwtWithRealmRoles(List.of("ordinis:client:public", "ordinis-restricted")); + assertThat(new ScopeContext(propsNoQuery).currentScopes()) + .containsExactlyInAnyOrder(DataScope.PUBLIC, DataScope.RESTRICTED); + } + @Test void unrecognizedRolesGivePublicFallback() { setJwtWithRealmRoles(List.of("admin", "viewer"));