diff --git a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/AasRegistryTargetInformation.java b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/AasRegistryTargetInformation.java index c5b065662..241ef81ae 100644 --- a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/AasRegistryTargetInformation.java +++ b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/AasRegistryTargetInformation.java @@ -27,6 +27,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -42,23 +43,23 @@ @TargetInformationSubtype(getValue = "aas-registry") public class AasRegistryTargetInformation implements TargetInformation { - private String aasId; + private List aasIds; @JsonCreator - public AasRegistryTargetInformation(final @JsonProperty("aasId") String aasId) { - this.aasId = aasId; + public AasRegistryTargetInformation(final @JsonProperty("aasIds") List aasIds) { + this.aasIds = aasIds; } @Override public Map toMap() { final Map map = new HashMap<>(); - map.put("aasId", aasId); + map.put("aasIds", aasIds); return map; } @Override public int hashCode() { - return Objects.hash(aasId); + return Objects.hash(aasIds); } @Override @@ -70,16 +71,16 @@ public boolean equals(Object obj) { if (getClass() != obj.getClass()) return false; AasRegistryTargetInformation other = (AasRegistryTargetInformation) obj; - return Objects.equals(aasId, other.aasId); + return Objects.equals(aasIds, other.aasIds); } @Override public String toString() { - return "AasTargetInformation [aasId=" + aasId + "]"; + return "AasTargetInformation [aasIds=" + aasIds + "]"; } - public String getAasId() { - return aasId; + public List getAasIds() { + return aasIds; } } diff --git a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/AuthorizedAasRegistryStorage.java b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/AuthorizedAasRegistryStorage.java index 7a39a67c0..acacfbeb4 100644 --- a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/AuthorizedAasRegistryStorage.java +++ b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/AuthorizedAasRegistryStorage.java @@ -25,6 +25,8 @@ package org.eclipse.digitaltwin.basyx.aasregistry.feature.authorization; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Set; @@ -62,19 +64,19 @@ public AuthorizedAasRegistryStorage(AasRegistryStorage decorated, RbacPermission @Override public CursorResult> getAllAasDescriptors(PaginationInfo pRequest, DescriptorFilter filter) { - assertHasPermission(Action.READ, AasRegistryTargetPermissionVerifier.ALL_ALLOWED_WILDCARD); + assertHasPermission(Action.READ, getIdAsList(AasRegistryTargetPermissionVerifier.ALL_ALLOWED_WILDCARD)); return decorated.getAllAasDescriptors(pRequest, filter); } @Override public AssetAdministrationShellDescriptor getAasDescriptor(String aasDescriptorId) throws AasDescriptorNotFoundException { - assertHasPermission(Action.READ, aasDescriptorId); + assertHasPermission(Action.READ, getIdAsList(aasDescriptorId)); return decorated.getAasDescriptor(aasDescriptorId); } @Override public void insertAasDescriptor(AssetAdministrationShellDescriptor descr) throws AasDescriptorAlreadyExistsException { - assertHasPermission(Action.CREATE, descr.getId()); + assertHasPermission(Action.CREATE, getIdAsList(descr.getId())); decorated.insertAasDescriptor(descr); } @@ -83,64 +85,64 @@ public void replaceAasDescriptor(String aasDescriptorId, AssetAdministrationShel String newId = descriptor.getId(); if (!aasDescriptorId.equals(newId)) { - assertHasPermission(Action.DELETE, aasDescriptorId); - assertHasPermission(Action.CREATE, newId); + assertHasPermission(Action.DELETE, getIdAsList(aasDescriptorId)); + assertHasPermission(Action.CREATE, getIdAsList(newId)); } else - assertHasPermission(Action.UPDATE, aasDescriptorId); + assertHasPermission(Action.UPDATE, getIdAsList(aasDescriptorId)); decorated.replaceAasDescriptor(aasDescriptorId, descriptor); } @Override public void removeAasDescriptor(String aasDescriptorId) throws AasDescriptorNotFoundException { - assertHasPermission(Action.DELETE, aasDescriptorId); + assertHasPermission(Action.DELETE, getIdAsList(aasDescriptorId)); decorated.removeAasDescriptor(aasDescriptorId); } @Override public CursorResult> getAllSubmodels(String aasDescriptorId, PaginationInfo pRequest) throws AasDescriptorNotFoundException { - assertHasPermission(Action.READ, aasDescriptorId); + assertHasPermission(Action.READ, getIdAsList(aasDescriptorId)); return decorated.getAllSubmodels(aasDescriptorId, pRequest); } @Override public SubmodelDescriptor getSubmodel(String aasDescriptorId, String submodelId) throws AasDescriptorNotFoundException, SubmodelNotFoundException { - assertHasPermission(Action.READ, aasDescriptorId); + assertHasPermission(Action.READ, getIdAsList(aasDescriptorId)); return decorated.getSubmodel(aasDescriptorId, submodelId); } @Override public void insertSubmodel(String aasDescriptorId, SubmodelDescriptor submodel) throws AasDescriptorNotFoundException, SubmodelAlreadyExistsException { - assertHasPermission(Action.UPDATE, aasDescriptorId); + assertHasPermission(Action.UPDATE, getIdAsList(aasDescriptorId)); decorated.insertSubmodel(aasDescriptorId, submodel); } @Override public void replaceSubmodel(String aasDescriptorId, String submodelId, SubmodelDescriptor submodel) throws AasDescriptorNotFoundException, SubmodelNotFoundException { - assertHasPermission(Action.UPDATE, aasDescriptorId); + assertHasPermission(Action.UPDATE, getIdAsList(aasDescriptorId)); decorated.replaceSubmodel(aasDescriptorId, submodelId, submodel); } @Override public void removeSubmodel(String aasDescriptorId, String submodelId) throws AasDescriptorNotFoundException, SubmodelNotFoundException { - assertHasPermission(Action.UPDATE, aasDescriptorId); + assertHasPermission(Action.UPDATE, getIdAsList(aasDescriptorId)); decorated.removeSubmodel(aasDescriptorId, submodelId); } @Override public Set clear() { - assertHasPermission(Action.DELETE, AasRegistryTargetPermissionVerifier.ALL_ALLOWED_WILDCARD); + assertHasPermission(Action.DELETE, getIdAsList(AasRegistryTargetPermissionVerifier.ALL_ALLOWED_WILDCARD)); return decorated.clear(); } @Override public ShellDescriptorSearchResponse searchAasDescriptors(ShellDescriptorSearchRequest request) { - assertHasPermission(Action.READ, AasRegistryTargetPermissionVerifier.ALL_ALLOWED_WILDCARD); + assertHasPermission(Action.READ, getIdAsList(AasRegistryTargetPermissionVerifier.ALL_ALLOWED_WILDCARD)); return decorated.searchAasDescriptors(request); } - private void assertHasPermission(Action action, String aasId) { - boolean isAuthorized = permissionResolver.hasPermission(action, new AasRegistryTargetInformation(aasId)); + private void assertHasPermission(Action action, List assIds) { + boolean isAuthorized = permissionResolver.hasPermission(action, new AasRegistryTargetInformation(assIds)); throwExceptionIfInsufficientPermission(isAuthorized); } @@ -148,4 +150,8 @@ private void throwExceptionIfInsufficientPermission(boolean isAuthorized) { if (!isAuthorized) throw new InsufficientPermissionException("Insufficient Permission: The current subject does not have the required permissions for this operation."); } + + private List getIdAsList(String id) { + return new ArrayList<>(Arrays.asList(id)); + } } diff --git a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/rbac/AasRegistryTargetPermissionVerifier.java b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/rbac/AasRegistryTargetPermissionVerifier.java index 8997e1fbc..46523e44d 100644 --- a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/rbac/AasRegistryTargetPermissionVerifier.java +++ b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/feature/authorization/rbac/AasRegistryTargetPermissionVerifier.java @@ -29,6 +29,8 @@ import org.eclipse.digitaltwin.basyx.authorization.rbac.RbacRule; import org.eclipse.digitaltwin.basyx.authorization.rbac.TargetPermissionVerifier; +import java.util.List; + /** * Verifies the {@link AasRegistryTargetInformation} against the {@link RbacRule} * @@ -37,14 +39,26 @@ public class AasRegistryTargetPermissionVerifier implements TargetPermissionVerifier { public static final String ALL_ALLOWED_WILDCARD = "*"; - + @Override public boolean isVerified(RbacRule rbacRule, AasRegistryTargetInformation targetInformation) { - String shellId = targetInformation.getAasId(); - + List targetInformationShellIds = targetInformation.getAasIds(); + AasRegistryTargetInformation rbacRuleAasTargetInformation = (AasRegistryTargetInformation) rbacRule.getTargetInformation(); - - return rbacRuleAasTargetInformation.getAasId().equals(ALL_ALLOWED_WILDCARD) || rbacRuleAasTargetInformation.getAasId().equals(shellId); + + List rbacRuleShellIds = rbacRuleAasTargetInformation.getAasIds(); + + return areShellsAllowed(rbacRuleShellIds, targetInformationShellIds); + } + + private boolean areShellsAllowed(List rbacRuleShellIds, List targetInformationShellIds) { + + return allShellsAllowed(rbacRuleShellIds) || rbacRuleShellIds.containsAll(targetInformationShellIds); + } + + private boolean allShellsAllowed(List rbacRuleShellIds) { + + return rbacRuleShellIds.size() == 1 && rbacRuleShellIds.get(0).equals(ALL_ALLOWED_WILDCARD); } } diff --git a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/regression/feature/authorization/TestAuthorizedAasRegistry.java b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/regression/feature/authorization/TestAuthorizedAasRegistry.java index df8145fcc..c78e3831e 100644 --- a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/regression/feature/authorization/TestAuthorizedAasRegistry.java +++ b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/regression/feature/authorization/TestAuthorizedAasRegistry.java @@ -276,222 +276,222 @@ public void deleteAasDescriptorWithNoAuthorization() throws IOException { } @Test - public void getSubmodelDescriptorsWithCorrectRoleAndPermission() throws IOException { + public void getAasDescriptorsWithCorrectRoleAndPermission() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_READER_CREDENTIAL); - CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSubmodelDescriptorsAccessURL(SPECIFIC_SHELL_ID), accessToken); + CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getAasDescriptorsAccessURL(SPECIFIC_SHELL_ID), accessToken); assertEquals(HttpStatus.OK.value(), retrievalResponse.getCode()); } @Test - public void getSubmodelDescriptorsWithCorrectRoleAndSpecificAasDescriptorPermission() throws IOException { + public void getAasDescriptorsWithCorrectRoleAndSpecificAasDescriptorPermission() throws IOException { DummyCredential dummyCredential = DummyCredentialStore.BASYX_READER_TWO_CREDENTIAL; String accessToken = tokenProvider.getAccessToken(dummyCredential.getUsername(), dummyCredential.getPassword()); - CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSubmodelDescriptorsAccessURL(SPECIFIC_SHELL_ID), accessToken); + CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getAasDescriptorsAccessURL(SPECIFIC_SHELL_ID), accessToken); assertEquals(HttpStatus.OK.value(), retrievalResponse.getCode()); } @Test - public void getSubmodelDescriptorsWithCorrectRoleAndUnauthorizedSpecificAasDescriptor() throws IOException { + public void getAasDescriptorsWithCorrectRoleAndUnauthorizedSpecificAasDescriptor() throws IOException { DummyCredential dummyCredential = DummyCredentialStore.BASYX_READER_TWO_CREDENTIAL; String accessToken = tokenProvider.getAccessToken(dummyCredential.getUsername(), dummyCredential.getPassword()); - CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSubmodelDescriptorsAccessURL(SPECIFIC_SHELL_ID_2), accessToken); + CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getAasDescriptorsAccessURL(SPECIFIC_SHELL_ID_2), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test - public void getSubmodelDescriptorsWithInsufficientPermissionRole() throws IOException { + public void getAasDescriptorsWithInsufficientPermissionRole() throws IOException { DummyCredential dummyCredential = DummyCredentialStore.BASYX_UPDATER_CREDENTIAL; String accessToken = tokenProvider.getAccessToken(dummyCredential.getUsername(), dummyCredential.getPassword()); - CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSubmodelDescriptorsAccessURL(SPECIFIC_SHELL_ID), accessToken); + CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getAasDescriptorsAccessURL(SPECIFIC_SHELL_ID), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test - public void getSubmodelDescriptorsWithNoAuthorization() throws IOException { - CloseableHttpResponse retrievalResponse = getElementWithNoAuthorization(getSubmodelDescriptorsAccessURL(SPECIFIC_SHELL_ID)); + public void getAasDescriptorsWithNoAuthorization() throws IOException { + CloseableHttpResponse retrievalResponse = getElementWithNoAuthorization(getAasDescriptorsAccessURL(SPECIFIC_SHELL_ID)); assertEquals(HttpStatus.UNAUTHORIZED.value(), retrievalResponse.getCode()); } @Test - public void getSubmodelDescriptorWithCorrectRoleAndPermission() throws IOException { + public void getAasDescriptorWithCorrectRoleAndPermission() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_READER_CREDENTIAL); - CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID, SPECIFIC_SUBMODEL_ID), accessToken); + CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID, SPECIFIC_SUBMODEL_ID), accessToken); assertEquals(HttpStatus.OK.value(), retrievalResponse.getCode()); } @Test - public void getSubmodelDescriptorWithCorrectRoleAndSpecificAasPermission() throws IOException { + public void getAasDescriptorWithCorrectRoleAndSpecificAasPermission() throws IOException { DummyCredential dummyCredential = DummyCredentialStore.BASYX_READER_TWO_CREDENTIAL; String accessToken = tokenProvider.getAccessToken(dummyCredential.getUsername(), dummyCredential.getPassword()); - CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID, SPECIFIC_SUBMODEL_ID), accessToken); + CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID, SPECIFIC_SUBMODEL_ID), accessToken); assertEquals(HttpStatus.OK.value(), retrievalResponse.getCode()); } @Test - public void getSubmodelDescriptorWithCorrectRoleAndUnauthorizedSpecificAas() throws IOException { + public void getAasDescriptorWithCorrectRoleAndUnauthorizedSpecificAas() throws IOException { DummyCredential dummyCredential = DummyCredentialStore.BASYX_READER_TWO_CREDENTIAL; String accessToken = tokenProvider.getAccessToken(dummyCredential.getUsername(), dummyCredential.getPassword()); - CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID_2, SPECIFIC_SUBMODEL_ID), accessToken); + CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2, SPECIFIC_SUBMODEL_ID), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test - public void getSubmodelDescriptorWithInsufficientPermissionRole() throws IOException { + public void getAasDescriptorWithInsufficientPermissionRole() throws IOException { DummyCredential dummyCredential = DummyCredentialStore.BASYX_UPDATER_CREDENTIAL; String accessToken = tokenProvider.getAccessToken(dummyCredential.getUsername(), dummyCredential.getPassword()); - CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID, SPECIFIC_SUBMODEL_ID), accessToken); + CloseableHttpResponse retrievalResponse = getElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID, SPECIFIC_SUBMODEL_ID), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test - public void getSubmodelDescriptorWithNoAuthorization() throws IOException { - CloseableHttpResponse retrievalResponse = getElementWithNoAuthorization(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID, SPECIFIC_SUBMODEL_ID)); + public void getAasDescriptorWithNoAuthorization() throws IOException { + CloseableHttpResponse retrievalResponse = getElementWithNoAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID, SPECIFIC_SUBMODEL_ID)); assertEquals(HttpStatus.UNAUTHORIZED.value(), retrievalResponse.getCode()); } @Test - public void addSubmodelDescriptorWithCorrectRoleAndPermission() throws IOException { + public void addAasDescriptorWithCorrectRoleAndPermission() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_UPDATER_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSubmodelDescriptorsAccessURL(SPECIFIC_SHELL_ID), getJSONStringFromFile("authorization/SingleSubmodelDescriptor.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getAasDescriptorsAccessURL(SPECIFIC_SHELL_ID), getJSONStringFromFile("authorization/SingleSubmodelDescriptor.json"), accessToken); assertEquals(HttpStatus.CREATED.value(), retrievalResponse.getCode()); } @Test - public void addSubmodelDescriptorWithCorrectRoleAndSpecificAasPermission() throws IOException { + public void addAasDescriptorWithCorrectRoleAndSpecificAasPermission() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_UPDATER_TWO_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSubmodelDescriptorsAccessURL(SPECIFIC_SHELL_ID), getJSONStringFromFile("authorization/SingleSubmodelDescriptor.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getAasDescriptorsAccessURL(SPECIFIC_SHELL_ID), getJSONStringFromFile("authorization/SingleSubmodelDescriptor.json"), accessToken); assertEquals(HttpStatus.CREATED.value(), retrievalResponse.getCode()); } @Test - public void addSubmodelDescriptorWithCorrectRoleAndUnauthorizedSpecificAas() throws IOException { + public void addAasDescriptorWithCorrectRoleAndUnauthorizedSpecificAas() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_UPDATER_TWO_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSubmodelDescriptorsAccessURL(SPECIFIC_SHELL_ID_2), getJSONStringFromFile("authorization/SingleSubmodelDescriptor.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getAasDescriptorsAccessURL(SPECIFIC_SHELL_ID_2), getJSONStringFromFile("authorization/SingleSubmodelDescriptor.json"), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test - public void addSubmodelDescriptorWithInsufficientPermissionRole() throws IOException { + public void addAasDescriptorWithInsufficientPermissionRole() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_READER_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSubmodelDescriptorsAccessURL(SPECIFIC_SHELL_ID), getJSONStringFromFile("authorization/SingleSubmodelDescriptor.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getAasDescriptorsAccessURL(SPECIFIC_SHELL_ID), getJSONStringFromFile("authorization/SingleSubmodelDescriptor.json"), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test - public void addSubmodelDescriptorWithNoAuthorization() throws IOException { - CloseableHttpResponse retrievalResponse = updateElementWithNoAuthorizationPostRequest(getSubmodelDescriptorsAccessURL(SPECIFIC_SHELL_ID), getJSONStringFromFile("authorization/SingleSubmodelDescriptor.json")); + public void addAasDescriptorWithNoAuthorization() throws IOException { + CloseableHttpResponse retrievalResponse = updateElementWithNoAuthorizationPostRequest(getAasDescriptorsAccessURL(SPECIFIC_SHELL_ID), getJSONStringFromFile("authorization/SingleSubmodelDescriptor.json")); assertEquals(HttpStatus.UNAUTHORIZED.value(), retrievalResponse.getCode()); } @Test - public void removeSubmodelDescriptorWithCorrectRoleAndPermission() throws IOException { + public void removeAasDescriptorWithCorrectRoleAndPermission() throws IOException { createAasDescriptorOnRegistryWithAuthorization(aasRegistryBaseUrl, getJSONStringFromFile(AAS_DESCRIPTOR_SIMPLE_2_JSON), getAccessToken(DummyCredentialStore.ADMIN_CREDENTIAL)); String accessToken = getAccessToken(DummyCredentialStore.BASYX_ASSET_UPDATER_CREDENTIAL); - CloseableHttpResponse retrievalResponse = deleteElementWithAuthorization(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), accessToken); + CloseableHttpResponse retrievalResponse = deleteElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), accessToken); assertEquals(HttpStatus.NO_CONTENT.value(), retrievalResponse.getCode()); deleteElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2), getAccessToken(DummyCredentialStore.ADMIN_CREDENTIAL)); } @Test - public void removeSubmodelDescriptorWithCorrectRoleAndSpecificAasPermission() throws IOException { + public void removeAasDescriptorWithCorrectRoleAndSpecificAasPermission() throws IOException { createAasDescriptorOnRegistryWithAuthorization(aasRegistryBaseUrl, getJSONStringFromFile(AAS_DESCRIPTOR_SIMPLE_2_JSON), getAccessToken(DummyCredentialStore.ADMIN_CREDENTIAL)); String accessToken = getAccessToken(DummyCredentialStore.BASYX_ASSET_UPDATER_TWO_CREDENTIAL); - CloseableHttpResponse retrievalResponse = deleteElementWithAuthorization(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), accessToken); + CloseableHttpResponse retrievalResponse = deleteElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), accessToken); assertEquals(HttpStatus.NO_CONTENT.value(), retrievalResponse.getCode()); deleteElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2), getAccessToken(DummyCredentialStore.ADMIN_CREDENTIAL)); } @Test - public void removeSubmodelDescriptorWithCorrectRoleAndUnauthorizedSpecificAas() throws IOException { + public void removeAasDescriptorWithCorrectRoleAndUnauthorizedSpecificAas() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_ASSET_UPDATER_TWO_CREDENTIAL); - CloseableHttpResponse retrievalResponse = deleteElementWithAuthorization(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID, "specificAasId-2-SM"), accessToken); + CloseableHttpResponse retrievalResponse = deleteElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID, "specificAasId-2-SM"), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test - public void removeSubmodelDescriptorWithInsufficientPermissionRole() throws IOException { + public void removeAasDescriptorWithInsufficientPermissionRole() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_CREATOR_CREDENTIAL); - CloseableHttpResponse retrievalResponse = deleteElementWithAuthorization(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), accessToken); + CloseableHttpResponse retrievalResponse = deleteElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test - public void removeSubmodelDescriptorWithNoAuthorization() throws IOException { - CloseableHttpResponse retrievalResponse = deleteElementWithNoAuthorization(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM")); + public void removeAasDescriptorWithNoAuthorization() throws IOException { + CloseableHttpResponse retrievalResponse = deleteElementWithNoAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM")); assertEquals(HttpStatus.UNAUTHORIZED.value(), retrievalResponse.getCode()); } @Test - public void replaceSubmodelDescriptorWithCorrectRoleAndPermission() throws IOException { + public void replaceAasDescriptorWithCorrectRoleAndPermission() throws IOException { createAasDescriptorOnRegistryWithAuthorization(aasRegistryBaseUrl, getJSONStringFromFile(AAS_DESCRIPTOR_SIMPLE_2_JSON), getAccessToken(DummyCredentialStore.ADMIN_CREDENTIAL)); String accessToken = getAccessToken(DummyCredentialStore.BASYX_ASSET_UPDATER_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPutRequest(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), getJSONStringFromFile("authorization/SingleSubmodelDescriptor_Update.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPutRequest(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), getJSONStringFromFile("authorization/SingleSubmodelDescriptor_Update.json"), accessToken); assertEquals(HttpStatus.NO_CONTENT.value(), retrievalResponse.getCode()); deleteElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2), getAccessToken(DummyCredentialStore.ADMIN_CREDENTIAL)); } @Test - public void replaceSubmodelDescriptorWithCorrectRoleAndSpecificAasPermission() throws IOException { + public void replaceAasDescriptorWithCorrectRoleAndSpecificAasPermission() throws IOException { createAasDescriptorOnRegistryWithAuthorization(aasRegistryBaseUrl, getJSONStringFromFile(AAS_DESCRIPTOR_SIMPLE_2_JSON), getAccessToken(DummyCredentialStore.ADMIN_CREDENTIAL)); String accessToken = getAccessToken(DummyCredentialStore.BASYX_ASSET_UPDATER_TWO_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPutRequest(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), getJSONStringFromFile("authorization/SingleSubmodelDescriptor_Update.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPutRequest(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), getJSONStringFromFile("authorization/SingleSubmodelDescriptor_Update.json"), accessToken); assertEquals(HttpStatus.NO_CONTENT.value(), retrievalResponse.getCode()); deleteElementWithAuthorization(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2), getAccessToken(DummyCredentialStore.ADMIN_CREDENTIAL)); } @Test - public void replaceSubmodelDescriptorWithCorrectRoleAndUnauthorizedSpecificAas() throws IOException { + public void replaceAasDescriptorWithCorrectRoleAndUnauthorizedSpecificAas() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_ASSET_UPDATER_TWO_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPutRequest(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID, "specificAasId-2-SM"), getJSONStringFromFile("authorization/SingleSubmodelDescriptor_Update.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPutRequest(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID, "specificAasId-2-SM"), getJSONStringFromFile("authorization/SingleSubmodelDescriptor_Update.json"), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test - public void replaceSubmodelDescriptorWithInsufficientPermissionRole() throws IOException { + public void replaceAasDescriptorWithInsufficientPermissionRole() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_CREATOR_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPutRequest(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), getJSONStringFromFile("authorization/SingleSubmodelDescriptor_Update.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPutRequest(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), getJSONStringFromFile("authorization/SingleSubmodelDescriptor_Update.json"), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test - public void replaceSubmodelDescriptorWithNoAuthorization() throws IOException { - CloseableHttpResponse retrievalResponse = updateElementWithNoAuthorizationPutRequest(getSpecificSubmodelDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), getJSONStringFromFile("authorization/SingleSubmodelDescriptor_Update.json")); + public void replaceAasDescriptorWithNoAuthorization() throws IOException { + CloseableHttpResponse retrievalResponse = updateElementWithNoAuthorizationPutRequest(getSpecificAasDescriptorAccessURL(SPECIFIC_SHELL_ID_2, "specificAasId-2-SM"), getJSONStringFromFile("authorization/SingleSubmodelDescriptor_Update.json")); assertEquals(HttpStatus.UNAUTHORIZED.value(), retrievalResponse.getCode()); } @@ -592,12 +592,12 @@ private String getSearchUrl() { return BASE_URL + "/search"; } - private String getSubmodelDescriptorsAccessURL(String shellId) { + private String getAasDescriptorsAccessURL(String shellId) { return getSpecificAasDescriptorAccessURL(shellId) + "/submodel-descriptors"; } - private String getSpecificSubmodelDescriptorAccessURL(String shellId, String submodelId) { - return getSubmodelDescriptorsAccessURL(shellId) + "/" + Base64UrlEncodedIdentifier.encodeIdentifier(submodelId); + private String getSpecificAasDescriptorAccessURL(String shellId, String submodelId) { + return getAasDescriptorsAccessURL(shellId) + "/" + Base64UrlEncodedIdentifier.encodeIdentifier(submodelId); } private CloseableHttpResponse deleteElementWithNoAuthorization(String url) throws IOException { diff --git a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/resources/rbac_rules.json b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/resources/rbac_rules.json index d0925041e..f1d984308 100644 --- a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/resources/rbac_rules.json +++ b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/resources/rbac_rules.json @@ -4,7 +4,7 @@ "action": "READ", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -12,7 +12,7 @@ "action": ["CREATE", "READ", "UPDATE", "DELETE"], "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -20,7 +20,7 @@ "action": "READ", "targetInformation": { "@type": "aas-registry", - "aasId": "dummyShellId_3" + "aasIds": ["dummyShellId_3", "dummyShellId_4"] } }, { @@ -28,7 +28,7 @@ "action": "CREATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -36,7 +36,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -44,7 +44,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "dummyShellId_3" + "aasIds": "dummyShellId_3" } }, { @@ -52,7 +52,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -60,7 +60,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "specificAasId-2" + "aasIds": "specificAasId-2" } }, { @@ -68,7 +68,7 @@ "action": "DELETE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -76,7 +76,7 @@ "action": "DELETE", "targetInformation": { "@type": "aas-registry", - "aasId": "specificAasId-2" + "aasIds": "specificAasId-2" } } ] \ No newline at end of file diff --git a/basyx.aasregistry/basyx.aasregistry-service-release-kafka-mem/src/test/resources/rbac_rules.json b/basyx.aasregistry/basyx.aasregistry-service-release-kafka-mem/src/test/resources/rbac_rules.json index d0925041e..f1d984308 100644 --- a/basyx.aasregistry/basyx.aasregistry-service-release-kafka-mem/src/test/resources/rbac_rules.json +++ b/basyx.aasregistry/basyx.aasregistry-service-release-kafka-mem/src/test/resources/rbac_rules.json @@ -4,7 +4,7 @@ "action": "READ", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -12,7 +12,7 @@ "action": ["CREATE", "READ", "UPDATE", "DELETE"], "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -20,7 +20,7 @@ "action": "READ", "targetInformation": { "@type": "aas-registry", - "aasId": "dummyShellId_3" + "aasIds": ["dummyShellId_3", "dummyShellId_4"] } }, { @@ -28,7 +28,7 @@ "action": "CREATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -36,7 +36,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -44,7 +44,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "dummyShellId_3" + "aasIds": "dummyShellId_3" } }, { @@ -52,7 +52,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -60,7 +60,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "specificAasId-2" + "aasIds": "specificAasId-2" } }, { @@ -68,7 +68,7 @@ "action": "DELETE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -76,7 +76,7 @@ "action": "DELETE", "targetInformation": { "@type": "aas-registry", - "aasId": "specificAasId-2" + "aasIds": "specificAasId-2" } } ] \ No newline at end of file diff --git a/basyx.aasregistry/basyx.aasregistry-service-release-kafka-mongodb/src/test/resources/rbac_rules.json b/basyx.aasregistry/basyx.aasregistry-service-release-kafka-mongodb/src/test/resources/rbac_rules.json index d0925041e..f1d984308 100644 --- a/basyx.aasregistry/basyx.aasregistry-service-release-kafka-mongodb/src/test/resources/rbac_rules.json +++ b/basyx.aasregistry/basyx.aasregistry-service-release-kafka-mongodb/src/test/resources/rbac_rules.json @@ -4,7 +4,7 @@ "action": "READ", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -12,7 +12,7 @@ "action": ["CREATE", "READ", "UPDATE", "DELETE"], "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -20,7 +20,7 @@ "action": "READ", "targetInformation": { "@type": "aas-registry", - "aasId": "dummyShellId_3" + "aasIds": ["dummyShellId_3", "dummyShellId_4"] } }, { @@ -28,7 +28,7 @@ "action": "CREATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -36,7 +36,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -44,7 +44,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "dummyShellId_3" + "aasIds": "dummyShellId_3" } }, { @@ -52,7 +52,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -60,7 +60,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "specificAasId-2" + "aasIds": "specificAasId-2" } }, { @@ -68,7 +68,7 @@ "action": "DELETE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -76,7 +76,7 @@ "action": "DELETE", "targetInformation": { "@type": "aas-registry", - "aasId": "specificAasId-2" + "aasIds": "specificAasId-2" } } ] \ No newline at end of file diff --git a/basyx.aasregistry/basyx.aasregistry-service-release-log-mem/src/test/resources/rbac_rules.json b/basyx.aasregistry/basyx.aasregistry-service-release-log-mem/src/test/resources/rbac_rules.json index d0925041e..f1d984308 100644 --- a/basyx.aasregistry/basyx.aasregistry-service-release-log-mem/src/test/resources/rbac_rules.json +++ b/basyx.aasregistry/basyx.aasregistry-service-release-log-mem/src/test/resources/rbac_rules.json @@ -4,7 +4,7 @@ "action": "READ", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -12,7 +12,7 @@ "action": ["CREATE", "READ", "UPDATE", "DELETE"], "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -20,7 +20,7 @@ "action": "READ", "targetInformation": { "@type": "aas-registry", - "aasId": "dummyShellId_3" + "aasIds": ["dummyShellId_3", "dummyShellId_4"] } }, { @@ -28,7 +28,7 @@ "action": "CREATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -36,7 +36,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -44,7 +44,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "dummyShellId_3" + "aasIds": "dummyShellId_3" } }, { @@ -52,7 +52,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -60,7 +60,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "specificAasId-2" + "aasIds": "specificAasId-2" } }, { @@ -68,7 +68,7 @@ "action": "DELETE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -76,7 +76,7 @@ "action": "DELETE", "targetInformation": { "@type": "aas-registry", - "aasId": "specificAasId-2" + "aasIds": "specificAasId-2" } } ] \ No newline at end of file diff --git a/basyx.aasregistry/basyx.aasregistry-service-release-log-mongodb/src/test/resources/rbac_rules.json b/basyx.aasregistry/basyx.aasregistry-service-release-log-mongodb/src/test/resources/rbac_rules.json index d0925041e..f1d984308 100644 --- a/basyx.aasregistry/basyx.aasregistry-service-release-log-mongodb/src/test/resources/rbac_rules.json +++ b/basyx.aasregistry/basyx.aasregistry-service-release-log-mongodb/src/test/resources/rbac_rules.json @@ -4,7 +4,7 @@ "action": "READ", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -12,7 +12,7 @@ "action": ["CREATE", "READ", "UPDATE", "DELETE"], "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -20,7 +20,7 @@ "action": "READ", "targetInformation": { "@type": "aas-registry", - "aasId": "dummyShellId_3" + "aasIds": ["dummyShellId_3", "dummyShellId_4"] } }, { @@ -28,7 +28,7 @@ "action": "CREATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -36,7 +36,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -44,7 +44,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "dummyShellId_3" + "aasIds": "dummyShellId_3" } }, { @@ -52,7 +52,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -60,7 +60,7 @@ "action": "UPDATE", "targetInformation": { "@type": "aas-registry", - "aasId": "specificAasId-2" + "aasIds": "specificAasId-2" } }, { @@ -68,7 +68,7 @@ "action": "DELETE", "targetInformation": { "@type": "aas-registry", - "aasId": "*" + "aasIds": "*" } }, { @@ -76,7 +76,7 @@ "action": "DELETE", "targetInformation": { "@type": "aas-registry", - "aasId": "specificAasId-2" + "aasIds": "specificAasId-2" } } ] \ No newline at end of file diff --git a/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/AuthorizedSubmodelRegistryStorage.java b/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/AuthorizedSubmodelRegistryStorage.java index 694c1f0d1..74887d22e 100644 --- a/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/AuthorizedSubmodelRegistryStorage.java +++ b/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/AuthorizedSubmodelRegistryStorage.java @@ -25,6 +25,8 @@ package org.eclipse.digitaltwin.basyx.submodelregistry.feature.authorization; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Set; import org.eclipse.digitaltwin.basyx.authorization.rbac.Action; @@ -55,19 +57,19 @@ public AuthorizedSubmodelRegistryStorage(SubmodelRegistryStorage decorated, Rbac @Override public CursorResult> getAllSubmodelDescriptors(PaginationInfo pRequest) { - assertHasPermission(Action.READ, SubmodelRegistryTargetPermissionVerifier.ALL_ALLOWED_WILDCARD); + assertHasPermission(Action.READ, getIdAsList(SubmodelRegistryTargetPermissionVerifier.ALL_ALLOWED_WILDCARD)); return decorated.getAllSubmodelDescriptors(pRequest); } @Override public SubmodelDescriptor getSubmodelDescriptor(String submodelId) throws SubmodelNotFoundException { - assertHasPermission(Action.READ, submodelId); + assertHasPermission(Action.READ, getIdAsList(submodelId)); return decorated.getSubmodelDescriptor(submodelId); } @Override public void removeSubmodelDescriptor(String submodelId) throws SubmodelNotFoundException { - assertHasPermission(Action.DELETE, submodelId); + assertHasPermission(Action.DELETE, getIdAsList(submodelId)); decorated.removeSubmodelDescriptor(submodelId); } @@ -75,29 +77,29 @@ public void replaceSubmodelDescriptor(String submodelId, SubmodelDescriptor desc String newId = descriptor.getId(); if (!submodelId.equals(newId)) { - assertHasPermission(Action.DELETE, submodelId); - assertHasPermission(Action.CREATE, newId); + assertHasPermission(Action.DELETE, getIdAsList(submodelId)); + assertHasPermission(Action.CREATE, getIdAsList(newId)); } else - assertHasPermission(Action.UPDATE, submodelId); + assertHasPermission(Action.UPDATE, getIdAsList(submodelId)); decorated.replaceSubmodelDescriptor(submodelId, descriptor); } @Override public void insertSubmodelDescriptor(SubmodelDescriptor descriptor) throws SubmodelAlreadyExistsException { - assertHasPermission(Action.CREATE, descriptor.getId()); + assertHasPermission(Action.CREATE, getIdAsList(descriptor.getId())); decorated.insertSubmodelDescriptor(descriptor); } @Override public Set clear() { - assertHasPermission(Action.DELETE, SubmodelRegistryTargetPermissionVerifier.ALL_ALLOWED_WILDCARD); + assertHasPermission(Action.DELETE, getIdAsList(SubmodelRegistryTargetPermissionVerifier.ALL_ALLOWED_WILDCARD)); return decorated.clear(); } - private void assertHasPermission(Action action, String submodelId) { - boolean isAuthorized = permissionResolver.hasPermission(action, new SubmodelRegistryTargetInformation(submodelId)); + private void assertHasPermission(Action action, List submodelIds) { + boolean isAuthorized = permissionResolver.hasPermission(action, new SubmodelRegistryTargetInformation(submodelIds)); throwExceptionIfInsufficientPermission(isAuthorized); } @@ -105,4 +107,8 @@ private void throwExceptionIfInsufficientPermission(boolean isAuthorized) { if (!isAuthorized) throw new InsufficientPermissionException("Insufficient Permission: The current subject does not have the required permissions for this operation."); } + + private List getIdAsList(String id) { + return new ArrayList<>(Arrays.asList(id)); + } } diff --git a/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/SubmodelRegistryTargetInformation.java b/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/SubmodelRegistryTargetInformation.java index ac4cd9f7d..4ece5156b 100644 --- a/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/SubmodelRegistryTargetInformation.java +++ b/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/SubmodelRegistryTargetInformation.java @@ -29,6 +29,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.List; import org.eclipse.digitaltwin.basyx.authorization.rbac.TargetInformation; import org.eclipse.digitaltwin.basyx.authorization.rbac.TargetInformationSubtype; @@ -42,23 +43,23 @@ @TargetInformationSubtype(getValue = "submodel-registry") public class SubmodelRegistryTargetInformation implements TargetInformation { - private String submodelId; + private List submodelIds; @JsonCreator - public SubmodelRegistryTargetInformation(final @JsonProperty("submodelId") String submodelId) { - this.submodelId = submodelId; + public SubmodelRegistryTargetInformation(final @JsonProperty("submodelIds") List submodelIds) { + this.submodelIds = submodelIds; } @Override public Map toMap() { final Map map = new HashMap<>(); - map.put("submodelId", submodelId); + map.put("submodelIds", submodelIds); return map; } @Override public int hashCode() { - return Objects.hash(submodelId); + return Objects.hash(submodelIds); } @Override @@ -70,16 +71,16 @@ public boolean equals(Object obj) { if (getClass() != obj.getClass()) return false; SubmodelRegistryTargetInformation other = (SubmodelRegistryTargetInformation) obj; - return Objects.equals(submodelId, other.submodelId); + return Objects.equals(submodelIds, other.submodelIds); } @Override public String toString() { - return "SubmodelTargetInformation [submodelId=" + submodelId + "]"; + return "SubmodelTargetInformation [submodelIds=" + submodelIds + "]"; } - public String getSubmodelId() { - return submodelId; + public List getSubmodelIds() { + return submodelIds; } } diff --git a/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/rbac/SubmodelRegistryTargetPermissionVerifier.java b/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/rbac/SubmodelRegistryTargetPermissionVerifier.java index a68400692..4e7870d2e 100644 --- a/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/rbac/SubmodelRegistryTargetPermissionVerifier.java +++ b/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/feature/authorization/rbac/SubmodelRegistryTargetPermissionVerifier.java @@ -29,6 +29,8 @@ import org.eclipse.digitaltwin.basyx.authorization.rbac.RbacRule; import org.eclipse.digitaltwin.basyx.authorization.rbac.TargetPermissionVerifier; +import java.util.List; + /** * Verifies the {@link SubmodelRegistryTargetInformation} against the {@link RbacRule} * @@ -37,14 +39,25 @@ public class SubmodelRegistryTargetPermissionVerifier implements TargetPermissionVerifier { public static final String ALL_ALLOWED_WILDCARD = "*"; - + @Override public boolean isVerified(RbacRule rbacRule, SubmodelRegistryTargetInformation targetInformation) { - String submodelId = targetInformation.getSubmodelId(); - + List targetInformationSubmodelIds = targetInformation.getSubmodelIds(); + SubmodelRegistryTargetInformation rbacRuleSubmodelTargetInformation = (SubmodelRegistryTargetInformation) rbacRule.getTargetInformation(); - - return rbacRuleSubmodelTargetInformation.getSubmodelId().equals(ALL_ALLOWED_WILDCARD) || rbacRuleSubmodelTargetInformation.getSubmodelId().equals(submodelId); + + List rbacRuleSubmodelIds = rbacRuleSubmodelTargetInformation.getSubmodelIds(); + + return areSubmodelsAllowed(rbacRuleSubmodelIds, targetInformationSubmodelIds); + } + + private boolean areSubmodelsAllowed(List rbacRuleSubmodelIds, List targetInformationSubmodelIds) { + return allSubmodelsAllowed(rbacRuleSubmodelIds) || rbacRuleSubmodelIds.containsAll(targetInformationSubmodelIds); + } + + private boolean allSubmodelsAllowed(List rbacRuleSubmodelIds) { + + return rbacRuleSubmodelIds.size() == 1 && rbacRuleSubmodelIds.get(0).equals(ALL_ALLOWED_WILDCARD); } } diff --git a/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/test/resources/rbac_rules.json b/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/test/resources/rbac_rules.json index 9fcf84488..cc90ddd86 100644 --- a/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/test/resources/rbac_rules.json +++ b/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/test/resources/rbac_rules.json @@ -4,7 +4,7 @@ "action": "READ", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -12,7 +12,7 @@ "action": ["CREATE", "READ", "UPDATE", "DELETE"], "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -20,7 +20,7 @@ "action": "READ", "targetInformation": { "@type": "submodel-registry", - "submodelId": "dummySubmodelId_3" + "submodelIds": ["dummySubmodelId_3", "specificSubmodelId-4"] } }, { @@ -28,7 +28,7 @@ "action": "CREATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -36,7 +36,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -44,7 +44,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "dummySubmodelId_3" + "submodelIds": "dummySubmodelId_3" } }, { @@ -52,7 +52,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -60,7 +60,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "specificSubmodelId-2" + "submodelIds": "specificSubmodelId-2" } }, { @@ -68,7 +68,7 @@ "action": "DELETE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -76,7 +76,7 @@ "action": "DELETE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "specificSubmodelId-2" + "submodelIds": "specificSubmodelId-2" } } ] \ No newline at end of file diff --git a/basyx.submodelregistry/basyx.submodelregistry-service-release-kafka-mem/src/test/resources/rbac_rules.json b/basyx.submodelregistry/basyx.submodelregistry-service-release-kafka-mem/src/test/resources/rbac_rules.json index 9fcf84488..cc90ddd86 100644 --- a/basyx.submodelregistry/basyx.submodelregistry-service-release-kafka-mem/src/test/resources/rbac_rules.json +++ b/basyx.submodelregistry/basyx.submodelregistry-service-release-kafka-mem/src/test/resources/rbac_rules.json @@ -4,7 +4,7 @@ "action": "READ", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -12,7 +12,7 @@ "action": ["CREATE", "READ", "UPDATE", "DELETE"], "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -20,7 +20,7 @@ "action": "READ", "targetInformation": { "@type": "submodel-registry", - "submodelId": "dummySubmodelId_3" + "submodelIds": ["dummySubmodelId_3", "specificSubmodelId-4"] } }, { @@ -28,7 +28,7 @@ "action": "CREATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -36,7 +36,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -44,7 +44,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "dummySubmodelId_3" + "submodelIds": "dummySubmodelId_3" } }, { @@ -52,7 +52,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -60,7 +60,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "specificSubmodelId-2" + "submodelIds": "specificSubmodelId-2" } }, { @@ -68,7 +68,7 @@ "action": "DELETE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -76,7 +76,7 @@ "action": "DELETE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "specificSubmodelId-2" + "submodelIds": "specificSubmodelId-2" } } ] \ No newline at end of file diff --git a/basyx.submodelregistry/basyx.submodelregistry-service-release-kafka-mongodb/src/test/resources/rbac_rules.json b/basyx.submodelregistry/basyx.submodelregistry-service-release-kafka-mongodb/src/test/resources/rbac_rules.json index 9fcf84488..cc90ddd86 100644 --- a/basyx.submodelregistry/basyx.submodelregistry-service-release-kafka-mongodb/src/test/resources/rbac_rules.json +++ b/basyx.submodelregistry/basyx.submodelregistry-service-release-kafka-mongodb/src/test/resources/rbac_rules.json @@ -4,7 +4,7 @@ "action": "READ", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -12,7 +12,7 @@ "action": ["CREATE", "READ", "UPDATE", "DELETE"], "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -20,7 +20,7 @@ "action": "READ", "targetInformation": { "@type": "submodel-registry", - "submodelId": "dummySubmodelId_3" + "submodelIds": ["dummySubmodelId_3", "specificSubmodelId-4"] } }, { @@ -28,7 +28,7 @@ "action": "CREATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -36,7 +36,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -44,7 +44,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "dummySubmodelId_3" + "submodelIds": "dummySubmodelId_3" } }, { @@ -52,7 +52,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -60,7 +60,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "specificSubmodelId-2" + "submodelIds": "specificSubmodelId-2" } }, { @@ -68,7 +68,7 @@ "action": "DELETE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -76,7 +76,7 @@ "action": "DELETE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "specificSubmodelId-2" + "submodelIds": "specificSubmodelId-2" } } ] \ No newline at end of file diff --git a/basyx.submodelregistry/basyx.submodelregistry-service-release-log-mem/src/test/resources/rbac_rules.json b/basyx.submodelregistry/basyx.submodelregistry-service-release-log-mem/src/test/resources/rbac_rules.json index 9fcf84488..cc90ddd86 100644 --- a/basyx.submodelregistry/basyx.submodelregistry-service-release-log-mem/src/test/resources/rbac_rules.json +++ b/basyx.submodelregistry/basyx.submodelregistry-service-release-log-mem/src/test/resources/rbac_rules.json @@ -4,7 +4,7 @@ "action": "READ", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -12,7 +12,7 @@ "action": ["CREATE", "READ", "UPDATE", "DELETE"], "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -20,7 +20,7 @@ "action": "READ", "targetInformation": { "@type": "submodel-registry", - "submodelId": "dummySubmodelId_3" + "submodelIds": ["dummySubmodelId_3", "specificSubmodelId-4"] } }, { @@ -28,7 +28,7 @@ "action": "CREATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -36,7 +36,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -44,7 +44,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "dummySubmodelId_3" + "submodelIds": "dummySubmodelId_3" } }, { @@ -52,7 +52,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -60,7 +60,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "specificSubmodelId-2" + "submodelIds": "specificSubmodelId-2" } }, { @@ -68,7 +68,7 @@ "action": "DELETE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -76,7 +76,7 @@ "action": "DELETE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "specificSubmodelId-2" + "submodelIds": "specificSubmodelId-2" } } ] \ No newline at end of file diff --git a/basyx.submodelregistry/basyx.submodelregistry-service-release-log-mongodb/src/test/resources/rbac_rules.json b/basyx.submodelregistry/basyx.submodelregistry-service-release-log-mongodb/src/test/resources/rbac_rules.json index 9fcf84488..cc90ddd86 100644 --- a/basyx.submodelregistry/basyx.submodelregistry-service-release-log-mongodb/src/test/resources/rbac_rules.json +++ b/basyx.submodelregistry/basyx.submodelregistry-service-release-log-mongodb/src/test/resources/rbac_rules.json @@ -4,7 +4,7 @@ "action": "READ", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -12,7 +12,7 @@ "action": ["CREATE", "READ", "UPDATE", "DELETE"], "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -20,7 +20,7 @@ "action": "READ", "targetInformation": { "@type": "submodel-registry", - "submodelId": "dummySubmodelId_3" + "submodelIds": ["dummySubmodelId_3", "specificSubmodelId-4"] } }, { @@ -28,7 +28,7 @@ "action": "CREATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -36,7 +36,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -44,7 +44,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "dummySubmodelId_3" + "submodelIds": "dummySubmodelId_3" } }, { @@ -52,7 +52,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -60,7 +60,7 @@ "action": "UPDATE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "specificSubmodelId-2" + "submodelIds": "specificSubmodelId-2" } }, { @@ -68,7 +68,7 @@ "action": "DELETE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "*" + "submodelIds": "*" } }, { @@ -76,7 +76,7 @@ "action": "DELETE", "targetInformation": { "@type": "submodel-registry", - "submodelId": "specificSubmodelId-2" + "submodelIds": "specificSubmodelId-2" } } ] \ No newline at end of file