diff --git a/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/authorization/TestAuthorizedAasRepository.java b/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/authorization/TestAuthorizedAasRepository.java index bdb5ffd7a..83c561788 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/authorization/TestAuthorizedAasRepository.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/authorization/TestAuthorizedAasRepository.java @@ -160,6 +160,16 @@ public void getAasWithOnlyResourceRole() throws IOException { assertEquals(HttpStatus.OK.value(), retrievalResponse.getCode()); } + @Test + public void getAasWithBothRealmAndResourceRole() throws IOException { + DummyCredential dummyCredential = DummyCredentialStore.VISITOR_CREDENTIAL; + + String accessToken = tokenProvider.getAccessToken(dummyCredential.getUsername(), dummyCredential.getPassword()); + + CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSpecificAasAccessURL(SPECIFIC_SHELL_ID), accessToken); + assertEquals(HttpStatus.OK.value(), retrievalResponse.getCode()); + } + @Test public void getAasWithCorrectRoleAndSpecificAasPermission() throws IOException { DummyCredential dummyCredential = DummyCredentialStore.BASYX_READER_TWO_CREDENTIAL; @@ -206,6 +216,16 @@ public void createAasWithCorrectRoleAndPermission() throws IOException { deleteElementWithAuthorization(getSpecificAasAccessURL(SPECIFIC_SHELL_ID_2), getAccessToken(DummyCredentialStore.ADMIN_CREDENTIAL)); } + @Test + public void createAasWithBothRealmAndResourceRole() throws IOException { + String accessToken = getAccessToken(DummyCredentialStore.VISITOR_CREDENTIAL); + + CloseableHttpResponse retrievalResponse = createAasOnRepositoryWithAuthorization(getAasJSONString(AAS_SIMPLE_2_JSON), accessToken); + assertEquals(HttpStatus.CREATED.value(), retrievalResponse.getCode()); + + deleteElementWithAuthorization(getSpecificAasAccessURL(SPECIFIC_SHELL_ID_2), getAccessToken(DummyCredentialStore.ADMIN_CREDENTIAL)); + } + @Test public void createAasWithInsufficientPermissionRole() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_READER_CREDENTIAL); diff --git a/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/resources/rbac_rules.json b/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/resources/rbac_rules.json index 212e5e195..4dc81114d 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/resources/rbac_rules.json +++ b/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/resources/rbac_rules.json @@ -23,6 +23,22 @@ "aasIds": "specificAasId" } }, + { + "role": "basyx-user", + "action": "CREATE", + "targetInformation": { + "@type": "aas", + "aasIds": "specificAasId-2" + } + }, + { + "role": "visitor", + "action": "READ", + "targetInformation": { + "@type": "aas", + "aasIds": "specificAasId" + } + }, { "role": "basyx-reader-two", "action": "READ", diff --git a/basyx.common/basyx.authorization/src/test/java/org/eclipse/digitaltwin/basyx/authorization/TestKeycloakRoleProvider.java b/basyx.common/basyx.authorization/src/test/java/org/eclipse/digitaltwin/basyx/authorization/TestKeycloakRoleProvider.java index 1eae8d4ae..c0a2275f4 100644 --- a/basyx.common/basyx.authorization/src/test/java/org/eclipse/digitaltwin/basyx/authorization/TestKeycloakRoleProvider.java +++ b/basyx.common/basyx.authorization/src/test/java/org/eclipse/digitaltwin/basyx/authorization/TestKeycloakRoleProvider.java @@ -46,16 +46,16 @@ */ public class TestKeycloakRoleProvider { - @Mock + @Mock private SubjectInformationProvider subjectInformationProvider; - @Mock + @Mock private Jwt jwt; - @InjectMocks + @InjectMocks private KeycloakRoleProvider keycloakRoleProvider; - @Before + @Before public void setUp() { MockitoAnnotations.openMocks(this); @@ -65,7 +65,7 @@ public void setUp() { when(subjectInformationProvider.get()).thenReturn(subjectInfo); } - @Test + @Test public void getRoles_whenBothRealmAndResourceRolesPresent() { Map> realmAccess = new HashMap<>(); realmAccess.put("roles", Arrays.asList("ROLE_USER", "ROLE_ADMIN")); @@ -92,7 +92,7 @@ public void getRoles_whenBothRealmAndResourceRolesPresent() { assertTrue(roles.contains("ROLE_SUPPORT")); } - @Test + @Test public void getRoles_whenOnlyRealmRolesPresent() { Map> realmAccess = new HashMap<>(); realmAccess.put("roles", Arrays.asList("ROLE_USER", "ROLE_ADMIN")); @@ -109,7 +109,7 @@ public void getRoles_whenOnlyRealmRolesPresent() { assertTrue(roles.contains("ROLE_ADMIN")); } - @Test + @Test public void getRoles_whenOnlyResourceRolesPresent() { Map>> resourceAccess = new HashMap<>(); resourceAccess.put("client1", new HashMap<>() {{ @@ -128,7 +128,7 @@ public void getRoles_whenOnlyResourceRolesPresent() { assertTrue(roles.contains("ROLE_SUPPORT")); } - @Test + @Test public void getRoles_whenNoRolesPresent() { when(jwt.hasClaim("realm_access")).thenReturn(true); when(jwt.hasClaim("resource_access")).thenReturn(true); @@ -140,7 +140,7 @@ public void getRoles_whenNoRolesPresent() { assertTrue(roles.isEmpty()); } - @Test(expected = NullSubjectException.class) + @Test(expected = NullSubjectException.class) public void getRoles_whenJwtIsNull() { @SuppressWarnings("unchecked") SubjectInformation subjectInfo = mock(SubjectInformation.class); @@ -150,7 +150,7 @@ public void getRoles_whenJwtIsNull() { keycloakRoleProvider.getRoles(); } - @Test + @Test public void getRoles_whenRealmAccessNotPresentButResourceAccessPresent() { Map>> resourceAccess = new HashMap<>(); resourceAccess.put("client1", new HashMap<>() {{ @@ -168,7 +168,7 @@ public void getRoles_whenRealmAccessNotPresentButResourceAccessPresent() { assertTrue(roles.contains("ROLE_USER")); } - @Test + @Test public void getRoles_whenResourceAccessNotPresentButRealmAccessPresent() { Map> realmAccess = new HashMap<>(); realmAccess.put("roles", Arrays.asList("ROLE_USER", "ROLE_ADMIN")); @@ -184,7 +184,7 @@ public void getRoles_whenResourceAccessNotPresentButRealmAccessPresent() { assertTrue(roles.contains("ROLE_ADMIN")); } - @Test + @Test public void getRoles_whenClaimNotPresent() { when(jwt.hasClaim("realm_access")).thenReturn(false); when(jwt.hasClaim("resource_access")).thenReturn(false); @@ -193,4 +193,4 @@ public void getRoles_whenClaimNotPresent() { assertTrue(roles.isEmpty()); } -} \ No newline at end of file +} diff --git a/ci/keycloak/realm/BaSyx-realm.json b/ci/keycloak/realm/BaSyx-realm.json index 358f6d711..3f417b521 100644 --- a/ci/keycloak/realm/BaSyx-realm.json +++ b/ci/keycloak/realm/BaSyx-realm.json @@ -52,14 +52,6 @@ "clientRole" : false, "containerId" : "bcb69552-bf11-4249-a3eb-d0c3ab54a570", "attributes" : { } - }, { - "id" : "784a37d9-37df-4f01-9748-5b6215496d6e", - "name" : "client1-admin", - "description" : "", - "composite" : false, - "clientRole" : false, - "containerId" : "bcb69552-bf11-4249-a3eb-d0c3ab54a570", - "attributes" : { } }, { "id" : "9b70ce9b-1b39-4f5a-893d-9f8956cf5dad", "name" : "basyx-reader-serialization-two", @@ -666,7 +658,7 @@ "otpPolicyLookAheadWindow" : 1, "otpPolicyPeriod" : 30, "otpPolicyCodeReusable" : false, - "otpSupportedApplications" : [ "totpAppGoogleName", "totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName" ], + "otpSupportedApplications" : [ "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName", "totpAppFreeOTPName" ], "webAuthnPolicyRpEntityName" : "keycloak", "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], "webAuthnPolicyRpId" : "", @@ -1306,24 +1298,6 @@ "realmRoles" : [ "maintainer", "default-roles-basyx" ], "notBefore" : 0, "groups" : [ ] - }, { - "id" : "00d5c956-aeec-415a-9c91-07297eb3c76e", - "createdTimestamp" : 1728034148186, - "username" : "client1", - "enabled" : true, - "totp" : false, - "emailVerified" : false, - "firstName" : "", - "lastName" : "", - "credentials" : [ ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "default-roles-basyx" ], - "clientRoles" : { - "realm-management" : [ "view-authorization", "manage-events", "view-clients", "create-client", "manage-realm", "manage-identity-providers", "manage-users", "view-events", "manage-authorization", "manage-clients" ] - }, - "notBefore" : 0, - "groups" : [ ] }, { "id" : "e75ac9e8-7093-4898-a203-d9839f854944", "createdTimestamp" : 1702030567684, @@ -1344,9 +1318,6 @@ "disableableCredentialTypes" : [ ], "requiredActions" : [ ], "realmRoles" : [ "user", "default-roles-basyx" ], - "clientRoles" : { - "basyx-client-api" : [ "basyx-user" ] - }, "notBefore" : 0, "groups" : [ ] }, { @@ -1416,6 +1387,9 @@ "disableableCredentialTypes" : [ ], "requiredActions" : [ ], "realmRoles" : [ "visitor", "default-roles-basyx" ], + "clientRoles" : { + "basyx-client-api" : [ "basyx-user" ] + }, "notBefore" : 0, "groups" : [ ] }, { @@ -1429,10 +1403,8 @@ "credentials" : [ ], "disableableCredentialTypes" : [ ], "requiredActions" : [ ], - "realmRoles" : [ "basyx-reader", "admin", "basyx-deleter", "basyx-updater", "basyx-creator", "default-roles-basyx" ], + "realmRoles" : [ "basyx-reader", "basyx-deleter", "basyx-updater", "admin", "basyx-creator", "default-roles-basyx" ], "clientRoles" : { - "realm-management" : [ "manage-realm", "query-users", "manage-users", "view-users" ], - "account" : [ "manage-account", "manage-consent" ], "workstation-1" : [ "uma_protection" ] }, "notBefore" : 0,