From 31cbb393db9c4e084f86d8e4aee00c8432e78467 Mon Sep 17 00:00:00 2001 From: MM1277 Date: Thu, 25 Apr 2024 12:03:14 +0200 Subject: [PATCH] Closes #2563 - Add assignment of workbasket access items via permissions --- .../src/main/resources/taskana-example.ldif | 16 +++++++++++--- .../ldap/LdapEmptySearchRootsTest.java | 6 ++--- .../pro/taskana/example/ldap/LdapTest.java | 2 +- .../src/test/resources/taskana-test.ldif | 16 +++++++++++--- .../src/main/resources/taskana-test.ldif | 16 +++++++++++--- .../common/rest/AccessIdController.java | 10 ++++++--- .../taskana/common/rest/ldap/LdapClient.java | 22 +++++++++++++------ .../rest/AccessIdControllerIntTest.java | 2 +- .../rest/TaskanaEngineControllerIntTest.java | 2 +- .../common/rest/ldap/LdapClientTest.java | 8 ++++--- 10 files changed, 72 insertions(+), 28 deletions(-) diff --git a/rest/taskana-rest-spring-example-common/src/main/resources/taskana-example.ldif b/rest/taskana-rest-spring-example-common/src/main/resources/taskana-example.ldif index 0e282334da..23049e3797 100644 --- a/rest/taskana-rest-spring-example-common/src/main/resources/taskana-example.ldif +++ b/rest/taskana-rest-spring-example-common/src/main/resources/taskana-example.ldif @@ -139,7 +139,7 @@ givenName: Elena description: desc memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA permission: perm:userleads -permission: perm:other +permission: perm/other memberOf: cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA uid: user-1-2 sn: Eifrig @@ -417,6 +417,16 @@ cn: monitor-users objectclass: groupofuniquenames objectclass: top +dn: cn=Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung,cn=groups,OU=Test,O=TASKANA +cn: Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung +objectclass: groupofuniquenames +objectclass: top + +dn: cn=Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung_vip,cn=groups,OU=Test,O=TASKANA +cn: Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung_vip +objectclass: groupofuniquenames +objectclass: top + ######################## # Permissions ######################## @@ -430,9 +440,9 @@ objectclass: permissiongroup objectclass: groupofuniquenames objectclass: top -dn: permission=perm:other,cn=permissions,OU=Test,O=TASKANA +dn: permission=perm/other,cn=permissions,OU=Test,O=TASKANA uniquemember: uid=user-1-2,cn=users,OU=Test,O=TASKANA -permission: perm:other +permission: perm/other cn: g01 objectclass: permissiongroup objectclass: groupofuniquenames diff --git a/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/example/ldap/LdapEmptySearchRootsTest.java b/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/example/ldap/LdapEmptySearchRootsTest.java index 6f06655969..f802394340 100644 --- a/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/example/ldap/LdapEmptySearchRootsTest.java +++ b/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/example/ldap/LdapEmptySearchRootsTest.java @@ -31,7 +31,7 @@ void should_FindPermissionsForUser_When_UserIdIsProvided() throws Exception { ldapClient.searchPermissionsAccessIdHas("user-1-2"); assertThat(permissions) .extracting(AccessIdRepresentationModel::getAccessId) - .containsExactlyInAnyOrder("perm:userleads", "perm:other"); + .containsExactlyInAnyOrder("perm:userleads", "perm/other"); } @Test @@ -42,7 +42,7 @@ void should_ReturnFullDnForUser_When_AccessIdOfUserIsGiven() throws Exception { @Test void should_ReturnFullDnForPermission_When_AccessIdOfPermissionIsGiven() throws Exception { - String dn = ldapClient.searchDnForAccessId("perm:other"); - assertThat(dn).isEqualTo("permission=perm:other,cn=permissions,ou=test,o=taskana"); + String dn = ldapClient.searchDnForAccessId("perm/other"); + assertThat(dn).isEqualTo("permission=perm/other,cn=permissions,ou=test,o=taskana"); } } diff --git a/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/example/ldap/LdapTest.java b/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/example/ldap/LdapTest.java index 1e1d7ce27d..8cdaf02d8d 100644 --- a/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/example/ldap/LdapTest.java +++ b/rest/taskana-rest-spring-example-common/src/test/java/pro/taskana/example/ldap/LdapTest.java @@ -55,7 +55,7 @@ void should_FindPermissionsForUser_When_UserIdIsProvided() throws Exception { ldapClient.searchPermissionsAccessIdHas("user-1-2"); assertThat(permissions) .extracting(AccessIdRepresentationModel::getAccessId) - .containsExactlyInAnyOrder("perm:other", "perm:userleads"); + .containsExactlyInAnyOrder("perm/other", "perm:userleads"); } @Test diff --git a/rest/taskana-rest-spring-example-wildfly/src/test/resources/taskana-test.ldif b/rest/taskana-rest-spring-example-wildfly/src/test/resources/taskana-test.ldif index 0e282334da..23049e3797 100644 --- a/rest/taskana-rest-spring-example-wildfly/src/test/resources/taskana-test.ldif +++ b/rest/taskana-rest-spring-example-wildfly/src/test/resources/taskana-test.ldif @@ -139,7 +139,7 @@ givenName: Elena description: desc memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA permission: perm:userleads -permission: perm:other +permission: perm/other memberOf: cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA uid: user-1-2 sn: Eifrig @@ -417,6 +417,16 @@ cn: monitor-users objectclass: groupofuniquenames objectclass: top +dn: cn=Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung,cn=groups,OU=Test,O=TASKANA +cn: Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung +objectclass: groupofuniquenames +objectclass: top + +dn: cn=Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung_vip,cn=groups,OU=Test,O=TASKANA +cn: Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung_vip +objectclass: groupofuniquenames +objectclass: top + ######################## # Permissions ######################## @@ -430,9 +440,9 @@ objectclass: permissiongroup objectclass: groupofuniquenames objectclass: top -dn: permission=perm:other,cn=permissions,OU=Test,O=TASKANA +dn: permission=perm/other,cn=permissions,OU=Test,O=TASKANA uniquemember: uid=user-1-2,cn=users,OU=Test,O=TASKANA -permission: perm:other +permission: perm/other cn: g01 objectclass: permissiongroup objectclass: groupofuniquenames diff --git a/rest/taskana-rest-spring-test-lib/src/main/resources/taskana-test.ldif b/rest/taskana-rest-spring-test-lib/src/main/resources/taskana-test.ldif index 0e282334da..23049e3797 100644 --- a/rest/taskana-rest-spring-test-lib/src/main/resources/taskana-test.ldif +++ b/rest/taskana-rest-spring-test-lib/src/main/resources/taskana-test.ldif @@ -139,7 +139,7 @@ givenName: Elena description: desc memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA permission: perm:userleads -permission: perm:other +permission: perm/other memberOf: cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA uid: user-1-2 sn: Eifrig @@ -417,6 +417,16 @@ cn: monitor-users objectclass: groupofuniquenames objectclass: top +dn: cn=Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung,cn=groups,OU=Test,O=TASKANA +cn: Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung +objectclass: groupofuniquenames +objectclass: top + +dn: cn=Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung_vip,cn=groups,OU=Test,O=TASKANA +cn: Postkorb:Sachbearbeitung:LV:LV/A:Sachbearbeitung_vip +objectclass: groupofuniquenames +objectclass: top + ######################## # Permissions ######################## @@ -430,9 +440,9 @@ objectclass: permissiongroup objectclass: groupofuniquenames objectclass: top -dn: permission=perm:other,cn=permissions,OU=Test,O=TASKANA +dn: permission=perm/other,cn=permissions,OU=Test,O=TASKANA uniquemember: uid=user-1-2,cn=users,OU=Test,O=TASKANA -permission: perm:other +permission: perm/other cn: g01 objectclass: permissiongroup objectclass: groupofuniquenames diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/AccessIdController.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/AccessIdController.java index 44534feb8f..e6cc5ca098 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/AccessIdController.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/AccessIdController.java @@ -1,6 +1,7 @@ package pro.taskana.common.rest; import java.util.List; +import javax.naming.InvalidNameException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.config.EnableHypermediaSupport; import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType; @@ -37,12 +38,13 @@ public AccessIdController(LdapClient ldapClient, TaskanaEngine taskanaEngine) { * @throws InvalidArgumentException if the provided search for Access Id is shorter than the * configured one. * @throws NotAuthorizedException if the current user is not ADMIN or BUSINESS_ADMIN. + * @throws InvalidNameException if name is not a valid dn. * @title Search for Access Id (users and groups and permissions) */ @GetMapping(path = RestEndpoints.URL_ACCESS_ID) public ResponseEntity> searchUsersAndGroupsAndPermissions( @RequestParam("search-for") String searchFor) - throws InvalidArgumentException, NotAuthorizedException { + throws InvalidArgumentException, NotAuthorizedException, InvalidNameException { taskanaEngine.checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.BUSINESS_ADMIN); List accessIdUsers = @@ -89,12 +91,13 @@ public ResponseEntity> searchUsersByNameOrAcce * @return a list of the group Access Ids the requested Access Id belongs to * @throws InvalidArgumentException if the requested Access Id does not exist or is not unique. * @throws NotAuthorizedException if the current user is not ADMIN or BUSINESS_ADMIN. + * @throws InvalidNameException if name is not a valid dn. * @title Get groups for Access Id */ @GetMapping(path = RestEndpoints.URL_ACCESS_ID_GROUPS) public ResponseEntity> getGroupsByAccessId( @RequestParam("access-id") String accessId) - throws InvalidArgumentException, NotAuthorizedException { + throws InvalidArgumentException, NotAuthorizedException, InvalidNameException { taskanaEngine.checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.BUSINESS_ADMIN); List accessIds = @@ -110,12 +113,13 @@ public ResponseEntity> getGroupsByAccessId( * @return a list of the permission Access Ids the requested Access Id belongs to * @throws InvalidArgumentException if the requested Access Id does not exist or is not unique. * @throws NotAuthorizedException if the current user is not ADMIN or BUSINESS_ADMIN. + * @throws InvalidNameException if name is not a valid dn. * @title Get permissions for Access Id */ @GetMapping(path = RestEndpoints.URL_ACCESS_ID_PERMISSIONS) public ResponseEntity> getPermissionsByAccessId( @RequestParam("access-id") String accessId) - throws InvalidArgumentException, NotAuthorizedException { + throws InvalidArgumentException, NotAuthorizedException, InvalidNameException { taskanaEngine.checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.BUSINESS_ADMIN); List accessIds = diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/ldap/LdapClient.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/ldap/LdapClient.java index 741df404b8..41c0dec604 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/ldap/LdapClient.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/ldap/LdapClient.java @@ -13,7 +13,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.naming.InvalidNameException; import javax.naming.directory.SearchControls; +import javax.naming.ldap.LdapName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -69,9 +71,10 @@ public LdapClient( * @return a list of AccessIdResources sorted by AccessId and limited to * maxNumberOfReturnedAccessIds * @throws InvalidArgumentException if input is shorter than minSearchForLength + * @throws InvalidNameException thrown if name is not a valid dn */ public List searchUsersAndGroupsAndPermissions(final String name) - throws InvalidArgumentException { + throws InvalidArgumentException, InvalidNameException { isInitOrFail(); testMinSearchForLength(name); @@ -253,7 +256,8 @@ public List searchPermissionsByName(final String na new PermissionContextMapper()); } - public AccessIdRepresentationModel searchAccessIdByDn(final String dn) { + public AccessIdRepresentationModel searchAccessIdByDn(final String dn) + throws InvalidNameException { isInitOrFail(); // Obviously Spring LdapTemplate does have a inconsistency and always adds the base name to the // given DN. @@ -266,12 +270,13 @@ public AccessIdRepresentationModel searchAccessIdByDn(final String dn) { "Removed baseDN {} from given DN. New DN to be used: {}", getBaseDn(), nameWithoutBaseDn); } return ldapTemplate.lookup( - nameWithoutBaseDn, getLookUpUserAndGroupAndPermissionAttributesToReturn(), + new LdapName(nameWithoutBaseDn), + getLookUpUserAndGroupAndPermissionAttributesToReturn(), new DnContextMapper()); } public List searchGroupsAccessIdIsMemberOf(final String accessId) - throws InvalidArgumentException { + throws InvalidArgumentException, InvalidNameException { isInitOrFail(); testMinSearchForLength(accessId); @@ -310,7 +315,7 @@ public List searchGroupsAccessIdIsMemberOf(final St } public List searchPermissionsAccessIdHas(final String accessId) - throws InvalidArgumentException { + throws InvalidArgumentException, InvalidNameException { isInitOrFail(); testMinSearchForLength(accessId); @@ -351,8 +356,10 @@ public List searchPermissionsAccessIdHas(final Stri * @param accessId The access id to lookup * @return the LDAP Distinguished Name for the access id * @throws InvalidArgumentException thrown if the given access id is ambiguous. + * @throws InvalidNameException thrown if name is not a valid dn */ - public String searchDnForAccessId(String accessId) throws InvalidArgumentException { + public String searchDnForAccessId(String accessId) + throws InvalidArgumentException, InvalidNameException { isInitOrFail(); if (nameIsDn(accessId)) { @@ -419,8 +426,9 @@ public String searchDnForAccessId(String accessId) throws InvalidArgumentExcepti * * @param name lookup string for names or groups * @return whether the given name is valid or not + * @throws InvalidNameException thrown if name is not a valid dn */ - public boolean validateAccessId(final String name) { + public boolean validateAccessId(final String name) throws InvalidNameException { isInitOrFail(); if (nameIsDn(name)) { diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/AccessIdControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/AccessIdControllerIntTest.java index d00447bdee..ebc9b124dd 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/AccessIdControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/AccessIdControllerIntTest.java @@ -162,7 +162,7 @@ void should_ReturnAccessIdsOfPermissionsTheAccessIdIsMemberOf_ifAccessIdOfUserIs .extracting(AccessIdRepresentationModel::getAccessId) .usingElementComparator(String.CASE_INSENSITIVE_ORDER) .containsExactlyInAnyOrder("perm:userleads", - "perm:other"); + "perm/other"); } @Test diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/TaskanaEngineControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/TaskanaEngineControllerIntTest.java index f6bfc3687f..3f6e4cce9a 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/TaskanaEngineControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/TaskanaEngineControllerIntTest.java @@ -147,7 +147,7 @@ void testGetCurrentUserInfoWithPermission() { "cn=ksc-users,cn=groups,ou=test,o=taskana"); assertThat(response.getBody().getPermissionIds()) .containsExactlyInAnyOrder("perm:userleads", - "perm:other"); + "perm/other"); assertThat(response.getBody().getRoles()) .contains(TaskanaRole.USER) .doesNotContain(TaskanaRole.ADMIN); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/ldap/LdapClientTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/ldap/LdapClientTest.java index 570fe2fcc5..33be465e9d 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/ldap/LdapClientTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/common/rest/ldap/LdapClientTest.java @@ -20,6 +20,8 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; +import javax.naming.InvalidNameException; +import javax.naming.ldap.LdapName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -57,14 +59,14 @@ class LdapClientTest { + "permission=developers:permission,cn=permissions" }, delimiter = ';') void should_SearchGroupOrPermissionByDnAndConvertAccessIdToLowercase_For_LdapCall(String arg1, - String arg2) { + String arg2) throws InvalidNameException { setUpEnvMock(); cut.init(); cut.searchAccessIdByDn(arg1); verify(ldapTemplate) - .lookup(eq(arg2), any(), any(LdapClient.DnContextMapper.class)); + .lookup(eq(new LdapName(arg2)), any(), any(LdapClient.DnContextMapper.class)); } @Test @@ -153,7 +155,7 @@ void testLdap_getNameWithoutBaseDnForPermission() { @Test void shouldNot_CreateOrCriteriaWithDnAndAccessIdString_When_PropertyTypeIsSet() - throws InvalidArgumentException { + throws InvalidArgumentException, InvalidNameException { setUpEnvMock(); lenient().when(this.environment.getProperty("taskana.ldap.groupsOfUser.type"))