Closes #2563 - add handling of permissions as access ids
Co-authored-by: SebastianRoseneck <55637012+SebastianRoseneck@users.noreply.github.com> Co-authored-by: ryzheboka <025465835+ryzheboka@users.noreply.github.com>
This commit is contained in:
parent
683068aad6
commit
31100a54dd
|
@ -1,7 +1,6 @@
|
|||
-- sample-data is used for rest tests and for the example application
|
||||
|
||||
--SERT INTO WORKBASKET_ACCESS_LIST VALUES (ID , WB_ID , ACCESS_ID , ACCESS_NAME , READ , OPEN , APPEND, TRANSFER, DISTRIBUTE, C1 , C2 , C3 , C4 , C5 , C6 , C7 , C8 , C9 , C10 , C11 , C12 , READTASKS, EDITTASKS)
|
||||
-- KSC authorizations
|
||||
-- KSC authorizations (ID , WB_ID , ACCESS_ID , ACCESS_NAME , READ , OPEN , APPEND, TRANSFER, DISTRIBUTE, C1, .., C12)
|
||||
-- PPKs
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000001', 'WBI:100000000000000000000000000000000004', 'teamlead-1' , 'Titus Toll' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true);
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000002', 'WBI:100000000000000000000000000000000005', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true);
|
||||
|
@ -37,7 +36,6 @@ INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:10000000000000000000000000000000
|
|||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000017', 'WBI:100000000000000000000000000000000008', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , false, false , false , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true);
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000018', 'WBI:100000000000000000000000000000000009', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , false, true , false , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true);
|
||||
|
||||
--SERT INTO WORKBASKET_ACCESS_LIST VALUES (ID , WB_ID , ACCESS_ID , ACCESS_NAME , READ , OPEN , APPEND, TRANSFER, DISTRIBUTE, C1 , C2 , C3 , C4 , C5 , C6 , C7 , C8 , C9 , C10 , C11 , C12 ,READTASKS, EDITTASKS)
|
||||
-- Team GPK access
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000019', 'WBI:100000000000000000000000000000000002', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true);
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000020', 'WBI:100000000000000000000000000000000003', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true);
|
||||
|
@ -64,3 +62,8 @@ INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:00000000000000000000000000000000
|
|||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000907', 'WBI:000000000000000000000000000000000907', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true);
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000908', 'WBI:000000000000000000000000000000000908', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true);
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000909', 'WBI:000000000000000000000000000000000909', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true);
|
||||
|
||||
-- permissions
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:200000000000000000000000000000000002', 'WBI:100000000000000000000000000000000005', 'taskana:callcenter:ab:ab/a:callcenter' , 'PERM_1' , true , true , true , false , true , false, false, false, false, false, false, false, false, false, false, false, false, true , false);
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:200000000000000000000000000000000003', 'WBI:100000000000000000000000000000000006', 'taskana:callcenter:ab:AB/a:callcenter' , 'PERM_1' , true , false, true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true );
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:200000000000000000000000000000000005', 'WBI:100000000000000000000000000000000012', 'taskana:callcenter:ab:AB/a:callcenter' , 'PERM_1' , true , false, true , false , false , false, false, false, false, false, false, false, false, false, false, false, false, false , false);
|
||||
|
|
|
@ -51,3 +51,8 @@ INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:00000000000000000000000000000000
|
|||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000907', 'WBI:000000000000000000000000000000000907', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true);
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000908', 'WBI:000000000000000000000000000000000908', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true);
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000909', 'WBI:000000000000000000000000000000000909', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true);
|
||||
|
||||
-- permissions
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:200000000000000000000000000000000002', 'WBI:100000000000000000000000000000000005', 'taskana:callcenter:ab:ab/a:callcenter' , 'PERM_1' , true , true , true , false , true , false, false, false, false, false, false, false, false, false, false, false, false, true , false);
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:200000000000000000000000000000000003', 'WBI:100000000000000000000000000000000006', 'taskana:callcenter:ab:ab/a:callcenter' , 'PERM_1' , true , false, true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true );
|
||||
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:200000000000000000000000000000000005', 'WBI:100000000000000000000000000000000012', 'taskana:callcenter:ab:ab/a:callcenter' , 'PERM_1' , true , false, true , false , false , false, false, false, false, false, false, false, false, false, false, false, false, false , false);
|
||||
|
|
|
@ -16,6 +16,8 @@ public @interface WithAccessId {
|
|||
|
||||
String[] groups() default {};
|
||||
|
||||
String[] permissions() default {};
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@interface WithAccessIds {
|
||||
|
|
|
@ -7,7 +7,6 @@ import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -215,11 +214,12 @@ class JaasExtensionTest {
|
|||
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo(accessId.user());
|
||||
}
|
||||
|
||||
@WithAccessId(user = "testtemplate1", groups = "abc")
|
||||
@WithAccessId(user = "testtemplate1", groups = "abc", permissions = "perm")
|
||||
@TestTemplate
|
||||
void should_InjectCorrectAccessId_When_AnnotationExists_On_TestTemplate(WithAccessId accessId) {
|
||||
assertThat(accessId.user()).isEqualTo("testtemplate1");
|
||||
assertThat(accessId.groups()).containsExactly("abc");
|
||||
assertThat(accessId.permissions()).containsExactly("perm");
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
@ -406,21 +406,21 @@ class JaasExtensionTest {
|
|||
|
||||
@TestFactory
|
||||
Iterable<DynamicTest> should_NotSetAccessIdForDynamicTestInIterable_When_AnnotationIsMissing() {
|
||||
return Stream.of(NULL_DYNAMIC_TEST, NULL_DYNAMIC_TEST).collect(Collectors.toList());
|
||||
return Stream.of(NULL_DYNAMIC_TEST, NULL_DYNAMIC_TEST).toList();
|
||||
}
|
||||
|
||||
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||
@TestFactory
|
||||
Iterable<DynamicTest> should_SetAccessIdForDynamicTestInIterable_When_AnnotationExists() {
|
||||
return Stream.of(DYNAMIC_TEST_USER_DYNAMIC_TEST, DYNAMIC_TEST_USER_DYNAMIC_TEST)
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
}
|
||||
|
||||
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||
@TestFactory
|
||||
Iterable<DynamicTest> should_SetMultipleAccessIdForDynamicTestInIterable_When_AnnotationsExist() {
|
||||
return Stream.of(NOT_NULL_DYNAMIC_TEST, NOT_NULL_DYNAMIC_TEST).collect(Collectors.toList());
|
||||
return Stream.of(NOT_NULL_DYNAMIC_TEST, NOT_NULL_DYNAMIC_TEST).toList();
|
||||
}
|
||||
|
||||
// WITH DynamicContainer
|
||||
|
@ -431,7 +431,7 @@ class JaasExtensionTest {
|
|||
Supplier<DynamicContainer> supplier =
|
||||
() ->
|
||||
dynamicContainer("dynamic container", Stream.of(NULL_DYNAMIC_TEST, NULL_DYNAMIC_TEST));
|
||||
return Stream.generate(supplier).limit(2).collect(Collectors.toList());
|
||||
return Stream.generate(supplier).limit(2).toList();
|
||||
}
|
||||
|
||||
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||
|
@ -443,7 +443,7 @@ class JaasExtensionTest {
|
|||
dynamicContainer(
|
||||
"dynamic container",
|
||||
Stream.of(DYNAMIC_TEST_USER_DYNAMIC_TEST, DYNAMIC_TEST_USER_DYNAMIC_TEST));
|
||||
return Stream.generate(supplier).limit(2).collect(Collectors.toList());
|
||||
return Stream.generate(supplier).limit(2).toList();
|
||||
}
|
||||
|
||||
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||
|
@ -455,7 +455,7 @@ class JaasExtensionTest {
|
|||
() ->
|
||||
dynamicContainer(
|
||||
"dynamic container", Stream.of(NOT_NULL_DYNAMIC_TEST, NOT_NULL_DYNAMIC_TEST));
|
||||
return Stream.generate(supplier).limit(2).collect(Collectors.toList());
|
||||
return Stream.generate(supplier).limit(2).toList();
|
||||
}
|
||||
|
||||
// WITH nested DynamicContainer
|
||||
|
@ -467,7 +467,7 @@ class JaasExtensionTest {
|
|||
() -> dynamicContainer("inside container", Stream.of(NULL_DYNAMIC_TEST, NULL_DYNAMIC_TEST));
|
||||
Supplier<DynamicContainer> outsideSupplier =
|
||||
() -> dynamicContainer("outside container", Stream.of(supplier.get(), NULL_DYNAMIC_TEST));
|
||||
return Stream.generate(outsideSupplier).limit(2).collect(Collectors.toList());
|
||||
return Stream.generate(outsideSupplier).limit(2).toList();
|
||||
}
|
||||
|
||||
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||
|
@ -483,7 +483,7 @@ class JaasExtensionTest {
|
|||
() ->
|
||||
dynamicContainer(
|
||||
"outside container", Stream.of(supplier.get(), DYNAMIC_TEST_USER_DYNAMIC_TEST));
|
||||
return Stream.generate(outsideSupplier).limit(2).collect(Collectors.toList());
|
||||
return Stream.generate(outsideSupplier).limit(2).toList();
|
||||
}
|
||||
|
||||
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||
|
@ -498,7 +498,7 @@ class JaasExtensionTest {
|
|||
Supplier<DynamicContainer> outsideSupplier =
|
||||
() ->
|
||||
dynamicContainer("outside container", Stream.of(supplier.get(), NOT_NULL_DYNAMIC_TEST));
|
||||
return Stream.generate(outsideSupplier).limit(2).collect(Collectors.toList());
|
||||
return Stream.generate(outsideSupplier).limit(2).toList();
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
|
|
@ -34,6 +34,12 @@ taskana.ldap.groupNameAttribute=cn
|
|||
taskana.ldap.minSearchForLength=3
|
||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||
taskana.ldap.groupsOfUser=memberUid
|
||||
taskana.ldap.permissionSearchBase=cn=groups
|
||||
taskana.ldap.permissionSearchFilterName=objectclass
|
||||
taskana.ldap.permissionSearchFilterValue=groupofuniquenames
|
||||
taskana.ldap.permissionNameAttribute=permission
|
||||
taskana.ldap.permissionsOfUser=uniquemember
|
||||
taskana.ldap.useDnForGroups=true
|
||||
# Embedded Spring LDAP server
|
||||
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
||||
spring.ldap.embedded.credential.username=uid=admin
|
||||
|
|
|
@ -39,6 +39,8 @@ public abstract class AbstractAccTest {
|
|||
"cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA";
|
||||
public static final String GROUP_2_DN =
|
||||
"cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA";
|
||||
public static final String PERM_1 =
|
||||
"taskana:callcenter:ab:ab/a:callcenter";
|
||||
|
||||
protected static TaskanaConfiguration taskanaConfiguration;
|
||||
protected static TaskanaEngine taskanaEngine;
|
||||
|
|
|
@ -34,7 +34,7 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
|||
|
||||
columnValueList =
|
||||
workbasketService.createWorkbasketAccessItemQuery().listValues(ACCESS_ID, null);
|
||||
assertThat(columnValueList).hasSize(10);
|
||||
assertThat(columnValueList).hasSize(11);
|
||||
|
||||
columnValueList =
|
||||
workbasketService.createWorkbasketAccessItemQuery().listValues(WORKBASKET_KEY, null);
|
||||
|
@ -51,9 +51,9 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
|||
List<WorkbasketAccessItem> results =
|
||||
workbasketService
|
||||
.createWorkbasketAccessItemQuery()
|
||||
.accessIdIn("user-1-1", GROUP_1_DN)
|
||||
.accessIdIn("user-1-1", GROUP_1_DN, PERM_1)
|
||||
.list();
|
||||
assertThat(results).hasSize(8);
|
||||
assertThat(results).hasSize(11);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "unknownuser")
|
||||
|
@ -78,12 +78,12 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
|||
WorkbasketAccessItemQuery query =
|
||||
workbasketService
|
||||
.createWorkbasketAccessItemQuery()
|
||||
.accessIdIn("user-1-1", GROUP_1_DN)
|
||||
.accessIdIn("user-1-1", GROUP_1_DN, PERM_1)
|
||||
.orderByAccessId(SortDirection.DESCENDING)
|
||||
.orderByWorkbasketId(SortDirection.DESCENDING);
|
||||
List<WorkbasketAccessItem> results = query.list();
|
||||
long count = query.count();
|
||||
assertThat(results).hasSize(8).size().isEqualTo(count);
|
||||
assertThat(results).hasSize(11).size().isEqualTo(count);
|
||||
assertThat(results.get(0).getId()).isEqualTo("WAI:100000000000000000000000000000000003");
|
||||
}
|
||||
|
||||
|
@ -94,12 +94,13 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
|||
List<WorkbasketAccessItem> results =
|
||||
workbasketService
|
||||
.createWorkbasketAccessItemQuery()
|
||||
.accessIdIn("user-1-1", GROUP_1_DN)
|
||||
.accessIdIn("user-1-1", GROUP_1_DN, PERM_1)
|
||||
.workbasketIdIn(
|
||||
"WBI:100000000000000000000000000000000006",
|
||||
"WBI:100000000000000000000000000000000002")
|
||||
"WBI:100000000000000000000000000000000002",
|
||||
"WBI:100000000000000000000000000000000005")
|
||||
.list();
|
||||
assertThat(results).hasSize(3);
|
||||
assertThat(results).hasSize(5);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
|
@ -135,7 +136,7 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
|||
.createWorkbasketAccessItemQuery()
|
||||
.workbasketIdIn("WBI:100000000000000000000000000000000006")
|
||||
.list();
|
||||
assertThat(results).hasSize(3);
|
||||
assertThat(results).hasSize(4);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
|
@ -149,7 +150,7 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
|||
.orderByWorkbasketId(SortDirection.DESCENDING)
|
||||
.orderByAccessId(SortDirection.ASCENDING)
|
||||
.list();
|
||||
assertThat(results).hasSize(3);
|
||||
assertThat(results).hasSize(4);
|
||||
assertThat(results.get(0).getId()).isEqualTo("WAI:100000000000000000000000000000000009");
|
||||
}
|
||||
|
||||
|
@ -160,7 +161,7 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
|||
String[] expectedIds = {
|
||||
"WAI:100000000000000000000000000000000001",
|
||||
"WAI:100000000000000000000000000000000015",
|
||||
"WAI:100000000000000000000000000000000007"
|
||||
"WAI:100000000000000000000000000000000006"
|
||||
};
|
||||
List<WorkbasketAccessItem> results =
|
||||
workbasketService.createWorkbasketAccessItemQuery().idIn(expectedIds).list();
|
||||
|
|
|
@ -70,20 +70,21 @@ class QueryWorkbasketByPermissionAccTest extends AbstractAccTest {
|
|||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
@Test
|
||||
void should_GetAllTransferTargetsForUserAndGroup_When_QueryingForSinglePermission()
|
||||
void should_GetAllTransferTargetsForUserGroupPermission_When_QueryingForSinglePermission()
|
||||
throws Exception {
|
||||
List<WorkbasketSummary> results =
|
||||
WORKBASKET_SERVICE
|
||||
.createWorkbasketQuery()
|
||||
.accessIdsHavePermissions(List.of(WorkbasketPermission.APPEND), "user-1-1", GROUP_1_DN)
|
||||
.accessIdsHavePermissions(List.of(WorkbasketPermission.APPEND), "user-1-1",
|
||||
GROUP_1_DN, PERM_1)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(6);
|
||||
assertThat(results).hasSize(7);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
@Test
|
||||
void should_GetAllTransferTargetsForUserAndGroup_When_QueryingForMultiplePermissions()
|
||||
void should_GetAllTransferTargetsForUserGroupPermission_When_QueryingForMultiplePermissions()
|
||||
throws Exception {
|
||||
List<WorkbasketSummary> results =
|
||||
WORKBASKET_SERVICE
|
||||
|
@ -91,21 +92,37 @@ class QueryWorkbasketByPermissionAccTest extends AbstractAccTest {
|
|||
.accessIdsHavePermissions(
|
||||
List.of(WorkbasketPermission.APPEND, WorkbasketPermission.OPEN),
|
||||
"user-1-1",
|
||||
GROUP_1_DN)
|
||||
GROUP_1_DN, PERM_1)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(4);
|
||||
assertThat(results).hasSize(5);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
@Test
|
||||
void should_GetAllWorkbasketsForUserAndGroup_When_QueryingForReadTasksPermissions()
|
||||
void should_GetAllWorkbasketsForUserGroupPermission_When_QueryingForReadTasksPermissions()
|
||||
throws Exception {
|
||||
List<WorkbasketSummary> results =
|
||||
WORKBASKET_SERVICE
|
||||
.createWorkbasketQuery()
|
||||
.accessIdsHavePermissions(
|
||||
List.of(WorkbasketPermission.READTASKS), "user-1-1", GROUP_1_DN)
|
||||
List.of(WorkbasketPermission.READTASKS), "user-1-1",
|
||||
GROUP_1_DN, PERM_1)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(8);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
@Test
|
||||
void should_GetAllWorkbasketsForUserGroupPermission_When_QueryingForEditTasksPermissions()
|
||||
throws Exception {
|
||||
List<WorkbasketSummary> results =
|
||||
WORKBASKET_SERVICE
|
||||
.createWorkbasketQuery()
|
||||
.accessIdsHavePermissions(
|
||||
List.of(WorkbasketPermission.EDITTASKS), "user-1-1",
|
||||
GROUP_1_DN, PERM_1)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(7);
|
||||
|
@ -113,63 +130,52 @@ class QueryWorkbasketByPermissionAccTest extends AbstractAccTest {
|
|||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
@Test
|
||||
void should_GetAllWorkbasketsForUserAndGroup_When_QueryingForEditTasksPermissions()
|
||||
void should_GetAllTransferTargetsForUserGroupPermission_When_QueryingForSortedByNameAscending()
|
||||
throws Exception {
|
||||
List<WorkbasketSummary> results =
|
||||
WORKBASKET_SERVICE
|
||||
.createWorkbasketQuery()
|
||||
.accessIdsHavePermissions(
|
||||
List.of(WorkbasketPermission.READTASKS), "user-1-1", GROUP_1_DN)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(7);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
@Test
|
||||
void should_GetAllTransferTargetsForUserAndGroup_When_QueryingForSortedByNameAscending()
|
||||
throws Exception {
|
||||
List<WorkbasketSummary> results =
|
||||
WORKBASKET_SERVICE
|
||||
.createWorkbasketQuery()
|
||||
.accessIdsHavePermissions(List.of(WorkbasketPermission.APPEND), "user-1-1", GROUP_1_DN)
|
||||
.accessIdsHavePermissions(List.of(WorkbasketPermission.APPEND),
|
||||
"user-1-1", GROUP_1_DN, PERM_1)
|
||||
.orderByName(SortDirection.ASCENDING)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(6);
|
||||
assertThat(results).hasSize(7);
|
||||
assertThat(results.get(0).getKey()).isEqualTo("GPK_KSC_1");
|
||||
}
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
@Test
|
||||
void should_GetAllTransferTargetsForUserAndGroup_When_QueryingForSortedByNameDescending()
|
||||
void should_GetAllTransferTargetsForUserGroupPermission_When_QueryingForSortedByNameDescending()
|
||||
throws Exception {
|
||||
List<WorkbasketSummary> results =
|
||||
WORKBASKET_SERVICE
|
||||
.createWorkbasketQuery()
|
||||
.accessIdsHavePermissions(List.of(WorkbasketPermission.APPEND), "user-1-1", GROUP_1_DN)
|
||||
.accessIdsHavePermissions(List.of(WorkbasketPermission.APPEND),
|
||||
"user-1-1", GROUP_1_DN, PERM_1)
|
||||
.orderByName(SortDirection.DESCENDING)
|
||||
.orderByKey(SortDirection.ASCENDING)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(6);
|
||||
assertThat(results).hasSize(7);
|
||||
assertThat(results.get(0).getKey()).isEqualTo("USER-2-2");
|
||||
}
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
@Test
|
||||
void should_GetAllTransferSourcesForUserAndGroup_When_QueryingForSinglePermission()
|
||||
void should_GetAllTransferSourcesForUserGroupPermission_When_QueryingForSinglePermission()
|
||||
throws Exception {
|
||||
List<WorkbasketSummary> results =
|
||||
WORKBASKET_SERVICE
|
||||
.createWorkbasketQuery()
|
||||
.accessIdsHavePermissions(
|
||||
List.of(WorkbasketPermission.DISTRIBUTE), "user-1-1", GROUP_1_DN)
|
||||
List.of(WorkbasketPermission.DISTRIBUTE),
|
||||
"user-1-1", GROUP_1_DN, PERM_1)
|
||||
.list();
|
||||
|
||||
assertThat(results)
|
||||
.extracting(WorkbasketSummary::getKey)
|
||||
.containsExactlyInAnyOrder("GPK_KSC_1", "USER-1-1");
|
||||
.containsExactlyInAnyOrder("GPK_KSC_1", "USER-1-1", "TEAMLEAD-2");
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
@ -224,28 +230,28 @@ class QueryWorkbasketByPermissionAccTest extends AbstractAccTest {
|
|||
assertThat(results).hasSize(3);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-1", groups = GROUP_1_DN)
|
||||
@WithAccessId(user = "user-1-1", groups = {GROUP_1_DN, PERM_1})
|
||||
@Test
|
||||
void should_GetAllTransferTargetsForSubjectUserAndGroup_When_QueryingForSinglePermission() {
|
||||
void should_GetAllTransferTargetsForSubjectUserGroupPerm_When_QueryingForSinglePermission() {
|
||||
List<WorkbasketSummary> results =
|
||||
WORKBASKET_SERVICE
|
||||
.createWorkbasketQuery()
|
||||
.callerHasPermissions(WorkbasketPermission.APPEND)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(6);
|
||||
assertThat(results).hasSize(7);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-1", groups = GROUP_1_DN)
|
||||
@WithAccessId(user = "user-1-1", groups = {GROUP_1_DN, PERM_1})
|
||||
@Test
|
||||
void should_GetAllTransferTargetsForSubjectUserAndGroup_When_QueryingForMultiplePermissions() {
|
||||
void should_GetAllTransferTargetsForSubjectUserGroupPerm_When_QueryingForMultiplePermissions() {
|
||||
List<WorkbasketSummary> results =
|
||||
WORKBASKET_SERVICE
|
||||
.createWorkbasketQuery()
|
||||
.callerHasPermissions(WorkbasketPermission.APPEND, WorkbasketPermission.OPEN)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(4);
|
||||
assertThat(results).hasSize(5);
|
||||
}
|
||||
|
||||
@WithAccessId(user = "businessadmin")
|
||||
|
|
|
@ -31,7 +31,8 @@ class WorkbasketQueryAccTest extends AbstractAccTest {
|
|||
.createWorkbasketQuery()
|
||||
.nameLike("%")
|
||||
.accessIdsHavePermissions(
|
||||
List.of(WorkbasketPermission.TRANSFER), "teamlead-1", GROUP_1_DN, GROUP_2_DN)
|
||||
List.of(WorkbasketPermission.TRANSFER),
|
||||
"teamlead-1", GROUP_1_DN, GROUP_2_DN, PERM_1)
|
||||
.list();
|
||||
};
|
||||
assertThatThrownBy(call).isInstanceOf(NotAuthorizedException.class);
|
||||
|
@ -50,7 +51,8 @@ class WorkbasketQueryAccTest extends AbstractAccTest {
|
|||
.createWorkbasketQuery()
|
||||
.nameLike("%")
|
||||
.accessIdsHavePermissions(
|
||||
List.of(WorkbasketPermission.TRANSFER), "teamlead-1", GROUP_1_DN, GROUP_2_DN)
|
||||
List.of(WorkbasketPermission.TRANSFER),
|
||||
"teamlead-1", GROUP_1_DN, GROUP_2_DN, PERM_1)
|
||||
.list();
|
||||
};
|
||||
assertThatThrownBy(call).isInstanceOf(NotAuthorizedException.class);
|
||||
|
@ -69,7 +71,8 @@ class WorkbasketQueryAccTest extends AbstractAccTest {
|
|||
.createWorkbasketQuery()
|
||||
.nameLike("%")
|
||||
.accessIdsHavePermissions(
|
||||
List.of(WorkbasketPermission.TRANSFER), "teamlead-1", GROUP_1_DN, GROUP_2_DN)
|
||||
List.of(WorkbasketPermission.TRANSFER),
|
||||
"teamlead-1", GROUP_1_DN, GROUP_2_DN, PERM_1)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(13);
|
||||
|
@ -88,7 +91,8 @@ class WorkbasketQueryAccTest extends AbstractAccTest {
|
|||
.createWorkbasketQuery()
|
||||
.nameLike("%")
|
||||
.accessIdsHavePermissions(
|
||||
List.of(WorkbasketPermission.TRANSFER), "teamlead-1", GROUP_1_DN, GROUP_2_DN)
|
||||
List.of(WorkbasketPermission.TRANSFER),
|
||||
"teamlead-1", GROUP_1_DN, GROUP_2_DN, PERM_1)
|
||||
.list();
|
||||
|
||||
assertThat(results).hasSize(13);
|
||||
|
|
|
@ -15,6 +15,8 @@ public @interface WithAccessId {
|
|||
|
||||
String[] groups() default {};
|
||||
|
||||
String[] permissions() default {};
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@interface WithAccessIds {
|
||||
|
|
|
@ -38,6 +38,8 @@ public class BootWebSecurityConfigurer {
|
|||
private final String ldapUserDnPatterns;
|
||||
private final String ldapGroupSearchBase;
|
||||
private final String ldapGroupSearchFilter;
|
||||
private final String ldapPermissionSearchBase;
|
||||
private final String ldapPermissionSearchFilter;
|
||||
|
||||
private final boolean devMode;
|
||||
private final boolean enableCsrf;
|
||||
|
@ -48,6 +50,9 @@ public class BootWebSecurityConfigurer {
|
|||
@Value("${taskana.ldap.userDnPatterns:uid={0},cn=users}") String ldapUserDnPatterns,
|
||||
@Value("${taskana.ldap.groupSearchBase:cn=groups}") String ldapGroupSearchBase,
|
||||
@Value("${taskana.ldap.groupSearchFilter:uniqueMember={0}}") String ldapGroupSearchFilter,
|
||||
@Value("${taskana.ldap.permissionSearchBase:cn=permissions}") String ldapPermissionSearchBase,
|
||||
@Value("${taskana.ldap.permissionSearchFilter:uniqueMember={0}}")
|
||||
String ldapPermissionSearchFilter,
|
||||
@Value("${enableCsrf:false}") boolean enableCsrf,
|
||||
@Value("${devMode:false}") boolean devMode) {
|
||||
this.enableCsrf = enableCsrf;
|
||||
|
@ -55,6 +60,8 @@ public class BootWebSecurityConfigurer {
|
|||
this.ldapBaseDn = ldapBaseDn;
|
||||
this.ldapGroupSearchBase = ldapGroupSearchBase;
|
||||
this.ldapGroupSearchFilter = ldapGroupSearchFilter;
|
||||
this.ldapPermissionSearchBase = ldapPermissionSearchBase;
|
||||
this.ldapPermissionSearchFilter = ldapPermissionSearchFilter;
|
||||
this.ldapUserDnPatterns = ldapUserDnPatterns;
|
||||
this.devMode = devMode;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,12 @@ taskana.ldap.groupNameAttribute=cn
|
|||
taskana.ldap.minSearchForLength=3
|
||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||
taskana.ldap.groupsOfUser=uniquemember
|
||||
taskana.ldap.permissionSearchBase=
|
||||
taskana.ldap.permissionSearchFilterName=objectclass
|
||||
taskana.ldap.permissionSearchFilterValue=groupofuniquenames
|
||||
taskana.ldap.permissionNameAttribute=permission
|
||||
taskana.ldap.permissionsOfUser=uniquemember
|
||||
taskana.ldap.useDnForGroups=true
|
||||
# Embedded Spring LDAP server
|
||||
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
||||
spring.ldap.embedded.credential.username=uid=admin
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
{
|
||||
"EN": {
|
||||
"global": {
|
||||
"debounceTimeLookupField": 750
|
||||
},
|
||||
"workbaskets": {
|
||||
"information": {
|
||||
"owner": {
|
||||
|
|
|
@ -11,6 +11,11 @@ cn: groups
|
|||
objectclass: top
|
||||
objectclass: container
|
||||
|
||||
dn: cn=permissions,OU=Test,O=TASKANA
|
||||
cn: permissions
|
||||
objectclass: top
|
||||
objectclass: container
|
||||
|
||||
dn: cn=users,OU=Test,O=TASKANA
|
||||
cn: users
|
||||
objectclass: top
|
||||
|
@ -109,8 +114,6 @@ sn: Toll
|
|||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||
cn: Titus Toll
|
||||
userPassword: teamlead-1
|
||||
permission: organize
|
||||
permission: inet
|
||||
|
||||
dn: uid=user-1-1,cn=users,OU=Test,O=TASKANA
|
||||
objectclass: inetorgperson
|
||||
|
@ -126,8 +129,6 @@ sn: Mustermann
|
|||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||
cn: Max Mustermann
|
||||
userPassword: user-1-1
|
||||
permission: organize
|
||||
permission: inet
|
||||
|
||||
dn: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
||||
objectclass: inetorgperson
|
||||
|
@ -137,15 +138,14 @@ objectclass: top
|
|||
givenName: Elena
|
||||
description: desc
|
||||
memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter-vip
|
||||
memberOf: cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||
uid: user-1-2
|
||||
sn: Eifrig
|
||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||
cn: Elena Eifrig
|
||||
userPassword: user-1-2
|
||||
permission: organize
|
||||
permission: inet
|
||||
permission: program
|
||||
|
||||
dn: uid=user-1-3,cn=users,OU=Test,O=TASKANA
|
||||
objectclass: inetorgperson
|
||||
|
@ -189,6 +189,7 @@ givenName: Simone
|
|||
description: desc
|
||||
memberOf: cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||
memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
uid: user-2-1
|
||||
sn: Müller
|
||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||
|
@ -223,9 +224,6 @@ sn: Bach
|
|||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||
cn: Thomas Bach
|
||||
userPassword: user-2-3
|
||||
permission: organize
|
||||
permission: inet
|
||||
permission: program
|
||||
|
||||
dn: uid=user-2-4,cn=users,OU=Test,O=TASKANA
|
||||
objectclass: inetorgperson
|
||||
|
@ -282,9 +280,6 @@ sn: Meyer
|
|||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||
cn: Wiebke Meyer
|
||||
userPassword: user-2-7
|
||||
permission: organize
|
||||
permission: inet
|
||||
permission: manage
|
||||
|
||||
dn: uid=user-2-8,cn=users,OU=Test,O=TASKANA
|
||||
objectclass: inetorgperson
|
||||
|
@ -370,10 +365,6 @@ sn: Bio
|
|||
ou: Organisationseinheit/Organisationseinheit B
|
||||
cn: Brunhilde Bio
|
||||
userPassword: user-b-2
|
||||
permission: organize
|
||||
permission: inet
|
||||
permission: siegen
|
||||
permission: frieden
|
||||
|
||||
########################
|
||||
# Users in other cn
|
||||
|
@ -426,6 +417,25 @@ cn: monitor-users
|
|||
objectclass: groupofuniquenames
|
||||
objectclass: top
|
||||
|
||||
########################
|
||||
# Permissions
|
||||
########################
|
||||
|
||||
dn: cn=g01,cn=groups,OU=Test,O=TASKANA
|
||||
uniquemember: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
||||
uniquemember: uid=user-2-1,cn=users,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
cn: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
objectclass: groupofuniquenames
|
||||
objectclass: top
|
||||
|
||||
dn: cn=g02,cn=groups,OU=Test,O=TASKANA
|
||||
uniquemember: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter-vip
|
||||
cn: g02
|
||||
objectclass: groupofuniquenames
|
||||
objectclass: top
|
||||
|
||||
######################
|
||||
# Organizational Units
|
||||
######################
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package pro.taskana.example.ldap;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import pro.taskana.common.rest.models.AccessIdRepresentationModel;
|
||||
import pro.taskana.rest.test.TaskanaSpringBootTest;
|
||||
|
||||
/** Test Ldap attachment. */
|
||||
@TaskanaSpringBootTest
|
||||
@TestPropertySource(properties = "taskana.ldap.useDnForGroups=false")
|
||||
@ActiveProfiles({"emptySearchRoots"})
|
||||
class LdapEmptySearchRootsForUseDnForGroupsDisabledTest
|
||||
extends LdapForUseDnForGroupsDisabledTest {
|
||||
|
||||
@Test
|
||||
void should_FindGroupsForUser_When_UserIdIsProvided() throws Exception {
|
||||
List<AccessIdRepresentationModel> groups =
|
||||
ldapClient.searchGroupsAccessIdIsMemberOf("user-2-2");
|
||||
assertThat(groups)
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.containsExactlyInAnyOrder(
|
||||
"ksc-users", "organisationseinheit ksc 2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_FindPermissionsForUser_When_UserIdIsProvided() throws Exception {
|
||||
List<AccessIdRepresentationModel> permissions =
|
||||
ldapClient.searchPermissionsAccessIdHas("user-1-2");
|
||||
assertThat(permissions)
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.containsExactlyInAnyOrder("taskana:callcenter:ab:ab/a:callcenter",
|
||||
"taskana:callcenter:ab:ab/a:callcenter-vip");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnFullDnForUser_When_AccessIdOfUserIsGiven() throws Exception {
|
||||
String dn = ldapClient.searchDnForAccessId("otheruser");
|
||||
assertThat(dn).isEqualTo("uid=otheruser,cn=other-users,ou=test,o=taskana");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnFullDnForPermission_When_AccessIdOfPermissionIsGiven() throws Exception {
|
||||
String dn = ldapClient.searchDnForAccessId("taskana:callcenter:ab:ab/a:callcenter-vip");
|
||||
assertThat(dn).isEqualTo("cn=g02,cn=groups,ou=test,o=taskana");
|
||||
}
|
||||
}
|
||||
|
|
@ -25,9 +25,25 @@ class LdapEmptySearchRootsTest extends LdapTest {
|
|||
+ "cn=organisation,ou=test,o=taskana");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_FindPermissionsForUser_When_UserIdIsProvided() throws Exception {
|
||||
List<AccessIdRepresentationModel> permissions =
|
||||
ldapClient.searchPermissionsAccessIdHas("user-1-2");
|
||||
assertThat(permissions)
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.containsExactlyInAnyOrder("taskana:callcenter:ab:ab/a:callcenter",
|
||||
"taskana:callcenter:ab:ab/a:callcenter-vip");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnFullDnForUser_When_AccessIdOfUserIsGiven() throws Exception {
|
||||
String dn = ldapClient.searchDnForAccessId("otheruser");
|
||||
assertThat(dn).isEqualTo("uid=otheruser,cn=other-users,ou=test,o=taskana");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnFullDnForPermission_When_AccessIdOfPermissionIsGiven() throws Exception {
|
||||
String dn = ldapClient.searchDnForAccessId("taskana:callcenter:ab:ab/a:callcenter-vip");
|
||||
assertThat(dn).isEqualTo("cn=g02,cn=groups,ou=test,o=taskana");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
package pro.taskana.example.ldap;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import pro.taskana.common.rest.ldap.LdapClient;
|
||||
import pro.taskana.common.rest.models.AccessIdRepresentationModel;
|
||||
import pro.taskana.rest.test.TaskanaSpringBootTest;
|
||||
import pro.taskana.user.api.models.User;
|
||||
|
||||
/** Test Ldap attachment. */
|
||||
@TestPropertySource(properties = "taskana.ldap.useDnForGroups=false")
|
||||
@TaskanaSpringBootTest
|
||||
class LdapForUseDnForGroupsDisabledTest {
|
||||
|
||||
@Autowired
|
||||
LdapClient ldapClient;
|
||||
|
||||
@Test
|
||||
void should_FindAllUsersAndGroupAndPermissions_When_SearchWithSubstringOfName() throws Exception {
|
||||
List<AccessIdRepresentationModel> usersGroupsPermissions =
|
||||
ldapClient.searchUsersAndGroupsAndPermissions("lead");
|
||||
assertThat(usersGroupsPermissions)
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.containsExactlyInAnyOrder(
|
||||
"teamlead-1", "teamlead-2", "ksc-teamleads");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_FindUser_When_SearchingWithFirstAndLastname() throws Exception {
|
||||
List<AccessIdRepresentationModel> usersGroupsPermissions =
|
||||
ldapClient.searchUsersAndGroupsAndPermissions("Elena");
|
||||
assertThat(usersGroupsPermissions).hasSize(2);
|
||||
|
||||
usersGroupsPermissions = ldapClient.searchUsersAndGroupsAndPermissions("Elena Faul");
|
||||
assertThat(usersGroupsPermissions).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_FindGroupsForUser_When_UserIdIsProvided() throws Exception {
|
||||
List<AccessIdRepresentationModel> groups =
|
||||
ldapClient.searchGroupsAccessIdIsMemberOf("user-2-2");
|
||||
assertThat(groups)
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.containsExactlyInAnyOrder("ksc-users");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_FindPermissionsForUser_When_UserIdIsProvided() throws Exception {
|
||||
List<AccessIdRepresentationModel> permissions =
|
||||
ldapClient.searchPermissionsAccessIdHas("user-1-2");
|
||||
assertThat(permissions)
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.containsExactlyInAnyOrder("taskana:callcenter:ab:ab/a:callcenter-vip",
|
||||
"taskana:callcenter:ab:ab/a:callcenter");
|
||||
assertThat(permissions)
|
||||
.extracting(AccessIdRepresentationModel::getName)
|
||||
.containsExactlyInAnyOrder("Taskana:CallCenter:AB:AB/A:CallCenter-vip",
|
||||
"Taskana:CallCenter:AB:AB/A:CallCenter");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnFullDnForUser_When_AccessIdOfUserIsGiven() throws Exception {
|
||||
String dn = ldapClient.searchDnForAccessId("user-2-2");
|
||||
assertThat(dn).isEqualTo("uid=user-2-2,cn=users,ou=test,o=taskana");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnAllUsersInUserRoleWithCorrectAttributes() {
|
||||
|
||||
Map<String, User> users =
|
||||
ldapClient.searchUsersInUserRole().stream()
|
||||
.collect(Collectors.toMap(User::getId, Function.identity()));
|
||||
|
||||
assertThat(users).hasSize(8);
|
||||
|
||||
User teamlead1 = users.get("teamlead-1");
|
||||
assertThat(teamlead1.getId()).isEqualTo("teamlead-1");
|
||||
assertThat(teamlead1.getFirstName()).isEqualTo("Titus");
|
||||
assertThat(teamlead1.getLastName()).isEqualTo("Toll");
|
||||
assertThat(teamlead1.getFullName()).isEqualTo("Titus Toll");
|
||||
assertThat(teamlead1.getEmail()).isEqualTo("Titus.Toll@taskana.de");
|
||||
assertThat(teamlead1.getPhone()).isEqualTo("012345678");
|
||||
assertThat(teamlead1.getMobilePhone()).isEqualTo("09876554321");
|
||||
assertThat(teamlead1.getOrgLevel1()).isEqualTo("ABC");
|
||||
assertThat(teamlead1.getOrgLevel2()).isEqualTo("DEF/GHI");
|
||||
assertThat(teamlead1.getOrgLevel3()).isEqualTo("JKL");
|
||||
assertThat(teamlead1.getOrgLevel4()).isEqualTo("MNO/PQR");
|
||||
|
||||
User user11 = users.get("user-1-1");
|
||||
assertThat(user11.getId()).isEqualTo("user-1-1");
|
||||
assertThat(user11.getFirstName()).isEqualTo("Max");
|
||||
assertThat(user11.getLastName()).isEqualTo("Mustermann");
|
||||
assertThat(user11.getFullName()).isEqualTo("Max Mustermann");
|
||||
assertThat(user11.getEmail()).isNull();
|
||||
assertThat(user11.getPhone()).isNull();
|
||||
assertThat(user11.getMobilePhone()).isNull();
|
||||
assertThat(user11.getOrgLevel1()).isNull();
|
||||
assertThat(user11.getOrgLevel2()).isNull();
|
||||
assertThat(user11.getOrgLevel3()).isNull();
|
||||
assertThat(user11.getOrgLevel4()).isNull();
|
||||
}
|
||||
}
|
||||
|
|
@ -20,9 +20,10 @@ class LdapTest {
|
|||
@Autowired LdapClient ldapClient;
|
||||
|
||||
@Test
|
||||
void should_FindAllUsersAndGroup_When_SearchWithSubstringOfName() throws Exception {
|
||||
List<AccessIdRepresentationModel> usersAndGroups = ldapClient.searchUsersAndGroups("lead");
|
||||
assertThat(usersAndGroups)
|
||||
void should_FindAllUsersAndGroupAndPermissions_When_SearchWithSubstringOfName() throws Exception {
|
||||
List<AccessIdRepresentationModel> usersGroupsPermissions =
|
||||
ldapClient.searchUsersAndGroupsAndPermissions("lead");
|
||||
assertThat(usersGroupsPermissions)
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.containsExactlyInAnyOrder(
|
||||
"teamlead-1", "teamlead-2", "cn=ksc-teamleads,cn=groups,ou=test,o=taskana");
|
||||
|
@ -30,11 +31,12 @@ class LdapTest {
|
|||
|
||||
@Test
|
||||
void should_FindUser_When_SearchingWithFirstAndLastname() throws Exception {
|
||||
List<AccessIdRepresentationModel> usersAndGroups = ldapClient.searchUsersAndGroups("Elena");
|
||||
assertThat(usersAndGroups).hasSize(2);
|
||||
List<AccessIdRepresentationModel> usersGroupsPermissions =
|
||||
ldapClient.searchUsersAndGroupsAndPermissions("Elena");
|
||||
assertThat(usersGroupsPermissions).hasSize(2);
|
||||
|
||||
usersAndGroups = ldapClient.searchUsersAndGroups("Elena Faul");
|
||||
assertThat(usersAndGroups).hasSize(1);
|
||||
usersGroupsPermissions = ldapClient.searchUsersAndGroupsAndPermissions("Elena Faul");
|
||||
assertThat(usersGroupsPermissions).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -46,6 +48,20 @@ class LdapTest {
|
|||
.containsExactlyInAnyOrder("cn=ksc-users,cn=groups,ou=test,o=taskana");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_FindPermissionsForUser_When_UserIdIsProvided() throws Exception {
|
||||
List<AccessIdRepresentationModel> permissions =
|
||||
ldapClient.searchPermissionsAccessIdHas("user-1-2");
|
||||
assertThat(permissions)
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.containsExactlyInAnyOrder("taskana:callcenter:ab:ab/a:callcenter-vip",
|
||||
"taskana:callcenter:ab:ab/a:callcenter");
|
||||
assertThat(permissions)
|
||||
.extracting(AccessIdRepresentationModel::getName)
|
||||
.containsExactlyInAnyOrder("Taskana:CallCenter:AB:AB/A:CallCenter-vip",
|
||||
"Taskana:CallCenter:AB:AB/A:CallCenter");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnFullDnForUser_When_AccessIdOfUserIsGiven() throws Exception {
|
||||
String dn = ldapClient.searchDnForAccessId("user-2-2");
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
taskana.ldap.userSearchBase=
|
||||
taskana.ldap.groupSearchBase=
|
||||
taskana.ldap.permissionSearchBase=
|
||||
|
|
|
@ -30,14 +30,21 @@ taskana.ldap.userOrglevel3Attribute=someDepartement
|
|||
taskana.ldap.userOrglevel4Attribute=orgLevel4
|
||||
taskana.ldap.userIdAttribute=uid
|
||||
taskana.ldap.userMemberOfGroupAttribute=memberOf
|
||||
taskana.ldap.userPermissionsAttribute=permission
|
||||
taskana.ldap.groupSearchBase=cn=groups
|
||||
taskana.ldap.groupSearchFilterName=objectclass
|
||||
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
||||
taskana.ldap.groupNameAttribute=cn
|
||||
taskana.ldap.groupsOfUser=uniquemember
|
||||
taskana.ldap.minSearchForLength=3
|
||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||
taskana.ldap.groupsOfUser=uniquemember
|
||||
taskana.ldap.userMemberOfPermissionAttribute=memberOf
|
||||
taskana.ldap.permissionSearchBase=
|
||||
taskana.ldap.permissionSearchFilterName=objectclass
|
||||
taskana.ldap.permissionSearchFilterValue=groupofuniquenames
|
||||
taskana.ldap.permissionNameAttribute=permission
|
||||
taskana.ldap.permissionsOfUser=uniquemember
|
||||
taskana.ldap.useDnForGroups=true
|
||||
taskana.ldap.userPermissionsAttribute=permission
|
||||
# Embedded Spring LDAP server
|
||||
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
||||
spring.ldap.embedded.credential.username=uid=admin
|
||||
|
|
|
@ -24,6 +24,12 @@ taskana.ldap.groupNameAttribute=cn
|
|||
taskana.ldap.minSearchForLength=3
|
||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||
taskana.ldap.groupsOfUser=uniquemember
|
||||
taskana.ldap.permissionSearchBase=
|
||||
taskana.ldap.permissionSearchFilterName=objectclass
|
||||
taskana.ldap.permissionSearchFilterValue=groupofuniquenames
|
||||
taskana.ldap.permissionNameAttribute=permission
|
||||
taskana.ldap.permissionsOfUser=uniquemember
|
||||
taskana.ldap.useDnForGroups=true
|
||||
|
||||
####### JobScheduler cron expression that specifies when the JobSchedler runs
|
||||
taskana.jobscheduler.async.cron=0 * * * * *
|
||||
|
|
|
@ -105,7 +105,7 @@ public class TaskanaWildflyWithUserConfigTest extends AbstractAccTest {
|
|||
TaskanaUserInfoRepresentationModel currentUser = response.getBody();
|
||||
assertThat(currentUser).isNotNull();
|
||||
assertThat(currentUser.getUserId()).isEqualTo("user-2-1");
|
||||
assertThat(currentUser.getGroupIds()).hasSize(2);
|
||||
assertThat(currentUser.getGroupIds()).hasSize(3);
|
||||
assertThat(currentUser.getRoles()).hasSize(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,13 @@ taskana.ldap.groupNameAttribute=cn
|
|||
taskana.ldap.minSearchForLength=3
|
||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||
taskana.ldap.groupsOfUser=uniquemember
|
||||
taskana.ldap.permissionSearchBase=
|
||||
taskana.ldap.permissionSearchFilterName=objectclass
|
||||
taskana.ldap.permissionSearchFilterValue=groupofuniquenames
|
||||
taskana.ldap.permissionNameAttribute=permission
|
||||
taskana.ldap.permissionsOfUser=uniquemember
|
||||
taskana.ldap.useDnForGroups=true
|
||||
taskana.ldap.userMemberOfPermissionAttribute=memberOf
|
||||
####### JobScheduler cron expression that specifies when the JobSchedler runs
|
||||
taskana.jobscheduler.async.cron=0 * * * * *
|
||||
####### cache static resources propertiesgit add --
|
||||
|
|
|
@ -29,6 +29,12 @@ taskana.ldap.groupNameAttribute=cn
|
|||
taskana.ldap.minSearchForLength=3
|
||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||
taskana.ldap.groupsOfUser=uniquemember
|
||||
taskana.ldap.permissionSearchBase=
|
||||
taskana.ldap.permissionSearchFilterName=objectclass
|
||||
taskana.ldap.permissionSearchFilterValue=groupofuniquenames
|
||||
taskana.ldap.permissionNameAttribute=permission
|
||||
taskana.ldap.permissionsOfUser=uniquemember
|
||||
taskana.ldap.useDnForGroups=true
|
||||
####### JobScheduler cron expression that specifies when the JobSchedler runs
|
||||
taskana.jobscheduler.async.cron=0 * * * * *
|
||||
####### cache static resources propertiesgit add --
|
||||
|
|
|
@ -133,6 +133,8 @@ objectclass: top
|
|||
givenName: Elena
|
||||
description: desc
|
||||
memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter-vip
|
||||
memberOf: cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||
uid: user-1-2
|
||||
sn: Eifrig
|
||||
|
@ -182,6 +184,7 @@ givenName: Simone
|
|||
description: desc
|
||||
memberOf: cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||
memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
uid: user-2-1
|
||||
sn: Müller
|
||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||
|
@ -409,6 +412,25 @@ cn: monitor-users
|
|||
objectclass: groupofuniquenames
|
||||
objectclass: top
|
||||
|
||||
########################
|
||||
# Permissions
|
||||
########################
|
||||
|
||||
dn: cn=g01,cn=groups,OU=Test,O=TASKANA
|
||||
uniquemember: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
||||
uniquemember: uid=user-2-1,cn=users,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
cn: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
objectclass: groupofuniquenames
|
||||
objectclass: top
|
||||
|
||||
dn: cn=g02,cn=groups,OU=Test,O=TASKANA
|
||||
uniquemember: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter-vip
|
||||
cn: g02
|
||||
objectclass: groupofuniquenames
|
||||
objectclass: top
|
||||
|
||||
######################
|
||||
# Organizational Units
|
||||
######################
|
||||
|
|
|
@ -48,7 +48,10 @@ public class TestWebSecurityConfig {
|
|||
@Value("${taskana.ldap.baseDn:OU=Test,O=TASKANA}") String ldapBaseDn,
|
||||
@Value("${taskana.ldap.userDnPatterns:uid={0},cn=users}") String ldapUserDnPatterns,
|
||||
@Value("${taskana.ldap.groupSearchBase:cn=groups}") String ldapGroupSearchBase,
|
||||
@Value("${taskana.ldap.groupSearchFilter:uniqueMember={0}}") String ldapGroupSearchFilter) {
|
||||
@Value("${taskana.ldap.groupSearchFilter:uniqueMember={0}}") String ldapGroupSearchFilter,
|
||||
@Value("${taskana.ldap.permissionSearchBase:cn=groups}") String ldapPermissionSearchBase,
|
||||
@Value("${taskana.ldap.permissionSearchFilter:uniqueMember={0}}")
|
||||
String ldapPermissionSearchFilter) {
|
||||
this.ldapServerUrl = ldapServerUrl;
|
||||
this.ldapBaseDn = ldapBaseDn;
|
||||
this.ldapUserDnPatterns = ldapUserDnPatterns;
|
||||
|
|
|
@ -11,6 +11,11 @@ cn: groups
|
|||
objectclass: top
|
||||
objectclass: container
|
||||
|
||||
dn: cn=permissions,OU=Test,O=TASKANA
|
||||
cn: permissions
|
||||
objectclass: top
|
||||
objectclass: container
|
||||
|
||||
dn: cn=users,OU=Test,O=TASKANA
|
||||
cn: users
|
||||
objectclass: top
|
||||
|
@ -109,8 +114,6 @@ sn: Toll
|
|||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||
cn: Titus Toll
|
||||
userPassword: teamlead-1
|
||||
permission: organize
|
||||
permission: inet
|
||||
|
||||
dn: uid=user-1-1,cn=users,OU=Test,O=TASKANA
|
||||
objectclass: inetorgperson
|
||||
|
@ -126,8 +129,6 @@ sn: Mustermann
|
|||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||
cn: Max Mustermann
|
||||
userPassword: user-1-1
|
||||
permission: organize
|
||||
permission: inet
|
||||
|
||||
dn: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
||||
objectclass: inetorgperson
|
||||
|
@ -137,15 +138,14 @@ objectclass: top
|
|||
givenName: Elena
|
||||
description: desc
|
||||
memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter-vip
|
||||
memberOf: cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||
uid: user-1-2
|
||||
sn: Eifrig
|
||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||
cn: Elena Eifrig
|
||||
userPassword: user-1-2
|
||||
permission: organize
|
||||
permission: inet
|
||||
permission: program
|
||||
|
||||
dn: uid=user-1-3,cn=users,OU=Test,O=TASKANA
|
||||
objectclass: inetorgperson
|
||||
|
@ -189,6 +189,7 @@ givenName: Simone
|
|||
description: desc
|
||||
memberOf: cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||
memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
uid: user-2-1
|
||||
sn: Müller
|
||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||
|
@ -223,9 +224,6 @@ sn: Bach
|
|||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||
cn: Thomas Bach
|
||||
userPassword: user-2-3
|
||||
permission: organize
|
||||
permission: inet
|
||||
permission: program
|
||||
|
||||
dn: uid=user-2-4,cn=users,OU=Test,O=TASKANA
|
||||
objectclass: inetorgperson
|
||||
|
@ -282,9 +280,6 @@ sn: Meyer
|
|||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||
cn: Wiebke Meyer
|
||||
userPassword: user-2-7
|
||||
permission: organize
|
||||
permission: inet
|
||||
permission: manage
|
||||
|
||||
dn: uid=user-2-8,cn=users,OU=Test,O=TASKANA
|
||||
objectclass: inetorgperson
|
||||
|
@ -370,10 +365,6 @@ sn: Bio
|
|||
ou: Organisationseinheit/Organisationseinheit B
|
||||
cn: Brunhilde Bio
|
||||
userPassword: user-b-2
|
||||
permission: organize
|
||||
permission: inet
|
||||
permission: siegen
|
||||
permission: frieden
|
||||
|
||||
########################
|
||||
# Users in other cn
|
||||
|
@ -426,6 +417,25 @@ cn: monitor-users
|
|||
objectclass: groupofuniquenames
|
||||
objectclass: top
|
||||
|
||||
########################
|
||||
# Permissions
|
||||
########################
|
||||
|
||||
dn: cn=g01,cn=groups,OU=Test,O=TASKANA
|
||||
uniquemember: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
||||
uniquemember: uid=user-2-1,cn=users,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter
|
||||
cn: g01
|
||||
objectclass: groupofuniquenames
|
||||
objectclass: top
|
||||
|
||||
dn: cn=g02,cn=groups,OU=Test,O=TASKANA
|
||||
uniquemember: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
||||
permission: Taskana:CallCenter:AB:AB/A:CallCenter-vip
|
||||
cn: g02
|
||||
objectclass: groupofuniquenames
|
||||
objectclass: top
|
||||
|
||||
######################
|
||||
# Organizational Units
|
||||
######################
|
||||
|
|
|
@ -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,15 +38,17 @@ public class AccessIdController {
|
|||
* @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.
|
||||
* @title Search for Access Id (users and groups)
|
||||
* @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<List<AccessIdRepresentationModel>> searchUsersAndGroups(
|
||||
public ResponseEntity<List<AccessIdRepresentationModel>> searchUsersAndGroupsAndPermissions(
|
||||
@RequestParam("search-for") String searchFor)
|
||||
throws InvalidArgumentException, NotAuthorizedException {
|
||||
throws InvalidArgumentException, NotAuthorizedException, InvalidNameException {
|
||||
taskanaEngine.checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.BUSINESS_ADMIN);
|
||||
|
||||
List<AccessIdRepresentationModel> accessIdUsers = ldapClient.searchUsersAndGroups(searchFor);
|
||||
List<AccessIdRepresentationModel> accessIdUsers =
|
||||
ldapClient.searchUsersAndGroupsAndPermissions(searchFor);
|
||||
return ResponseEntity.ok(accessIdUsers);
|
||||
}
|
||||
|
||||
|
@ -88,12 +91,13 @@ public class AccessIdController {
|
|||
* @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<List<AccessIdRepresentationModel>> getGroupsByAccessId(
|
||||
@RequestParam("access-id") String accessId)
|
||||
throws InvalidArgumentException, NotAuthorizedException {
|
||||
throws InvalidArgumentException, NotAuthorizedException, InvalidNameException {
|
||||
taskanaEngine.checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.BUSINESS_ADMIN);
|
||||
|
||||
List<AccessIdRepresentationModel> accessIds =
|
||||
|
@ -101,4 +105,26 @@ public class AccessIdController {
|
|||
|
||||
return ResponseEntity.ok(accessIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint retrieves all permissions a given Access Id belongs to.
|
||||
*
|
||||
* @param accessId the Access Id whose permissions should be determined.
|
||||
* @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<List<AccessIdRepresentationModel>> getPermissionsByAccessId(
|
||||
@RequestParam("access-id") String accessId)
|
||||
throws InvalidArgumentException, NotAuthorizedException, InvalidNameException {
|
||||
taskanaEngine.checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.BUSINESS_ADMIN);
|
||||
|
||||
List<AccessIdRepresentationModel> accessIds =
|
||||
ldapClient.searchPermissionsAccessIdHas(accessId);
|
||||
|
||||
return ResponseEntity.ok(accessIds);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ public final class RestEndpoints {
|
|||
public static final String URL_ACCESS_ID = API_V1 + "access-ids";
|
||||
public static final String URL_ACCESS_ID_WITH_NAME = URL_ACCESS_ID + "/with-name";
|
||||
public static final String URL_ACCESS_ID_GROUPS = URL_ACCESS_ID + "/groups";
|
||||
public static final String URL_ACCESS_ID_PERMISSIONS = URL_ACCESS_ID + "/permissions";
|
||||
|
||||
// import / export endpoints
|
||||
public static final String URL_CLASSIFICATION_DEFINITIONS = API_V1 + "classification-definitions";
|
||||
|
|
|
@ -7,13 +7,17 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
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;
|
||||
|
@ -23,7 +27,9 @@ import org.springframework.ldap.core.LdapTemplate;
|
|||
import org.springframework.ldap.core.support.AbstractContextMapper;
|
||||
import org.springframework.ldap.filter.AndFilter;
|
||||
import org.springframework.ldap.filter.EqualsFilter;
|
||||
import org.springframework.ldap.filter.NotPresentFilter;
|
||||
import org.springframework.ldap.filter.OrFilter;
|
||||
import org.springframework.ldap.filter.PresentFilter;
|
||||
import org.springframework.ldap.filter.WhitespaceWildcardsFilter;
|
||||
import org.springframework.ldap.support.LdapNameBuilder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -62,15 +68,16 @@ public class LdapClient {
|
|||
}
|
||||
|
||||
/**
|
||||
* Search LDAP for matching users or groups.
|
||||
* Search LDAP for matching users or groups or permissions.
|
||||
*
|
||||
* @param name lookup string for names or groups
|
||||
* @param name lookup string for names or groups or permissions
|
||||
* @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<AccessIdRepresentationModel> searchUsersAndGroups(final String name)
|
||||
throws InvalidArgumentException {
|
||||
public List<AccessIdRepresentationModel> searchUsersAndGroupsAndPermissions(final String name)
|
||||
throws InvalidArgumentException, InvalidNameException {
|
||||
isInitOrFail();
|
||||
testMinSearchForLength(name);
|
||||
|
||||
|
@ -83,6 +90,7 @@ public class LdapClient {
|
|||
} else {
|
||||
accessIds.addAll(searchUsersByNameOrAccessId(name));
|
||||
accessIds.addAll(searchGroupsByName(name));
|
||||
accessIds.addAll(searchPermissionsByName(name));
|
||||
}
|
||||
sortListOfAccessIdResources(accessIds);
|
||||
return getFirstPageOfaResultList(accessIds);
|
||||
|
@ -214,19 +222,74 @@ public class LdapClient {
|
|||
if (!CN.equals(getGroupNameAttribute())) {
|
||||
orFilter.or(new WhitespaceWildcardsFilter(CN, name));
|
||||
}
|
||||
final AndFilter andFilter2 = new AndFilter();
|
||||
andFilter2.and(new NotPresentFilter(getUserPermissionsAttribute()));
|
||||
andFilter.and(orFilter);
|
||||
andFilter2.and(andFilter);
|
||||
|
||||
LOGGER.debug("Using filter '{}' for LDAP query.", andFilter);
|
||||
|
||||
return ldapTemplate.search(
|
||||
getGroupSearchBase(),
|
||||
andFilter.encode(),
|
||||
andFilter2.encode(),
|
||||
SearchControls.SUBTREE_SCOPE,
|
||||
getLookUpGroupAttributesToReturn(),
|
||||
new GroupContextMapper());
|
||||
}
|
||||
|
||||
public AccessIdRepresentationModel searchAccessIdByDn(final String dn) {
|
||||
public Map<String, List<String>> searchAccessIdForGroupsAndPermissionsByDn(List<String> dns)
|
||||
throws InvalidNameException {
|
||||
List<String> accessIdsOfGroupsAndPermissions = new ArrayList<>();
|
||||
List<AccessIdRepresentationModel> permissions = new ArrayList<>();
|
||||
List<String> accessIdsOfPermissions = new ArrayList<>();
|
||||
for (String groupOrPermission : dns) {
|
||||
accessIdsOfGroupsAndPermissions.add(searchAccessIdByDn(groupOrPermission)
|
||||
.getAccessId());
|
||||
}
|
||||
for (String groupOrPermission : accessIdsOfGroupsAndPermissions) {
|
||||
permissions.addAll(searchPermissionsByName(groupOrPermission));
|
||||
}
|
||||
for (AccessIdRepresentationModel permission : permissions) {
|
||||
accessIdsOfPermissions.add(permission.getAccessId());
|
||||
}
|
||||
List<String> accessIdsOfGroups = new ArrayList<>(accessIdsOfGroupsAndPermissions);
|
||||
accessIdsOfGroups.removeAll(accessIdsOfPermissions);
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
map.put("permissions", accessIdsOfPermissions);
|
||||
map.put("groups", accessIdsOfGroups);
|
||||
return map;
|
||||
}
|
||||
|
||||
public List<AccessIdRepresentationModel> searchPermissionsByName(final String name)
|
||||
throws InvalidArgumentException {
|
||||
isInitOrFail();
|
||||
testMinSearchForLength(name);
|
||||
|
||||
final AndFilter andFilter = new AndFilter();
|
||||
andFilter.and(new EqualsFilter(getPermissionSearchFilterName(),
|
||||
getPermissionSearchFilterValue()));
|
||||
final OrFilter orFilter = new OrFilter();
|
||||
orFilter.or(new WhitespaceWildcardsFilter(getUserPermissionsAttribute(), name));
|
||||
if (!CN.equals(getUserPermissionsAttribute())) {
|
||||
orFilter.or(new WhitespaceWildcardsFilter(CN, name));
|
||||
}
|
||||
final AndFilter andFilter2 = new AndFilter();
|
||||
andFilter2.and(new PresentFilter(getUserPermissionsAttribute()));
|
||||
andFilter.and(orFilter);
|
||||
andFilter2.and(andFilter);
|
||||
|
||||
LOGGER.debug("Using filter '{}' for LDAP query.", andFilter);
|
||||
|
||||
return ldapTemplate.search(
|
||||
getPermissionSearchBase(),
|
||||
andFilter2.encode(),
|
||||
SearchControls.SUBTREE_SCOPE,
|
||||
getLookUpPermissionAttributesToReturn(),
|
||||
new PermissionContextMapper());
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -239,11 +302,13 @@ public class LdapClient {
|
|||
"Removed baseDN {} from given DN. New DN to be used: {}", getBaseDn(), nameWithoutBaseDn);
|
||||
}
|
||||
return ldapTemplate.lookup(
|
||||
nameWithoutBaseDn, getLookUpUserAndGroupAttributesToReturn(), new DnContextMapper());
|
||||
new LdapName(nameWithoutBaseDn),
|
||||
getLookUpUserAndGroupAndPermissionAttributesToReturn(),
|
||||
new DnContextMapper());
|
||||
}
|
||||
|
||||
public List<AccessIdRepresentationModel> searchGroupsAccessIdIsMemberOf(final String accessId)
|
||||
throws InvalidArgumentException {
|
||||
throws InvalidArgumentException, InvalidNameException {
|
||||
isInitOrFail();
|
||||
testMinSearchForLength(accessId);
|
||||
|
||||
|
@ -259,74 +324,186 @@ public class LdapClient {
|
|||
orFilter.or(new EqualsFilter(getGroupsOfUserName(), accessId));
|
||||
}
|
||||
orFilter.or(new EqualsFilter(getGroupsOfUserName(), dn));
|
||||
final AndFilter andFilter2 = new AndFilter();
|
||||
andFilter2.and(new NotPresentFilter(getUserPermissionsAttribute()));
|
||||
andFilter.and(orFilter);
|
||||
andFilter2.and(andFilter);
|
||||
|
||||
String[] userAttributesToReturn = {getUserIdAttribute(), getGroupNameAttribute()};
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(
|
||||
"Using filter '{}' for LDAP query with group search base {}.",
|
||||
andFilter,
|
||||
andFilter2,
|
||||
getGroupSearchBase());
|
||||
}
|
||||
|
||||
return ldapTemplate.search(
|
||||
getGroupSearchBase(),
|
||||
andFilter.encode(),
|
||||
andFilter2.encode(),
|
||||
SearchControls.SUBTREE_SCOPE,
|
||||
userAttributesToReturn,
|
||||
new GroupContextMapper());
|
||||
}
|
||||
|
||||
public List<AccessIdRepresentationModel> searchPermissionsAccessIdHas(final String accessId)
|
||||
throws InvalidArgumentException, InvalidNameException {
|
||||
isInitOrFail();
|
||||
testMinSearchForLength(accessId);
|
||||
|
||||
String dn = searchDnForAccessId(accessId);
|
||||
if (dn == null || dn.isEmpty()) {
|
||||
throw new InvalidArgumentException("The AccessId is invalid");
|
||||
}
|
||||
|
||||
final AndFilter andFilter = new AndFilter();
|
||||
andFilter.and(new EqualsFilter(getPermissionSearchFilterName(),
|
||||
getPermissionSearchFilterValue()));
|
||||
final OrFilter orFilter = new OrFilter();
|
||||
if (!"DN".equalsIgnoreCase(getPermissionsOfUserType())) {
|
||||
orFilter.or(new EqualsFilter(getPermissionsOfUserName(), accessId));
|
||||
}
|
||||
orFilter.or(new EqualsFilter(getPermissionsOfUserName(), dn));
|
||||
final AndFilter andFilter2 = new AndFilter();
|
||||
andFilter2.and(new PresentFilter(getUserPermissionsAttribute()));
|
||||
andFilter.and(orFilter);
|
||||
andFilter2.and(andFilter);
|
||||
|
||||
String[] userAttributesToReturn = {getUserIdAttribute(), getUserPermissionsAttribute()};
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(
|
||||
"Using filter '{}' for LDAP query with group search base {}.",
|
||||
andFilter2,
|
||||
getPermissionSearchBase());
|
||||
}
|
||||
|
||||
return ldapTemplate.search(
|
||||
getPermissionSearchBase(),
|
||||
andFilter2.encode(),
|
||||
SearchControls.SUBTREE_SCOPE,
|
||||
userAttributesToReturn,
|
||||
new PermissionContextMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a lookup to retrieve correct DN for the given access id.
|
||||
*
|
||||
* @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)) {
|
||||
AccessIdRepresentationModel groupByDn = searchAccessIdByDn(accessId);
|
||||
return groupByDn.getAccessId();
|
||||
} else {
|
||||
final AndFilter andFilter = new AndFilter();
|
||||
andFilter.and(new EqualsFilter(getUserSearchFilterName(), getUserSearchFilterValue()));
|
||||
final OrFilter orFilter = new OrFilter();
|
||||
orFilter.or(new EqualsFilter(getUserIdAttribute(), accessId));
|
||||
andFilter.and(orFilter);
|
||||
return searchDnForAccessIdIfAccessIdNameIsNotDn(accessId);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.debug(
|
||||
"Using filter '{}' for LDAP query with user search base {}.",
|
||||
andFilter,
|
||||
getUserSearchBase());
|
||||
|
||||
final List<String> distinguishedNames =
|
||||
ldapTemplate.search(
|
||||
getUserSearchBase(),
|
||||
andFilter.encode(),
|
||||
SearchControls.SUBTREE_SCOPE,
|
||||
null,
|
||||
new DnStringContextMapper());
|
||||
|
||||
if (distinguishedNames == null || distinguishedNames.isEmpty()) {
|
||||
return null;
|
||||
} else if (distinguishedNames.size() > 1) {
|
||||
private String searchDnForAccessIdIfAccessIdNameIsNotDn(String accessId) {
|
||||
final List<String> distinguishedNames = searchDnForUserAccessId(accessId);
|
||||
if (distinguishedNames == null || distinguishedNames.isEmpty()) {
|
||||
final List<String> distinguishedNamesPermissions = searchDnForPermissionAccessId(accessId);
|
||||
if (distinguishedNamesPermissions == null || distinguishedNamesPermissions.isEmpty()) {
|
||||
final List<String> distinguishedNamesGroups = searchDnForGroupAccessId(accessId);
|
||||
if (distinguishedNamesGroups == null || distinguishedNamesGroups.isEmpty()) {
|
||||
return null;
|
||||
} else if (distinguishedNamesGroups.size() > 1) {
|
||||
throw new InvalidArgumentException("Ambiguous access id found: " + accessId);
|
||||
} else {
|
||||
return distinguishedNamesGroups.get(0);
|
||||
}
|
||||
} else if (distinguishedNamesPermissions.size() > 1) {
|
||||
throw new InvalidArgumentException("Ambiguous access id found: " + accessId);
|
||||
} else {
|
||||
return distinguishedNames.get(0);
|
||||
return distinguishedNamesPermissions.get(0);
|
||||
}
|
||||
} else if (distinguishedNames.size() > 1) {
|
||||
throw new InvalidArgumentException("Ambiguous access id found: " + accessId);
|
||||
} else {
|
||||
return distinguishedNames.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> searchDnForUserAccessId(String accessId) {
|
||||
final AndFilter andFilter = new AndFilter();
|
||||
andFilter.and(new EqualsFilter(getUserSearchFilterName(), getUserSearchFilterValue()));
|
||||
final OrFilter orFilter = new OrFilter();
|
||||
orFilter.or(new EqualsFilter(getUserIdAttribute(), accessId));
|
||||
andFilter.and(orFilter);
|
||||
|
||||
LOGGER.debug(
|
||||
"Using filter '{}' for LDAP query with user search base {}.",
|
||||
andFilter,
|
||||
getUserSearchBase());
|
||||
|
||||
return ldapTemplate.search(
|
||||
getUserSearchBase(),
|
||||
andFilter.encode(),
|
||||
SearchControls.SUBTREE_SCOPE,
|
||||
null,
|
||||
new DnStringContextMapper());
|
||||
}
|
||||
|
||||
private List<String> searchDnForPermissionAccessId(String accessId) {
|
||||
final AndFilter andFilter = new AndFilter();
|
||||
andFilter.and(new EqualsFilter(getPermissionSearchFilterName(),
|
||||
getPermissionSearchFilterValue()));
|
||||
final OrFilter orFilter = new OrFilter();
|
||||
orFilter.or(new EqualsFilter(getUserPermissionsAttribute(), accessId));
|
||||
final AndFilter andFilterPermission2 = new AndFilter();
|
||||
andFilter.and(new PresentFilter(getUserPermissionsAttribute()));
|
||||
andFilter.and(orFilter);
|
||||
andFilterPermission2.and(andFilter);
|
||||
|
||||
LOGGER.debug(
|
||||
"Using filter '{}' for LDAP query with user search base {}.",
|
||||
andFilterPermission2,
|
||||
getPermissionSearchBase());
|
||||
|
||||
return ldapTemplate.search(
|
||||
getPermissionSearchBase(),
|
||||
andFilterPermission2.encode(),
|
||||
SearchControls.SUBTREE_SCOPE,
|
||||
null,
|
||||
new DnStringContextMapper());
|
||||
}
|
||||
|
||||
private List<String> searchDnForGroupAccessId(String accessId) {
|
||||
final AndFilter andFilter = new AndFilter();
|
||||
andFilter.and(new EqualsFilter(getGroupSearchFilterName(), getGroupSearchFilterValue()));
|
||||
final OrFilter orFilter = new OrFilter();
|
||||
orFilter.or(new EqualsFilter(getGroupNameAttribute(), accessId));
|
||||
final AndFilter andFilter2 = new AndFilter();
|
||||
andFilter2.and(new NotPresentFilter(getUserPermissionsAttribute()));
|
||||
andFilter.and(orFilter);
|
||||
andFilter2.and(andFilter);
|
||||
|
||||
LOGGER.debug(
|
||||
"Using filter '{}' for LDAP query with user search base {}.",
|
||||
andFilter2,
|
||||
getPermissionSearchBase());
|
||||
|
||||
return ldapTemplate.search(
|
||||
getPermissionSearchBase(),
|
||||
andFilter.encode(),
|
||||
SearchControls.SUBTREE_SCOPE,
|
||||
null,
|
||||
new DnStringContextMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a given AccessId / name.
|
||||
*
|
||||
* @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)) {
|
||||
|
@ -417,6 +594,22 @@ public class LdapClient {
|
|||
return LdapSettings.TASKANA_LDAP_USER_PERMISSIONS_ATTRIBUTE.getValueFromEnv(env);
|
||||
}
|
||||
|
||||
public String getPermissionSearchBase() {
|
||||
return LdapSettings.TASKANA_LDAP_PERMISSION_SEARCH_BASE.getValueFromEnv(env);
|
||||
}
|
||||
|
||||
public String getPermissionSearchFilterName() {
|
||||
return LdapSettings.TASKANA_LDAP_PERMISSION_SEARCH_FILTER_NAME.getValueFromEnv(env);
|
||||
}
|
||||
|
||||
public String getPermissionSearchFilterValue() {
|
||||
return LdapSettings.TASKANA_LDAP_PERMISSION_SEARCH_FILTER_VALUE.getValueFromEnv(env);
|
||||
}
|
||||
|
||||
public String getPermissionNameAttribute() {
|
||||
return LdapSettings.TASKANA_LDAP_PERMISSION_NAME_ATTRIBUTE.getValueFromEnv(env);
|
||||
}
|
||||
|
||||
public String getGroupSearchBase() {
|
||||
return LdapSettings.TASKANA_LDAP_GROUP_SEARCH_BASE.getValueFromEnv(env);
|
||||
}
|
||||
|
@ -458,6 +651,15 @@ public class LdapClient {
|
|||
return Integer.parseInt(envValue);
|
||||
}
|
||||
|
||||
public boolean useDnForGroups() {
|
||||
String envValue =
|
||||
LdapSettings.TASKANA_LDAP_USE_DN_FOR_GROUPS.getValueFromEnv(env);
|
||||
if (envValue == null || envValue.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return Boolean.parseBoolean(envValue);
|
||||
}
|
||||
|
||||
public int getMaxNumberOfReturnedAccessIds() {
|
||||
return maxNumberOfReturnedAccessIds;
|
||||
}
|
||||
|
@ -474,6 +676,19 @@ public class LdapClient {
|
|||
return LdapSettings.TASKANA_LDAP_GROUPS_OF_USER_TYPE.getValueFromEnv(env);
|
||||
}
|
||||
|
||||
public String getPermissionsOfUserName() {
|
||||
String permissionsOfUser =
|
||||
LdapSettings.TASKANA_LDAP_PERMISSIONS_OF_USER_NAME.getValueFromEnv(env);
|
||||
if (permissionsOfUser == null || permissionsOfUser.isEmpty()) {
|
||||
permissionsOfUser = LdapSettings.TASKANA_LDAP_PERMISSIONS_OF_USER.getValueFromEnv(env);
|
||||
}
|
||||
return permissionsOfUser;
|
||||
}
|
||||
|
||||
public String getPermissionsOfUserType() {
|
||||
return LdapSettings.TASKANA_LDAP_PERMISSIONS_OF_USER_TYPE.getValueFromEnv(env);
|
||||
}
|
||||
|
||||
public boolean isUser(String accessId) {
|
||||
return !getUsersByAccessId(accessId).isEmpty();
|
||||
}
|
||||
|
@ -522,10 +737,19 @@ public class LdapClient {
|
|||
return new String[] {getGroupNameAttribute(), CN, getGroupSearchFilterName()};
|
||||
}
|
||||
|
||||
String[] getLookUpUserAndGroupAttributesToReturn() {
|
||||
return Stream.concat(
|
||||
String[] getLookUpPermissionAttributesToReturn() {
|
||||
return new String[] {
|
||||
getUserPermissionsAttribute(),
|
||||
getPermissionSearchFilterName()
|
||||
};
|
||||
}
|
||||
|
||||
String[] getLookUpUserAndGroupAndPermissionAttributesToReturn() {
|
||||
return Stream.concat(Stream.concat(
|
||||
Arrays.stream(getLookUpUserAttributesToReturn()),
|
||||
Arrays.stream(getLookUpGroupAttributesToReturn()))
|
||||
Arrays.stream(getLookUpGroupAttributesToReturn())),
|
||||
Arrays.stream(getLookUpPermissionAttributesToReturn())
|
||||
)
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
|
@ -587,6 +811,9 @@ public class LdapClient {
|
|||
.filter(not(LdapSettings.TASKANA_LDAP_GROUPS_OF_USER::equals))
|
||||
.filter(not(LdapSettings.TASKANA_LDAP_GROUPS_OF_USER_NAME::equals))
|
||||
.filter(not(LdapSettings.TASKANA_LDAP_GROUPS_OF_USER_TYPE::equals))
|
||||
.filter(not(LdapSettings.TASKANA_LDAP_PERMISSIONS_OF_USER::equals))
|
||||
.filter(not(LdapSettings.TASKANA_LDAP_PERMISSIONS_OF_USER_NAME::equals))
|
||||
.filter(not(LdapSettings.TASKANA_LDAP_PERMISSIONS_OF_USER_TYPE::equals))
|
||||
.filter(p -> p.getValueFromEnv(env) == null)
|
||||
.toList();
|
||||
}
|
||||
|
@ -622,6 +849,15 @@ public class LdapClient {
|
|||
}
|
||||
}
|
||||
|
||||
private String getGroupIdFromContext(final DirContextOperations context) {
|
||||
String groupId = context.getStringAttribute(getGroupNameAttribute());
|
||||
if (groupId != null && useLowerCaseForAccessIds) {
|
||||
return groupId.toLowerCase();
|
||||
} else {
|
||||
return groupId;
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> getGroupIdsFromContext(final DirContextOperations context) {
|
||||
String[] groupAttributes = context.getStringAttributes(getUserMemberOfGroupAttribute());
|
||||
Set<String> groups = groupAttributes != null ? Set.of(groupAttributes) : Collections.emptySet();
|
||||
|
@ -635,6 +871,15 @@ public class LdapClient {
|
|||
return groups;
|
||||
}
|
||||
|
||||
private String getPermissionIdFromContext(final DirContextOperations context) {
|
||||
String permissionId = context.getStringAttribute(getUserPermissionsAttribute());
|
||||
if (permissionId != null && useLowerCaseForAccessIds) {
|
||||
return permissionId.toLowerCase();
|
||||
} else {
|
||||
return permissionId;
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> getPermissionIdsFromContext(final DirContextOperations context) {
|
||||
String[] permissionAttributes = context.getStringAttributes(getUserPermissionsAttribute());
|
||||
Set<String> permissions =
|
||||
|
@ -655,12 +900,27 @@ public class LdapClient {
|
|||
@Override
|
||||
public AccessIdRepresentationModel doMapFromContext(final DirContextOperations context) {
|
||||
final AccessIdRepresentationModel accessId = new AccessIdRepresentationModel();
|
||||
accessId.setAccessId(getDnFromContext(context)); // fully qualified dn
|
||||
if (useDnForGroups()) {
|
||||
accessId.setAccessId(getDnFromContext(context)); // fully qualified dn
|
||||
} else {
|
||||
accessId.setAccessId(getGroupIdFromContext(context));
|
||||
}
|
||||
accessId.setName(context.getStringAttribute(getGroupNameAttribute()));
|
||||
return accessId;
|
||||
}
|
||||
}
|
||||
|
||||
class PermissionContextMapper extends AbstractContextMapper<AccessIdRepresentationModel> {
|
||||
|
||||
@Override
|
||||
public AccessIdRepresentationModel doMapFromContext(final DirContextOperations context) {
|
||||
final AccessIdRepresentationModel accessId = new AccessIdRepresentationModel();
|
||||
accessId.setAccessId(getPermissionIdFromContext(context)); // fully qualified dn
|
||||
accessId.setName(context.getStringAttribute(getUserPermissionsAttribute()));
|
||||
return accessId;
|
||||
}
|
||||
}
|
||||
|
||||
/** Context Mapper for user info entries. */
|
||||
class UserInfoContextMapper extends AbstractContextMapper<User> {
|
||||
|
||||
|
@ -712,9 +972,16 @@ public class LdapClient {
|
|||
String firstName = context.getStringAttribute(getUserFirstnameAttribute());
|
||||
String lastName = context.getStringAttribute(getUserLastnameAttribute());
|
||||
accessId.setName(String.format("%s, %s", lastName, firstName));
|
||||
} else {
|
||||
accessId.setAccessId(getDnFromContext(context)); // fully qualified dn
|
||||
} else if (context.getStringAttribute(getUserPermissionsAttribute()) == null) {
|
||||
if (useDnForGroups()) {
|
||||
accessId.setAccessId(getDnFromContext(context)); // fully qualified dn
|
||||
} else {
|
||||
accessId.setAccessId(getGroupIdFromContext(context));
|
||||
}
|
||||
accessId.setName(context.getStringAttribute(getGroupNameAttribute()));
|
||||
} else {
|
||||
accessId.setAccessId(getPermissionIdFromContext(context));
|
||||
accessId.setName(context.getStringAttribute(getUserPermissionsAttribute()));
|
||||
}
|
||||
return accessId;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@ enum LdapSettings {
|
|||
TASKANA_LDAP_USER_ORG_LEVEL_4_ATTRIBUTE("taskana.ldap.userOrglevel4Attribute"),
|
||||
TASKANA_LDAP_USER_MEMBER_OF_GROUP_ATTRIBUTE("taskana.ldap.userMemberOfGroupAttribute"),
|
||||
TASKANA_LDAP_USER_PERMISSIONS_ATTRIBUTE("taskana.ldap.userPermissionsAttribute"),
|
||||
TASKANA_LDAP_PERMISSION_SEARCH_BASE("taskana.ldap.permissionSearchBase"),
|
||||
TASKANA_LDAP_PERMISSION_SEARCH_FILTER_NAME("taskana.ldap.permissionSearchFilterName"),
|
||||
TASKANA_LDAP_PERMISSION_SEARCH_FILTER_VALUE("taskana.ldap.permissionSearchFilterValue"),
|
||||
TASKANA_LDAP_PERMISSION_NAME_ATTRIBUTE("taskana.ldap.permissionNameAttribute"),
|
||||
TASKANA_LDAP_GROUP_SEARCH_BASE("taskana.ldap.groupSearchBase"),
|
||||
TASKANA_LDAP_BASE_DN("taskana.ldap.baseDn"),
|
||||
TASKANA_LDAP_GROUP_SEARCH_FILTER_NAME("taskana.ldap.groupSearchFilterName"),
|
||||
|
@ -29,7 +33,11 @@ enum LdapSettings {
|
|||
TASKANA_LDAP_MAX_NUMBER_OF_RETURNED_ACCESS_IDS("taskana.ldap.maxNumberOfReturnedAccessIds"),
|
||||
TASKANA_LDAP_GROUPS_OF_USER("taskana.ldap.groupsOfUser"),
|
||||
TASKANA_LDAP_GROUPS_OF_USER_NAME("taskana.ldap.groupsOfUser.name"),
|
||||
TASKANA_LDAP_GROUPS_OF_USER_TYPE("taskana.ldap.groupsOfUser.type");
|
||||
TASKANA_LDAP_GROUPS_OF_USER_TYPE("taskana.ldap.groupsOfUser.type"),
|
||||
TASKANA_LDAP_PERMISSIONS_OF_USER("taskana.ldap.permissionsOfUser"),
|
||||
TASKANA_LDAP_PERMISSIONS_OF_USER_NAME("taskana.ldap.permissionsOfUser.name"),
|
||||
TASKANA_LDAP_PERMISSIONS_OF_USER_TYPE("taskana.ldap.permissionsOfUser.type"),
|
||||
TASKANA_LDAP_USE_DN_FOR_GROUPS("taskana.ldap.useDnForGroups");
|
||||
|
||||
private final String key;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ public class TaskanaUserInfoRepresentationModel
|
|||
private String userId;
|
||||
/** All groups the current user is a member of. */
|
||||
private List<String> groupIds = new ArrayList<>();
|
||||
/** All taskana roles the current user fulfills. */
|
||||
/** All permissions the current user has. */
|
||||
private List<TaskanaRole> roles = new ArrayList<>();
|
||||
|
||||
public String getUserId() {
|
||||
|
|
|
@ -0,0 +1,280 @@
|
|||
package pro.taskana.common.rest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static pro.taskana.rest.test.RestHelper.TEMPLATE;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
import org.junit.jupiter.api.DynamicTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestFactory;
|
||||
import org.junit.jupiter.api.function.ThrowingConsumer;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import pro.taskana.common.internal.util.Pair;
|
||||
import pro.taskana.common.rest.models.AccessIdRepresentationModel;
|
||||
import pro.taskana.rest.test.RestHelper;
|
||||
import pro.taskana.rest.test.TaskanaSpringBootTest;
|
||||
|
||||
@TestPropertySource(properties = "taskana.ldap.useDnForGroups=false")
|
||||
@TaskanaSpringBootTest
|
||||
class AccessIdControllerForUseDnForGroupsDisabledIntTest {
|
||||
|
||||
private static final ParameterizedTypeReference<List<AccessIdRepresentationModel>>
|
||||
ACCESS_ID_LIST_TYPE = new ParameterizedTypeReference<List<AccessIdRepresentationModel>>() {};
|
||||
|
||||
private final RestHelper restHelper;
|
||||
|
||||
@Autowired
|
||||
AccessIdControllerForUseDnForGroupsDisabledIntTest(RestHelper restHelper) {
|
||||
this.restHelper = restHelper;
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
Stream<DynamicTest> should_ResolveAccessId_When_SearchingForDnOrCn() {
|
||||
List<Pair<String, String>> list =
|
||||
List.of(
|
||||
Pair.of(
|
||||
"cn=ksc-users,cn=groups,OU=Test,O=TASKANA",
|
||||
"ksc-users"),
|
||||
Pair.of("uid=teamlead-1,cn=users,OU=Test,O=TASKANA", "teamlead-1"),
|
||||
Pair.of("ksc-use", "ksc-users"),
|
||||
Pair.of("user-b-2", "user-b-2"),
|
||||
Pair.of("User-b-2", "user-b-2"),
|
||||
Pair.of("cn=g01,cn=groups,OU=Test,O=TASKANA",
|
||||
"taskana:callcenter:ab:ab/a:callcenter"),
|
||||
Pair.of("cn=g02,cn=groups,OU=Test,O=TASKANA",
|
||||
"taskana:callcenter:ab:ab/a:callcenter-vip"));
|
||||
|
||||
ThrowingConsumer<Pair<String, String>> test =
|
||||
pair -> {
|
||||
String url =
|
||||
restHelper.toUrl(RestEndpoints.URL_ACCESS_ID) + "?search-for=" + pair.getLeft();
|
||||
HttpEntity<Object> auth =
|
||||
new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody())
|
||||
.isNotNull()
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.containsExactly(pair.getRight());
|
||||
};
|
||||
|
||||
return DynamicTest.stream(list.iterator(), pair -> "search for: " + pair.getLeft(), test);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnEmptyResults_ifInvalidCharacterIsUsedInCondition() {
|
||||
String url =
|
||||
restHelper.toUrl(RestEndpoints.URL_ACCESS_ID) + "?search-for=ksc-teamleads,cn=groups";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody()).isNotNull().isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetMatches() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID) + "?search-for=rig";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody())
|
||||
.isNotNull()
|
||||
.extracting(AccessIdRepresentationModel::getName)
|
||||
.containsExactlyInAnyOrder("Schläfrig, Tim", "Eifrig, Elena");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnAccessIdWithUmlauten_ifBased64EncodedUserIsLookedUp() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID) + "?search-for=läf";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody())
|
||||
.isNotNull()
|
||||
.extracting(AccessIdRepresentationModel::getName)
|
||||
.containsExactlyInAnyOrder("Schläfrig, Tim");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ThrowException_When_SearchForIsTooShort() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID) + "?search-for=al";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ThrowingCallable httpCall =
|
||||
() -> {
|
||||
TEMPLATE.exchange(
|
||||
url, HttpMethod.GET, auth, ParameterizedTypeReference.forType(List.class));
|
||||
};
|
||||
|
||||
assertThatThrownBy(httpCall)
|
||||
.isInstanceOf(HttpStatusCodeException.class)
|
||||
.hasMessageContaining("Minimum Length is")
|
||||
.extracting(HttpStatusCodeException.class::cast)
|
||||
.extracting(HttpStatusCodeException::getStatusCode)
|
||||
.isEqualTo(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnAccessIdsOfGroupsTheAccessIdIsMemberOf_ifAccessIdOfUserIsGiven() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_GROUPS) + "?access-id=teamlead-2";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody())
|
||||
.isNotNull()
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.usingElementComparator(String.CASE_INSENSITIVE_ORDER)
|
||||
.containsExactlyInAnyOrder(
|
||||
"ksc-teamleads",
|
||||
"business-admins",
|
||||
"monitor-users",
|
||||
"Organisationseinheit KSC 2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnAccessIdsOfPermissionsTheAccessIdIsMemberOf_ifAccessIdOfUserIsGiven() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_PERMISSIONS)
|
||||
+ "?access-id=user-1-2";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody())
|
||||
.isNotNull()
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.usingElementComparator(String.CASE_INSENSITIVE_ORDER)
|
||||
.containsExactlyInAnyOrder("taskana:callcenter:ab:ab/a:callcenter",
|
||||
"taskana:callcenter:ab:ab/a:callcenter-vip");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ValidateAccessIdWithEqualsFilterAndReturnAccessIdsOfGroupsTheAccessIdIsMemberOf() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_GROUPS) + "?access-id=user-2-1";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody())
|
||||
.isNotNull()
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.usingElementComparator(String.CASE_INSENSITIVE_ORDER)
|
||||
.containsExactlyInAnyOrder(
|
||||
"ksc-users",
|
||||
"Organisationseinheit KSC 2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ValidateAccessIdWithEqualsFilterAndReturnAccessIdsOfPermissionsAccessIdIsMemberOf() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_PERMISSIONS) + "?access-id=user-2-1";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody())
|
||||
.isNotNull()
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.usingElementComparator(String.CASE_INSENSITIVE_ORDER)
|
||||
.containsExactlyInAnyOrder(
|
||||
"taskana:callcenter:ab:ab/a:callcenter");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnBadRequest_ifAccessIdOfUserContainsInvalidCharacter() {
|
||||
String url =
|
||||
restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_GROUPS) + "?access-id=teamlead-2,cn=users";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ThrowingCallable call = () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(HttpStatusCodeException.class)
|
||||
.hasMessageContaining("The AccessId is invalid")
|
||||
.extracting(HttpStatusCodeException.class::cast)
|
||||
.extracting(HttpStatusCodeException::getStatusCode)
|
||||
.isEqualTo(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnAccessIdsOfGroupsTheAccessIdIsMemberOf_ifAccessIdOfGroupIsGiven() {
|
||||
String url =
|
||||
restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_GROUPS)
|
||||
+ "?access-id=cn=Organisationseinheit KSC 1,"
|
||||
+ "cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody())
|
||||
.isNotNull()
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.usingElementComparator(String.CASE_INSENSITIVE_ORDER)
|
||||
.containsExactlyInAnyOrder("Organisationseinheit KSC");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ThrowNotAuthorizedException_ifCallerOfGroupRetrievalIsNotAdminOrBusinessAdmin() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_GROUPS) + "?access-id=teamlead-2";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
|
||||
|
||||
ThrowingCallable call = () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(HttpStatusCodeException.class)
|
||||
.extracting(HttpStatusCodeException.class::cast)
|
||||
.extracting(HttpStatusCodeException::getStatusCode)
|
||||
.isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ThrowNotAuthorizedException_ifCallerOfPermissionRetrievalIsNotAdminOrBusinessAdmin() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_PERMISSIONS)
|
||||
+ "?access-id=teamlead-2";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
|
||||
|
||||
ThrowingCallable call = () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(HttpStatusCodeException.class)
|
||||
.extracting(HttpStatusCodeException.class::cast)
|
||||
.extracting(HttpStatusCodeException::getStatusCode)
|
||||
.isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ThrowNotAuthorizedException_ifCallerOfValidationIsNotAdminOrBusinessAdmin() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID) + "?search-for=al";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
|
||||
|
||||
ThrowingCallable call = () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(HttpStatusCodeException.class)
|
||||
.extracting(HttpStatusCodeException.class::cast)
|
||||
.extracting(HttpStatusCodeException::getStatusCode)
|
||||
.isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
}
|
|
@ -46,7 +46,11 @@ class AccessIdControllerIntTest {
|
|||
Pair.of("uid=teamlead-1,cn=users,OU=Test,O=TASKANA", "teamlead-1"),
|
||||
Pair.of("ksc-use", "cn=ksc-users,cn=groups,ou=test,o=taskana"),
|
||||
Pair.of("user-b-2", "user-b-2"),
|
||||
Pair.of("User-b-2", "user-b-2"));
|
||||
Pair.of("User-b-2", "user-b-2"),
|
||||
Pair.of("cn=g01,cn=groups,OU=Test,O=TASKANA",
|
||||
"taskana:callcenter:ab:ab/a:callcenter"),
|
||||
Pair.of("cn=g02,cn=groups,OU=Test,O=TASKANA",
|
||||
"taskana:callcenter:ab:ab/a:callcenter-vip"));
|
||||
|
||||
ThrowingConsumer<Pair<String, String>> test =
|
||||
pair -> {
|
||||
|
@ -146,6 +150,23 @@ class AccessIdControllerIntTest {
|
|||
+ "cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnAccessIdsOfPermissionsTheAccessIdIsMemberOf_ifAccessIdOfUserIsGiven() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_PERMISSIONS)
|
||||
+ "?access-id=user-1-2";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody())
|
||||
.isNotNull()
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.usingElementComparator(String.CASE_INSENSITIVE_ORDER)
|
||||
.containsExactlyInAnyOrder("taskana:callcenter:ab:ab/a:callcenter",
|
||||
"taskana:callcenter:ab:ab/a:callcenter-vip");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ValidateAccessIdWithEqualsFilterAndReturnAccessIdsOfGroupsTheAccessIdIsMemberOf() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_GROUPS) + "?access-id=user-2-1";
|
||||
|
@ -164,6 +185,22 @@ class AccessIdControllerIntTest {
|
|||
+ "cn=organisation,ou=Test,O=TASKANA");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ValidateAccessIdWithEqualsFilterAndReturnAccessIdsOfPermissionsAccessIdIsMemberOf() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_PERMISSIONS) + "?access-id=user-2-1";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1"));
|
||||
|
||||
ResponseEntity<List<AccessIdRepresentationModel>> response =
|
||||
TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThat(response.getBody())
|
||||
.isNotNull()
|
||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||
.usingElementComparator(String.CASE_INSENSITIVE_ORDER)
|
||||
.containsExactlyInAnyOrder(
|
||||
"taskana:callcenter:ab:ab/a:callcenter");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnBadRequest_ifAccessIdOfUserContainsInvalidCharacter() {
|
||||
String url =
|
||||
|
@ -212,6 +249,21 @@ class AccessIdControllerIntTest {
|
|||
.isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ThrowNotAuthorizedException_ifCallerOfPermissionRetrievalIsNotAdminOrBusinessAdmin() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_PERMISSIONS)
|
||||
+ "?access-id=teamlead-2";
|
||||
HttpEntity<Object> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-1"));
|
||||
|
||||
ThrowingCallable call = () -> TEMPLATE.exchange(url, HttpMethod.GET, auth, ACCESS_ID_LIST_TYPE);
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(HttpStatusCodeException.class)
|
||||
.extracting(HttpStatusCodeException.class::cast)
|
||||
.extracting(HttpStatusCodeException::getStatusCode)
|
||||
.isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ThrowNotAuthorizedException_ifCallerOfValidationIsNotAdminOrBusinessAdmin() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID) + "?search-for=al";
|
||||
|
|
|
@ -7,7 +7,9 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import pro.taskana.common.api.TaskanaRole;
|
||||
|
@ -85,6 +87,25 @@ class TaskanaEngineControllerIntTest {
|
|||
assertThat(response.getBody()).containsExactly("EXTERNAL");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnUserInformation_WhenCurrentUserNotAuthorizedToUseUserFromHeader() {
|
||||
HttpHeaders headers = RestHelper.generateHeadersForUser("user-2-1");
|
||||
headers.add("userid", "user-1-1");
|
||||
ResponseEntity<TaskanaUserInfoRepresentationModel> response =
|
||||
TEMPLATE.exchange(
|
||||
restHelper.toUrl(RestEndpoints.URL_CURRENT_USER),
|
||||
HttpMethod.GET,
|
||||
new HttpEntity<>(headers),
|
||||
ParameterizedTypeReference.forType(TaskanaUserInfoRepresentationModel.class));
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
TaskanaUserInfoRepresentationModel currentUser = response.getBody();
|
||||
assertThat(currentUser).isNotNull();
|
||||
assertThat(currentUser.getUserId()).isEqualTo("user-2-1");
|
||||
assertThat(currentUser.getGroupIds()).hasSize(3);
|
||||
assertThat(currentUser.getRoles()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetCurrentUserInfo() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_CURRENT_USER);
|
||||
|
@ -105,6 +126,29 @@ class TaskanaEngineControllerIntTest {
|
|||
.doesNotContain(TaskanaRole.ADMIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetCurrentUserInfoWithPermission() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_CURRENT_USER);
|
||||
HttpEntity<?> auth = new HttpEntity<>(RestHelper.generateHeadersForUser("user-1-2"));
|
||||
|
||||
ResponseEntity<TaskanaUserInfoRepresentationModel> response =
|
||||
TEMPLATE.exchange(
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
auth,
|
||||
ParameterizedTypeReference.forType(TaskanaUserInfoRepresentationModel.class));
|
||||
assertThat(response.getBody()).isNotNull();
|
||||
assertThat(response.getBody().getUserId()).isEqualTo("user-1-2");
|
||||
assertThat(response.getBody().getGroupIds())
|
||||
.containsExactlyInAnyOrder("cn=organisationseinheit ksc 1,cn=organisationseinheit "
|
||||
+ "ksc,cn=organisation,ou=test,o=taskana",
|
||||
"cn=ksc-users,cn=groups,ou=test,o=taskana", "cn=g02,cn=groups,ou=test,o=taskana",
|
||||
"cn=g01,cn=groups,ou=test,o=taskana");
|
||||
assertThat(response.getBody().getRoles())
|
||||
.contains(TaskanaRole.USER)
|
||||
.doesNotContain(TaskanaRole.ADMIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnCustomAttributes() {
|
||||
String url = restHelper.toUrl(RestEndpoints.URL_CUSTOM_ATTRIBUTES);
|
||||
|
|
|
@ -17,11 +17,14 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
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;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
|
@ -45,37 +48,39 @@ class LdapClientTest {
|
|||
|
||||
@Spy @InjectMocks LdapClient cut;
|
||||
|
||||
@Test
|
||||
void should_SearchGroupByDn_For_LdapCall() {
|
||||
@ParameterizedTest
|
||||
@CsvSource(value = {
|
||||
"cn=developersgroup,ou=groups,o=taskanatest;cn=developersgroup,ou=groups",
|
||||
"cn=developers:permission,cn=groups;"
|
||||
+ "cn=developers:permission,cn=groups",
|
||||
"cn=Developersgroup,ou=groups,o=taskanatest;cn=developersgroup,ou=groups",
|
||||
"cn=Developers:Permission,cn=groups,o=taskanatest;"
|
||||
+ "cn=developers:permission,cn=groups"
|
||||
}, delimiter = ';')
|
||||
void should_SearchGroupOrPermissionByDnAndConvertAccessIdToLowercase_For_LdapCall(String arg1,
|
||||
String arg2) throws InvalidNameException {
|
||||
setUpEnvMock();
|
||||
cut.init();
|
||||
|
||||
cut.searchAccessIdByDn("cn=developersgroup,ou=groups,o=taskanatest");
|
||||
cut.searchAccessIdByDn(arg1);
|
||||
|
||||
verify(ldapTemplate)
|
||||
.lookup(eq("cn=developersgroup,ou=groups"), any(), any(LdapClient.DnContextMapper.class));
|
||||
.lookup(eq(new LdapName(arg2)), any(), any(LdapClient.DnContextMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ConvertAccessIdToLowercase_When_SearchingGroupByDn() {
|
||||
setUpEnvMock();
|
||||
cut.init();
|
||||
|
||||
cut.searchAccessIdByDn("cn=Developersgroup,ou=groups,o=taskanatest");
|
||||
|
||||
verify(ldapTemplate)
|
||||
.lookup(eq("cn=developersgroup,ou=groups"), any(), any(LdapClient.DnContextMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLdap_searchUsersAndGroups() throws Exception {
|
||||
void testLdap_searchUsersAndGroupsAndPermissions() throws Exception {
|
||||
|
||||
setUpEnvMock();
|
||||
cut.init();
|
||||
|
||||
AccessIdRepresentationModel permission = new AccessIdRepresentationModel("testP", "testPId");
|
||||
AccessIdRepresentationModel group = new AccessIdRepresentationModel("testG", "testGId");
|
||||
AccessIdRepresentationModel user = new AccessIdRepresentationModel("testU", "testUId");
|
||||
|
||||
when(ldapTemplate.search(
|
||||
any(String.class), any(), anyInt(), any(), any(LdapClient.PermissionContextMapper.class)))
|
||||
.thenReturn(List.of(permission));
|
||||
when(ldapTemplate.search(
|
||||
any(String.class), any(), anyInt(), any(), any(LdapClient.GroupContextMapper.class)))
|
||||
.thenReturn(List.of(group));
|
||||
|
@ -83,7 +88,9 @@ class LdapClientTest {
|
|||
any(String.class), any(), anyInt(), any(), any(LdapClient.UserContextMapper.class)))
|
||||
.thenReturn(List.of(user));
|
||||
|
||||
assertThat(cut.searchUsersAndGroups("test")).hasSize(2).containsExactlyInAnyOrder(user, group);
|
||||
assertThat(cut.searchUsersAndGroupsAndPermissions("test"))
|
||||
.hasSize(3)
|
||||
.containsExactlyInAnyOrder(user, group, permission);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -105,19 +112,21 @@ class LdapClientTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnAllUsersAndMembersOfGroupsWithTaskanaUserRole() throws Exception {
|
||||
void should_ReturnAllUsersAndMembersOfGroupsAndMemberOfPermissionsWithTaskanaUserRole() {
|
||||
|
||||
setUpEnvMock();
|
||||
cut.init();
|
||||
|
||||
AccessIdRepresentationModel user = new AccessIdRepresentationModel("testU", "testUId");
|
||||
|
||||
Set<String> groupsOfUserRole = new HashSet<>();
|
||||
Map<TaskanaRole, Set<String>> roleMap = new HashMap<>();
|
||||
roleMap.put(TaskanaRole.USER, groupsOfUserRole);
|
||||
Set<String> permissionsOfUserRole = new HashSet<>();
|
||||
roleMap.put(TaskanaRole.USER, permissionsOfUserRole);
|
||||
|
||||
when(taskanaConfiguration.getRoleMap()).thenReturn(roleMap);
|
||||
|
||||
AccessIdRepresentationModel user = new AccessIdRepresentationModel("testU", "testUId");
|
||||
|
||||
when(ldapTemplate.search(
|
||||
any(String.class), any(), anyInt(), any(), any(LdapClient.UserContextMapper.class)))
|
||||
.thenReturn(List.of(user));
|
||||
|
@ -126,7 +135,7 @@ class LdapClientTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void testLdap_getNameWithoutBaseDn() {
|
||||
void testLdap_getNameWithoutBaseDnForGroup() {
|
||||
|
||||
setUpEnvMock();
|
||||
cut.init();
|
||||
|
@ -135,11 +144,23 @@ class LdapClientTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void shouldNot_CreateOrCriteriaWithDnAndAccessIdString_When_PropertyTypeIsSet()
|
||||
throws InvalidArgumentException {
|
||||
void testLdap_getNameWithoutBaseDnForPermission() {
|
||||
|
||||
setUpEnvMock();
|
||||
lenient().when(this.environment.getProperty("taskana.ldap.groupsOfUser.type")).thenReturn("dn");
|
||||
cut.init();
|
||||
assertThat(cut.getNameWithoutBaseDn("cn=other:permission,cn=groups,o=taskanatest"))
|
||||
.isEqualTo("cn=other:permission,cn=groups");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNot_CreateOrCriteriaWithDnAndAccessIdStringForGroup_When_PropertyTypeIsSet()
|
||||
throws InvalidArgumentException, InvalidNameException {
|
||||
|
||||
setUpEnvMock();
|
||||
lenient().when(this.environment.getProperty("taskana.ldap.groupsOfUser.type"))
|
||||
.thenReturn("dn");
|
||||
lenient().when(this.environment.getProperty("taskana.ldap.permissionsOfUser.type"))
|
||||
.thenReturn("dn");
|
||||
lenient()
|
||||
.when(
|
||||
ldapTemplate.search(
|
||||
|
@ -153,9 +174,10 @@ class LdapClientTest {
|
|||
cut.init();
|
||||
|
||||
cut.searchGroupsAccessIdIsMemberOf("user-1-1");
|
||||
cut.searchPermissionsAccessIdHas("user-1-1");
|
||||
|
||||
String expectedFilterValue =
|
||||
"(&(objectclass=groupOfUniqueNames)(memberUid=uid=user-1-1,cn=users,OU=Test,O=TASKANA))";
|
||||
String expectedFilterValue = "(&(!(permission=*))"
|
||||
+ "(&(objectclass=groupOfUniqueNames)(memberUid=uid=user-1-1,cn=users,OU=Test,O=TASKANA)))";
|
||||
verify(ldapTemplate)
|
||||
.search(
|
||||
any(String.class),
|
||||
|
@ -163,6 +185,16 @@ class LdapClientTest {
|
|||
anyInt(),
|
||||
any(),
|
||||
any(LdapClient.GroupContextMapper.class));
|
||||
|
||||
String expectedFilterValueForPermission = "(&(permission=*)"
|
||||
+ "(&(objectclass=groupOfUniqueNames)(memberUid=uid=user-1-1,cn=users,OU=Test,O=TASKANA)))";
|
||||
verify(ldapTemplate)
|
||||
.search(
|
||||
any(String.class),
|
||||
eq(expectedFilterValueForPermission),
|
||||
anyInt(),
|
||||
any(),
|
||||
any(LdapClient.PermissionContextMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -173,7 +205,7 @@ class LdapClientTest {
|
|||
List<AccessIdRepresentationModel> result =
|
||||
IntStream.range(0, 100)
|
||||
.mapToObj(i -> new AccessIdRepresentationModel("" + i, "" + i))
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
|
||||
assertThat(cut.getFirstPageOfaResultList(result))
|
||||
.hasSize(cut.getMaxNumberOfReturnedAccessIds());
|
||||
|
@ -193,7 +225,7 @@ class LdapClientTest {
|
|||
// userMobilePhoneAttribute, userEmailAttribute, userOrglevel1Attribute, userOrglevel2Attribute,
|
||||
// userOrglevel3Attribute, userOrglevel4Attribute, groupsOfUser, groupsOfUserName,
|
||||
// groupOfUserType
|
||||
assertThat(cut.checkForMissingConfigurations()).hasSize(LdapSettings.values().length - 12);
|
||||
assertThat(cut.checkForMissingConfigurations()).hasSize(LdapSettings.values().length - 15);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -231,7 +263,14 @@ class LdapClientTest {
|
|||
{"taskana.ldap.userOrglevel1Attribute", "orgLevel1"},
|
||||
{"taskana.ldap.userOrglevel2Attribute", "orgLevel2"},
|
||||
{"taskana.ldap.userOrglevel3Attribute", "orgLevel3"},
|
||||
{"taskana.ldap.userOrglevel4Attribute", "orgLevel4"}
|
||||
{"taskana.ldap.userOrglevel4Attribute", "orgLevel4"},
|
||||
{"taskana.ldap.permissionsOfUser", "memberUid"},
|
||||
{"taskana.ldap.permissionNameAttribute", "permission"},
|
||||
{"taskana.ldap.permissionSearchFilterValue", "groupOfUniqueNames"},
|
||||
{"taskana.ldap.permissionSearchFilterName", "objectclass"},
|
||||
{"taskana.ldap.permissionSearchBase", "ou=groups"},
|
||||
{"taskana.ldap.userPermissionsAttribute", "permission"},
|
||||
{"taskana.ldap.useDnForGroups", "false"},
|
||||
})
|
||||
.forEach(
|
||||
strings ->
|
||||
|
|
|
@ -4,7 +4,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static pro.taskana.rest.test.RestHelper.TEMPLATE;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
|
@ -42,7 +41,7 @@ class WorkbasketControllerIntTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void testGetWorkbasket() throws UnsupportedEncodingException {
|
||||
void testGetWorkbasket() {
|
||||
final String url =
|
||||
restHelper.toUrl(
|
||||
RestEndpoints.URL_WORKBASKET_ID, "WBI%3A100000000000000000000000000000000006");
|
||||
|
@ -278,7 +277,7 @@ class WorkbasketControllerIntTest {
|
|||
assertThat(response.getBody()).isNotNull();
|
||||
assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull();
|
||||
assertThat(response.getHeaders().getContentType()).isEqualTo(MediaTypes.HAL_JSON);
|
||||
assertThat(response.getBody().getContent()).hasSize(3);
|
||||
assertThat(response.getBody().getContent()).hasSize(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -37,6 +37,13 @@ taskana.ldap.minSearchForLength=3
|
|||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||
taskana.ldap.groupsOfUser=uniquemember
|
||||
taskana.ldap.groupsOfUser.type=
|
||||
taskana.ldap.permissionSearchBase=
|
||||
taskana.ldap.permissionSearchFilterName=objectclass
|
||||
taskana.ldap.permissionSearchFilterValue=groupofuniquenames
|
||||
taskana.ldap.permissionNameAttribute=permission
|
||||
taskana.ldap.permissionsOfUser=uniquemember
|
||||
taskana.ldap.useDnForGroups=true
|
||||
|
||||
# Embedded Spring LDAP server
|
||||
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
||||
spring.ldap.embedded.credential.username=uid=admin
|
||||
|
|
|
@ -42,6 +42,12 @@ taskana.ldap.groupNameAttribute=cn
|
|||
taskana.ldap.minSearchForLength=3
|
||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||
taskana.ldap.groupsOfUser=uniquemember
|
||||
taskana.ldap.permissionSearchBase=
|
||||
taskana.ldap.permissionSearchFilterName=objectclass
|
||||
taskana.ldap.permissionSearchFilterValue=groupofuniquenames
|
||||
taskana.ldap.permissionNameAttribute=permission
|
||||
taskana.ldap.permissionsOfUser=uniquemember
|
||||
taskana.ldap.useDnForGroups=true
|
||||
# Embedded Spring LDAP server
|
||||
spring.ldap.embedded.base-dn= OU=Test,O=TASKANA
|
||||
spring.ldap.embedded.credential.username= uid=admin
|
||||
|
|
|
@ -34,6 +34,29 @@
|
|||
<ng-template #noGroups>The user is not associated to any groups </ng-template>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<!-- EXPANSION PANEL PERMISSIONS -->
|
||||
<mat-expansion-panel *ngIf="accessItemsForm" class="access-items__permissions-expansion-panel">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
Permissions of {{accessId.accessId}}</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<!-- TABLE WITH PERMISSION NAMES AND ACCESS IDs -->
|
||||
<table *ngIf="permissions && permissions.length > 0; else noPermissions" mat-table [dataSource]="permissions">
|
||||
<ng-container matColumnDef="Name">
|
||||
<th mat-header-cell *matHeaderCellDef> Name </th>
|
||||
<td mat-cell class="access-items__permission-table-cell" *matCellDef="let element"> {{element.name}} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="Access Id">
|
||||
<th mat-header-cell *matHeaderCellDef> Access Id </th>
|
||||
<td mat-cell class="access-items__permission-table-cell" *matCellDef="let element"> {{element.accessId}} </td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="['Name', 'Access Id']"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: ['Name', 'Access Id'];"></tr>
|
||||
</table>
|
||||
|
||||
<ng-template #noPermissions>The user is not associated to any permissions </ng-template>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<!-- EXPANSION PANEL AUTHORIZATION -->
|
||||
<mat-expansion-panel *ngIf="accessItemsForm" [expanded]="true" class="access-items__authorization-expansion-panel">
|
||||
<mat-expansion-panel-header>
|
||||
|
|
|
@ -45,6 +45,11 @@ tr:first-child > td {
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
&__permission-table-cell {
|
||||
height: 48px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__table {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
@ -67,6 +72,11 @@ tr:first-child > td {
|
|||
left: 1%;
|
||||
}
|
||||
|
||||
&__permissions-expansion-panel {
|
||||
width: 98%;
|
||||
left: 1%;
|
||||
}
|
||||
|
||||
&__authorization-expansion-panel {
|
||||
width: 98%;
|
||||
left: 1%;
|
||||
|
|
|
@ -146,6 +146,9 @@ describe('AccessItemsManagementComponent', () => {
|
|||
|
||||
const groups = store.selectSnapshot((state) => state.accessItemsManagement);
|
||||
expect(groups).toBeDefined();
|
||||
|
||||
const permissions = store.selectSnapshot((state) => state.accessItemsManagement);
|
||||
expect(permissions).toBeDefined();
|
||||
});
|
||||
|
||||
it('should be able to get groups if selected access ID is not null in onSelectAccessId', () => {
|
||||
|
@ -158,12 +161,30 @@ describe('AccessItemsManagementComponent', () => {
|
|||
expect(groups).toMatchObject({});
|
||||
});
|
||||
|
||||
it('should be able to get permissions if selected access ID is not null in onSelectAccessId', () => {
|
||||
const selectedAccessId = { accessId: '1', name: '' };
|
||||
app.permissions = [
|
||||
{ accessId: '1', name: 'perm' },
|
||||
{ accessId: '2', name: 'perm' }
|
||||
];
|
||||
app.onSelectAccessId(selectedAccessId);
|
||||
const permissions = store.selectSnapshot((state) => state.accessItemsManagement);
|
||||
expect(selectedAccessId).not.toBeNull();
|
||||
expect(permissions).not.toBeNull();
|
||||
app.onSelectAccessId(null);
|
||||
expect(permissions).toMatchObject({});
|
||||
});
|
||||
|
||||
it('should dispatch GetAccessItems action in searchForAccessItemsWorkbaskets', async((done) => {
|
||||
app.accessId = { accessId: '1', name: 'max' };
|
||||
app.groups = [
|
||||
{ accessId: '1', name: 'users' },
|
||||
{ accessId: '2', name: 'users' }
|
||||
];
|
||||
app.permissions = [
|
||||
{ accessId: '1', name: 'perm' },
|
||||
{ accessId: '2', name: 'perm' }
|
||||
];
|
||||
app.sortModel = {
|
||||
'sort-by': WorkbasketAccessItemQuerySortParameter.ACCESS_ID,
|
||||
order: Direction.DESC
|
||||
|
@ -175,6 +196,7 @@ describe('AccessItemsManagementComponent', () => {
|
|||
actionDispatched = true;
|
||||
expect(actionDispatched).toBe(true);
|
||||
expect(app.setAccessItemsGroups).toHaveBeenCalled();
|
||||
expect(app.setAccessItemsPermissions).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
@ -194,6 +216,12 @@ describe('AccessItemsManagementComponent', () => {
|
|||
expect(app.accessItemsForm).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should create accessItemsForm in setAccessItemsPermissions', () => {
|
||||
app.setAccessItemsPermissions([]);
|
||||
expect(app.accessItemsForm).toBeDefined();
|
||||
expect(app.accessItemsForm).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should invoke sorting function correctly', () => {
|
||||
const newSort: Sorting<WorkbasketAccessItemQuerySortParameter> = {
|
||||
'sort-by': WorkbasketAccessItemQuerySortParameter.ACCESS_ID,
|
||||
|
@ -201,6 +229,7 @@ describe('AccessItemsManagementComponent', () => {
|
|||
};
|
||||
app.accessId = { accessId: '1', name: 'max' };
|
||||
app.groups = [{ accessId: '1', name: 'users' }];
|
||||
app.permissions = [{ accessId: '1', name: 'perm' }];
|
||||
app.sorting(newSort);
|
||||
expect(app.sortModel).toMatchObject(newSort);
|
||||
});
|
||||
|
@ -209,4 +238,9 @@ describe('AccessItemsManagementComponent', () => {
|
|||
app.accessItemsForm = null;
|
||||
expect(app.accessItemsGroups).toBeNull();
|
||||
});
|
||||
|
||||
it('should not return accessItemsPermissions when accessItemsForm is null', () => {
|
||||
app.accessItemsForm = null;
|
||||
expect(app.accessItemsPermissions).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@ import { AccessItemsCustomisation, CustomField, getCustomFields } from '../../..
|
|||
import { customFieldCount } from '../../../shared/models/workbasket-access-items';
|
||||
import {
|
||||
GetAccessItems,
|
||||
GetPermissionsByAccessId,
|
||||
GetGroupsByAccessId,
|
||||
RemoveAccessItemsPermissions
|
||||
} from '../../../shared/store/access-items-management-store/access-items-management.actions';
|
||||
|
@ -38,6 +39,7 @@ export class AccessItemsManagementComponent implements OnInit {
|
|||
accessItemsForm: FormGroup;
|
||||
accessId: AccessId;
|
||||
groups: AccessId[];
|
||||
permissions: AccessId[];
|
||||
defaultSortBy: WorkbasketAccessItemQuerySortParameter = WorkbasketAccessItemQuerySortParameter.ACCESS_ID;
|
||||
sortingFields: Map<WorkbasketAccessItemQuerySortParameter, string> = WORKBASKET_ACCESS_ITEM_SORT_PARAMETER_NAMING;
|
||||
sortModel: Sorting<WorkbasketAccessItemQuerySortParameter> = {
|
||||
|
@ -46,11 +48,13 @@ export class AccessItemsManagementComponent implements OnInit {
|
|||
};
|
||||
accessItems: WorkbasketAccessItems[];
|
||||
isGroup: boolean = false;
|
||||
isPermission: boolean = false;
|
||||
|
||||
@Select(EngineConfigurationSelectors.accessItemsCustomisation)
|
||||
accessItemsCustomization$: Observable<AccessItemsCustomisation>;
|
||||
@Select(AccessItemsManagementSelector.groups) groups$: Observable<AccessId[]>;
|
||||
customFields$: Observable<CustomField[]>;
|
||||
@Select(AccessItemsManagementSelector.permissions) permissions$: Observable<AccessId[]>;
|
||||
destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
|
@ -65,6 +69,9 @@ export class AccessItemsManagementComponent implements OnInit {
|
|||
this.groups$.pipe(takeUntil(this.destroy$)).subscribe((groups) => {
|
||||
this.groups = groups;
|
||||
});
|
||||
this.permissions$.pipe(takeUntil(this.destroy$)).subscribe((permissions) => {
|
||||
this.permissions = permissions;
|
||||
});
|
||||
}
|
||||
|
||||
onSelectAccessId(selected: AccessId) {
|
||||
|
@ -79,6 +86,12 @@ export class AccessItemsManagementComponent implements OnInit {
|
|||
.subscribe(() => {
|
||||
this.searchForAccessItemsWorkbaskets();
|
||||
});
|
||||
this.store
|
||||
.dispatch(new GetPermissionsByAccessId(selected.accessId))
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(() => {
|
||||
this.searchForAccessItemsWorkbaskets();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.accessItemsForm = null;
|
||||
|
@ -88,19 +101,40 @@ export class AccessItemsManagementComponent implements OnInit {
|
|||
|
||||
searchForAccessItemsWorkbaskets() {
|
||||
this.removeFocus();
|
||||
const filterParameter: WorkbasketAccessItemQueryFilterParameter = {
|
||||
'access-id': [this.accessId, ...this.groups].map((a) => a.accessId)
|
||||
};
|
||||
this.store
|
||||
.dispatch(new GetAccessItems(filterParameter, this.sortModel))
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((state) => {
|
||||
this.setAccessItemsGroups(
|
||||
state['accessItemsManagement'].accessItemsResource
|
||||
? state['accessItemsManagement'].accessItemsResource.accessItems
|
||||
: []
|
||||
);
|
||||
});
|
||||
if (this.permissions == null) {
|
||||
const filterParameter: WorkbasketAccessItemQueryFilterParameter = {
|
||||
'access-id': [this.accessId, ...this.groups].map((a) => a.accessId)
|
||||
};
|
||||
this.store
|
||||
.dispatch(new GetAccessItems(filterParameter, this.sortModel))
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((state) => {
|
||||
this.setAccessItemsGroups(
|
||||
state['accessItemsManagement'].accessItemsResource
|
||||
? state['accessItemsManagement'].accessItemsResource.accessItems
|
||||
: []
|
||||
);
|
||||
});
|
||||
} else {
|
||||
const filterParameter: WorkbasketAccessItemQueryFilterParameter = {
|
||||
'access-id': [this.accessId, ...this.groups, ...this.permissions].map((a) => a.accessId)
|
||||
};
|
||||
this.store
|
||||
.dispatch(new GetAccessItems(filterParameter, this.sortModel))
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((state) => {
|
||||
this.setAccessItemsPermissions(
|
||||
state['accessItemsManagement'].accessItemsResource
|
||||
? state['accessItemsManagement'].accessItemsResource.accessItems
|
||||
: []
|
||||
);
|
||||
this.setAccessItemsGroups(
|
||||
state['accessItemsManagement'].accessItemsResource
|
||||
? state['accessItemsManagement'].accessItemsResource.accessItems
|
||||
: []
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setAccessItemsGroups(accessItems: Array<WorkbasketAccessItems>) {
|
||||
|
@ -129,6 +163,32 @@ export class AccessItemsManagementComponent implements OnInit {
|
|||
}
|
||||
}
|
||||
|
||||
setAccessItemsPermissions(accessItems: Array<WorkbasketAccessItems>) {
|
||||
const AccessItemsFormPermissions = accessItems.map((accessItem) => this.formBuilder.group(accessItem));
|
||||
AccessItemsFormPermissions.forEach((accessItemPermission) => {
|
||||
accessItemPermission.controls.accessId.setValidators(Validators.required);
|
||||
Object.keys(accessItemPermission.controls).forEach((key) => {
|
||||
accessItemPermission.controls[key].disable();
|
||||
});
|
||||
});
|
||||
|
||||
const AccessItemsFormArray = this.formBuilder.array(AccessItemsFormPermissions);
|
||||
if (!this.accessItemsForm) {
|
||||
this.accessItemsForm = this.formBuilder.group({});
|
||||
}
|
||||
this.accessItemsForm.setControl('accessItemsPermissions', AccessItemsFormArray);
|
||||
if (!this.accessItemsForm.value.workbasketKeyFilter) {
|
||||
this.accessItemsForm.addControl('workbasketKeyFilter', new FormControl());
|
||||
}
|
||||
if (!this.accessItemsForm.value.accessIdFilter) {
|
||||
this.accessItemsForm.addControl('accessIdFilter', new FormControl());
|
||||
}
|
||||
this.accessItems = accessItems;
|
||||
if (this.accessItemsForm.value.workbasketKeyFilter || this.accessItemsForm.value.accessIdFilter) {
|
||||
this.filterAccessItems();
|
||||
}
|
||||
}
|
||||
|
||||
filterAccessItems() {
|
||||
if (this.accessItemsForm.value.accessIdFilter) {
|
||||
this.accessItems = this.accessItems.filter((value) =>
|
||||
|
@ -161,8 +221,15 @@ export class AccessItemsManagementComponent implements OnInit {
|
|||
return this.accessItemsForm ? (this.accessItemsForm.get('accessItemsGroups') as FormArray) : null;
|
||||
}
|
||||
|
||||
get accessItemsPermissions(): FormArray {
|
||||
return this.accessItemsForm ? (this.accessItemsForm.get('accessItemsPermissions') as FormArray) : null;
|
||||
}
|
||||
|
||||
isFieldValid(field: string, index: number): boolean {
|
||||
return this.formsValidatorService.isFieldValid(this.accessItemsGroups[index], field);
|
||||
return (
|
||||
this.formsValidatorService.isFieldValid(this.accessItemsGroups[index], field) ||
|
||||
this.formsValidatorService.isFieldValid(this.accessItemsPermissions[index], field)
|
||||
);
|
||||
}
|
||||
|
||||
sorting(sort: Sorting<WorkbasketAccessItemQuerySortParameter>) {
|
||||
|
|
|
@ -157,7 +157,13 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
|
|||
this.selectedWorkbasket$.pipe(take(1)).subscribe((workbasket) => {
|
||||
this.accessItemsRepresentation._links = { self: { href: workbasket._links.accessItems.href } };
|
||||
this.setWorkbasketIdForCopy(workbasket.workbasketId);
|
||||
this.onSave();
|
||||
this.formsValidatorService
|
||||
.validateFormAccess(this.accessItemsGroups, this.toggleValidationAccessIdMap)
|
||||
.then((value) => {
|
||||
if (value) {
|
||||
this.onSave();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -3,13 +3,17 @@ import { DebugElement } from '@angular/core';
|
|||
import { TypeAheadComponent } from './type-ahead.component';
|
||||
import { AccessIdsService } from '../../services/access-ids/access-ids.service';
|
||||
import { of } from 'rxjs';
|
||||
import { NgxsModule } from '@ngxs/store';
|
||||
import { NgxsModule, Store } from '@ngxs/store';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { EngineConfigurationState } from '../../store/engine-configuration-store/engine-configuration.state';
|
||||
import { ClassificationCategoriesService } from '../../services/classification-categories/classification-categories.service';
|
||||
import { engineConfigurationMock } from '../../store/mock-data/mock-store';
|
||||
|
||||
const accessIdService: Partial<AccessIdsService> = {
|
||||
searchForAccessId: jest.fn().mockReturnValue(of([{ accessId: 'user-g-1', name: 'Gerda' }]))
|
||||
|
@ -19,23 +23,29 @@ describe('TypeAheadComponent with AccessId input', () => {
|
|||
let fixture: ComponentFixture<TypeAheadComponent>;
|
||||
let debugElement: DebugElement;
|
||||
let component: TypeAheadComponent;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
NgxsModule.forRoot([]),
|
||||
NgxsModule.forRoot([EngineConfigurationState]),
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatAutocompleteModule,
|
||||
MatTooltipModule,
|
||||
NoopAnimationsModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule
|
||||
ReactiveFormsModule,
|
||||
HttpClientModule
|
||||
],
|
||||
declarations: [TypeAheadComponent],
|
||||
providers: [{ provide: AccessIdsService, useValue: accessIdService }]
|
||||
providers: [{ provide: AccessIdsService, useValue: accessIdService }, ClassificationCategoriesService]
|
||||
}).compileComponents();
|
||||
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
engineConfiguration: engineConfigurationMock
|
||||
});
|
||||
fixture = TestBed.createComponent(TypeAheadComponent);
|
||||
debugElement = fixture.debugElement;
|
||||
component = fixture.componentInstance;
|
||||
|
@ -53,7 +63,7 @@ describe('TypeAheadComponent with AccessId input', () => {
|
|||
input.dispatchEvent(new Event('input'));
|
||||
component.accessIdForm.get('accessId').updateValueAndValidity({ emitEvent: true });
|
||||
|
||||
tick();
|
||||
tick(50);
|
||||
expect(component.name).toBe('Gerda');
|
||||
}));
|
||||
|
||||
|
@ -63,7 +73,7 @@ describe('TypeAheadComponent with AccessId input', () => {
|
|||
component.accessIdForm.get('accessId').setValue('invalid-user');
|
||||
component.accessIdForm.get('accessId').updateValueAndValidity({ emitEvent: true });
|
||||
|
||||
tick();
|
||||
tick(50);
|
||||
fixture.detectChanges();
|
||||
expect(emitSpy).toHaveBeenCalledWith(false);
|
||||
}));
|
||||
|
@ -73,7 +83,7 @@ describe('TypeAheadComponent with AccessId input', () => {
|
|||
component.accessIdForm.get('accessId').setValue('user-g-1');
|
||||
component.accessIdForm.get('accessId').updateValueAndValidity({ emitEvent: true });
|
||||
|
||||
tick();
|
||||
tick(50);
|
||||
fixture.detectChanges();
|
||||
expect(emitSpy).toHaveBeenCalledWith(true);
|
||||
}));
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core';
|
||||
import { AccessIdsService } from '../../services/access-ids/access-ids.service';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged, Observable, Subject } from 'rxjs';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { AccessId } from '../../models/access-id';
|
||||
import { take, takeUntil } from 'rxjs/operators';
|
||||
import { map, take, takeUntil } from 'rxjs/operators';
|
||||
import { Select } from '@ngxs/store';
|
||||
import { WorkbasketSelectors } from '../../store/workbasket-store/workbasket.selectors';
|
||||
import { ButtonAction } from '../../../administration/models/button-action';
|
||||
import { EngineConfigurationSelectors } from '../../store/engine-configuration-store/engine-configuration.selectors';
|
||||
import { GlobalCustomisation } from '../../models/customisation';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-shared-type-ahead',
|
||||
|
@ -24,12 +26,16 @@ export class TypeAheadComponent implements OnInit, OnDestroy {
|
|||
@Output() accessIdEventEmitter = new EventEmitter<AccessId>();
|
||||
@Output() isFormValid = new EventEmitter<boolean>();
|
||||
|
||||
@Select(EngineConfigurationSelectors.globalCustomisation)
|
||||
globalCustomisation$: Observable<GlobalCustomisation>;
|
||||
|
||||
@Select(WorkbasketSelectors.buttonAction)
|
||||
buttonAction$: Observable<ButtonAction>;
|
||||
|
||||
name: string = '';
|
||||
lastSavedAccessId: string = '';
|
||||
filteredAccessIds: AccessId[] = [];
|
||||
debounceTime: number = 750;
|
||||
destroy$ = new Subject<void>();
|
||||
accessIdForm = new FormGroup({
|
||||
accessId: new FormControl('')
|
||||
|
@ -57,14 +63,27 @@ export class TypeAheadComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
});
|
||||
|
||||
this.accessIdForm.controls['accessId'].valueChanges.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
||||
const value = this.accessIdForm.controls['accessId'].value;
|
||||
if (value === '') {
|
||||
this.handleEmptyAccessId();
|
||||
return;
|
||||
}
|
||||
this.searchForAccessId(value);
|
||||
});
|
||||
this.globalCustomisation$
|
||||
.pipe(
|
||||
take(1),
|
||||
map((customisation) => customisation?.debounceTimeLookupField)
|
||||
)
|
||||
.subscribe((debounceTime) => {
|
||||
if (!!debounceTime) {
|
||||
this.debounceTime = debounceTime;
|
||||
}
|
||||
});
|
||||
|
||||
this.accessIdForm.controls['accessId'].valueChanges
|
||||
.pipe(debounceTime(this.debounceTime), distinctUntilChanged(), takeUntil(this.destroy$))
|
||||
.subscribe(() => {
|
||||
const value = this.accessIdForm.controls['accessId'].value;
|
||||
if (value === '') {
|
||||
this.handleEmptyAccessId();
|
||||
return;
|
||||
}
|
||||
this.searchForAccessId(value);
|
||||
});
|
||||
|
||||
this.setAccessIdFromInput();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ export interface Customisation {
|
|||
}
|
||||
|
||||
export interface CustomisationContent {
|
||||
global?: GlobalCustomisation;
|
||||
workbaskets?: WorkbasketsCustomisation;
|
||||
classifications?: ClassificationsCustomisation;
|
||||
tasks?: TasksCustomisation;
|
||||
|
@ -31,6 +32,10 @@ export interface WorkbasketsCustomisation {
|
|||
'access-items'?: AccessItemsCustomisation;
|
||||
}
|
||||
|
||||
export interface GlobalCustomisation {
|
||||
debounceTimeLookupField: number;
|
||||
}
|
||||
|
||||
export type AccessItemsCustomisation = { accessId?: LookupField } & CustomFields;
|
||||
|
||||
export interface CustomFields {
|
||||
|
|
|
@ -34,6 +34,13 @@ export class AccessIdsService {
|
|||
return this.httpClient.get<AccessId[]>(`${this.url}/groups?access-id=${accessId}`);
|
||||
}
|
||||
|
||||
getPermissionsByAccessId(accessId: string): Observable<AccessId[]> {
|
||||
if (!accessId || accessId.length < 3) {
|
||||
return of([]);
|
||||
}
|
||||
return this.httpClient.get<AccessId[]>(`${this.url}/permissions?access-id=${accessId}`);
|
||||
}
|
||||
|
||||
getAccessItems(
|
||||
filterParameter?: WorkbasketAccessItemQueryFilterParameter,
|
||||
sortParameter?: Sorting<WorkbasketAccessItemQuerySortParameter>,
|
||||
|
|
|
@ -90,7 +90,8 @@ export class FormsValidatorService {
|
|||
}
|
||||
|
||||
form.controls.forEach((control) => {
|
||||
const { permEditTasks, permReadTasks, permRead } = control.value;
|
||||
const { permEditTasks, permReadTasks, permRead, permOpen, permDistribute, permAppend, permTransfer } =
|
||||
control.value;
|
||||
|
||||
if (permEditTasks && (!permReadTasks || !permRead)) {
|
||||
this.notificationsService.showWarning('PERM_EDIT_TASKS_MISSING_DEPENDING_PERMISSION');
|
||||
|
@ -99,6 +100,14 @@ export class FormsValidatorService {
|
|||
if (permReadTasks && !permRead) {
|
||||
this.notificationsService.showWarning('PERM_READ_TASKS_MISSING_DEPENDING_PERMISSIONS');
|
||||
}
|
||||
|
||||
if (permOpen && (!permReadTasks || !permRead)) {
|
||||
this.notificationsService.showWarning('PERM_OPEN_MISSING_DEPENDING_PERMISSIONS');
|
||||
}
|
||||
|
||||
if (permDistribute && (!permAppend || !permTransfer)) {
|
||||
this.notificationsService.showWarning('PERM_DISTRIBUTE_MISSING_DEPENDING_PERMISSIONS');
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
|
|
|
@ -109,6 +109,12 @@ export const messageByErrorCode = {
|
|||
PERM_READ_TASKS_MISSING_DEPENDING_PERMISSIONS:
|
||||
'"Read tasks" permission was selected without the required "Read" permission. ' +
|
||||
'Your changes will still be saved but they might lead to unexpected behavior.',
|
||||
PERM_OPEN_MISSING_DEPENDING_PERMISSIONS:
|
||||
'"Open" permission was selected without the required "Read tasks" and "Read" permissions. ' +
|
||||
'Your changes will still be saved but they might lead to unexpected behavior.',
|
||||
PERM_DISTRIBUTE_MISSING_DEPENDING_PERMISSIONS:
|
||||
'"Distribute" permission was selected without the required "Append" and "Transfer" permissions. ' +
|
||||
'Your changes will still be saved but they might lead to unexpected behavior.',
|
||||
REPORT_DATA_WRONG_HEADER:
|
||||
'The received header of the Report data does not match the expected header. ' +
|
||||
'The data might be displayed incorrectly. Please contact your administrator.',
|
||||
|
|
|
@ -13,6 +13,11 @@ export class GetGroupsByAccessId {
|
|||
constructor(public accessId: string) {}
|
||||
}
|
||||
|
||||
export class GetPermissionsByAccessId {
|
||||
static readonly type = '[Access Items Management] Get permissions by access ID';
|
||||
constructor(public accessId: string) {}
|
||||
}
|
||||
|
||||
export class GetAccessItems {
|
||||
static readonly type = '[Access Items Management] Get access items';
|
||||
constructor(
|
||||
|
|
|
@ -7,4 +7,9 @@ export class AccessItemsManagementSelector {
|
|||
static groups(state: AccessItemsManagementStateModel): AccessId[] {
|
||||
return state.groups;
|
||||
}
|
||||
|
||||
@Selector([AccessItemsManagementState])
|
||||
static permissions(state: AccessItemsManagementStateModel): AccessId[] {
|
||||
return state.permissions;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Action, NgxsAfterBootstrap, State, StateContext } from '@ngxs/store';
|
||||
import {
|
||||
GetAccessItems,
|
||||
GetPermissionsByAccessId,
|
||||
GetGroupsByAccessId,
|
||||
RemoveAccessItemsPermissions,
|
||||
SelectAccessId
|
||||
|
@ -56,6 +57,26 @@ export class AccessItemsManagementState implements NgxsAfterBootstrap {
|
|||
);
|
||||
}
|
||||
|
||||
@Action(GetPermissionsByAccessId)
|
||||
getPermissionsByAccessId(
|
||||
ctx: StateContext<AccessItemsManagementStateModel>,
|
||||
action: GetPermissionsByAccessId
|
||||
): Observable<any> {
|
||||
return this.accessIdsService.getPermissionsByAccessId(action.accessId).pipe(
|
||||
take(1),
|
||||
tap(
|
||||
(permissions: AccessId[]) => {
|
||||
ctx.patchState({
|
||||
permissions
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Action(GetAccessItems)
|
||||
getAccessItems(ctx: StateContext<AccessItemsManagementStateModel>, action: GetAccessItems): Observable<any> {
|
||||
this.requestInProgressService.setRequestInProgress(true);
|
||||
|
@ -108,4 +129,5 @@ export interface AccessItemsManagementStateModel {
|
|||
accessItemsResource: WorkbasketAccessItemsRepresentation;
|
||||
selectedAccessId: AccessId;
|
||||
groups: AccessId[];
|
||||
permissions: AccessId[];
|
||||
}
|
||||
|
|
|
@ -3,12 +3,18 @@ import {
|
|||
ClassificationsCustomisation,
|
||||
AccessItemsCustomisation,
|
||||
TasksCustomisation,
|
||||
ClassificationCategoryImages
|
||||
ClassificationCategoryImages,
|
||||
GlobalCustomisation
|
||||
} from 'app/shared/models/customisation';
|
||||
import { Selector } from '@ngxs/store';
|
||||
import { EngineConfigurationStateModel, EngineConfigurationState } from './engine-configuration.state';
|
||||
|
||||
export class EngineConfigurationSelectors {
|
||||
@Selector([EngineConfigurationState])
|
||||
static globalCustomisation(state: EngineConfigurationStateModel): GlobalCustomisation {
|
||||
return state.customisation[state.language].global;
|
||||
}
|
||||
|
||||
@Selector([EngineConfigurationState])
|
||||
static workbasketsCustomisation(state: EngineConfigurationStateModel): WorkbasketsCustomisation {
|
||||
return state.customisation[state.language].workbaskets;
|
||||
|
|
|
@ -17,6 +17,9 @@ export const classificationStateMock = {
|
|||
export const engineConfigurationMock = {
|
||||
customisation: {
|
||||
EN: {
|
||||
global: {
|
||||
debounceTimeLookupField: 50
|
||||
},
|
||||
workbaskets: {
|
||||
information: {
|
||||
owner: {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
{
|
||||
"EN": {
|
||||
"global": {
|
||||
"debounceTimeLookupField": 750
|
||||
},
|
||||
"workbaskets": {
|
||||
"information": {
|
||||
"owner": {
|
||||
|
|
Loading…
Reference in New Issue