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
|
-- 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 (ID , WB_ID , ACCESS_ID , ACCESS_NAME , READ , OPEN , APPEND, TRANSFER, DISTRIBUTE, C1, .., C12)
|
||||||
-- KSC authorizations
|
|
||||||
-- PPKs
|
-- 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: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);
|
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: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);
|
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
|
-- 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: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);
|
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: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: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);
|
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: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: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);
|
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[] groups() default {};
|
||||||
|
|
||||||
|
String[] permissions() default {};
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@interface WithAccessIds {
|
@interface WithAccessIds {
|
||||||
|
|
|
@ -7,7 +7,6 @@ import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
@ -215,11 +214,12 @@ class JaasExtensionTest {
|
||||||
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo(accessId.user());
|
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo(accessId.user());
|
||||||
}
|
}
|
||||||
|
|
||||||
@WithAccessId(user = "testtemplate1", groups = "abc")
|
@WithAccessId(user = "testtemplate1", groups = "abc", permissions = "perm")
|
||||||
@TestTemplate
|
@TestTemplate
|
||||||
void should_InjectCorrectAccessId_When_AnnotationExists_On_TestTemplate(WithAccessId accessId) {
|
void should_InjectCorrectAccessId_When_AnnotationExists_On_TestTemplate(WithAccessId accessId) {
|
||||||
assertThat(accessId.user()).isEqualTo("testtemplate1");
|
assertThat(accessId.user()).isEqualTo("testtemplate1");
|
||||||
assertThat(accessId.groups()).containsExactly("abc");
|
assertThat(accessId.groups()).containsExactly("abc");
|
||||||
|
assertThat(accessId.permissions()).containsExactly("perm");
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
@ -406,21 +406,21 @@ class JaasExtensionTest {
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
Iterable<DynamicTest> should_NotSetAccessIdForDynamicTestInIterable_When_AnnotationIsMissing() {
|
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)
|
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||||
@TestFactory
|
@TestFactory
|
||||||
Iterable<DynamicTest> should_SetAccessIdForDynamicTestInIterable_When_AnnotationExists() {
|
Iterable<DynamicTest> should_SetAccessIdForDynamicTestInIterable_When_AnnotationExists() {
|
||||||
return Stream.of(DYNAMIC_TEST_USER_DYNAMIC_TEST, DYNAMIC_TEST_USER_DYNAMIC_TEST)
|
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)
|
||||||
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||||
@TestFactory
|
@TestFactory
|
||||||
Iterable<DynamicTest> should_SetMultipleAccessIdForDynamicTestInIterable_When_AnnotationsExist() {
|
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
|
// WITH DynamicContainer
|
||||||
|
@ -431,7 +431,7 @@ class JaasExtensionTest {
|
||||||
Supplier<DynamicContainer> supplier =
|
Supplier<DynamicContainer> supplier =
|
||||||
() ->
|
() ->
|
||||||
dynamicContainer("dynamic container", Stream.of(NULL_DYNAMIC_TEST, NULL_DYNAMIC_TEST));
|
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)
|
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||||
|
@ -443,7 +443,7 @@ class JaasExtensionTest {
|
||||||
dynamicContainer(
|
dynamicContainer(
|
||||||
"dynamic container",
|
"dynamic container",
|
||||||
Stream.of(DYNAMIC_TEST_USER_DYNAMIC_TEST, DYNAMIC_TEST_USER_DYNAMIC_TEST));
|
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)
|
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||||
|
@ -455,7 +455,7 @@ class JaasExtensionTest {
|
||||||
() ->
|
() ->
|
||||||
dynamicContainer(
|
dynamicContainer(
|
||||||
"dynamic container", Stream.of(NOT_NULL_DYNAMIC_TEST, NOT_NULL_DYNAMIC_TEST));
|
"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
|
// WITH nested DynamicContainer
|
||||||
|
@ -467,7 +467,7 @@ class JaasExtensionTest {
|
||||||
() -> dynamicContainer("inside container", Stream.of(NULL_DYNAMIC_TEST, NULL_DYNAMIC_TEST));
|
() -> dynamicContainer("inside container", Stream.of(NULL_DYNAMIC_TEST, NULL_DYNAMIC_TEST));
|
||||||
Supplier<DynamicContainer> outsideSupplier =
|
Supplier<DynamicContainer> outsideSupplier =
|
||||||
() -> dynamicContainer("outside container", Stream.of(supplier.get(), NULL_DYNAMIC_TEST));
|
() -> 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)
|
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||||
|
@ -483,7 +483,7 @@ class JaasExtensionTest {
|
||||||
() ->
|
() ->
|
||||||
dynamicContainer(
|
dynamicContainer(
|
||||||
"outside container", Stream.of(supplier.get(), DYNAMIC_TEST_USER_DYNAMIC_TEST));
|
"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)
|
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
|
||||||
|
@ -498,7 +498,7 @@ class JaasExtensionTest {
|
||||||
Supplier<DynamicContainer> outsideSupplier =
|
Supplier<DynamicContainer> outsideSupplier =
|
||||||
() ->
|
() ->
|
||||||
dynamicContainer("outside container", Stream.of(supplier.get(), NOT_NULL_DYNAMIC_TEST));
|
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
|
// endregion
|
||||||
|
|
|
@ -34,6 +34,12 @@ taskana.ldap.groupNameAttribute=cn
|
||||||
taskana.ldap.minSearchForLength=3
|
taskana.ldap.minSearchForLength=3
|
||||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||||
taskana.ldap.groupsOfUser=memberUid
|
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
|
# Embedded Spring LDAP server
|
||||||
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
||||||
spring.ldap.embedded.credential.username=uid=admin
|
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";
|
"cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA";
|
||||||
public static final String GROUP_2_DN =
|
public static final String GROUP_2_DN =
|
||||||
"cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA";
|
"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 TaskanaConfiguration taskanaConfiguration;
|
||||||
protected static TaskanaEngine taskanaEngine;
|
protected static TaskanaEngine taskanaEngine;
|
||||||
|
|
|
@ -34,7 +34,7 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
||||||
|
|
||||||
columnValueList =
|
columnValueList =
|
||||||
workbasketService.createWorkbasketAccessItemQuery().listValues(ACCESS_ID, null);
|
workbasketService.createWorkbasketAccessItemQuery().listValues(ACCESS_ID, null);
|
||||||
assertThat(columnValueList).hasSize(10);
|
assertThat(columnValueList).hasSize(11);
|
||||||
|
|
||||||
columnValueList =
|
columnValueList =
|
||||||
workbasketService.createWorkbasketAccessItemQuery().listValues(WORKBASKET_KEY, null);
|
workbasketService.createWorkbasketAccessItemQuery().listValues(WORKBASKET_KEY, null);
|
||||||
|
@ -51,9 +51,9 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
||||||
List<WorkbasketAccessItem> results =
|
List<WorkbasketAccessItem> results =
|
||||||
workbasketService
|
workbasketService
|
||||||
.createWorkbasketAccessItemQuery()
|
.createWorkbasketAccessItemQuery()
|
||||||
.accessIdIn("user-1-1", GROUP_1_DN)
|
.accessIdIn("user-1-1", GROUP_1_DN, PERM_1)
|
||||||
.list();
|
.list();
|
||||||
assertThat(results).hasSize(8);
|
assertThat(results).hasSize(11);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WithAccessId(user = "unknownuser")
|
@WithAccessId(user = "unknownuser")
|
||||||
|
@ -78,12 +78,12 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
||||||
WorkbasketAccessItemQuery query =
|
WorkbasketAccessItemQuery query =
|
||||||
workbasketService
|
workbasketService
|
||||||
.createWorkbasketAccessItemQuery()
|
.createWorkbasketAccessItemQuery()
|
||||||
.accessIdIn("user-1-1", GROUP_1_DN)
|
.accessIdIn("user-1-1", GROUP_1_DN, PERM_1)
|
||||||
.orderByAccessId(SortDirection.DESCENDING)
|
.orderByAccessId(SortDirection.DESCENDING)
|
||||||
.orderByWorkbasketId(SortDirection.DESCENDING);
|
.orderByWorkbasketId(SortDirection.DESCENDING);
|
||||||
List<WorkbasketAccessItem> results = query.list();
|
List<WorkbasketAccessItem> results = query.list();
|
||||||
long count = query.count();
|
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");
|
assertThat(results.get(0).getId()).isEqualTo("WAI:100000000000000000000000000000000003");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,12 +94,13 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
||||||
List<WorkbasketAccessItem> results =
|
List<WorkbasketAccessItem> results =
|
||||||
workbasketService
|
workbasketService
|
||||||
.createWorkbasketAccessItemQuery()
|
.createWorkbasketAccessItemQuery()
|
||||||
.accessIdIn("user-1-1", GROUP_1_DN)
|
.accessIdIn("user-1-1", GROUP_1_DN, PERM_1)
|
||||||
.workbasketIdIn(
|
.workbasketIdIn(
|
||||||
"WBI:100000000000000000000000000000000006",
|
"WBI:100000000000000000000000000000000006",
|
||||||
"WBI:100000000000000000000000000000000002")
|
"WBI:100000000000000000000000000000000002",
|
||||||
|
"WBI:100000000000000000000000000000000005")
|
||||||
.list();
|
.list();
|
||||||
assertThat(results).hasSize(3);
|
assertThat(results).hasSize(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WithAccessId(user = "businessadmin")
|
@WithAccessId(user = "businessadmin")
|
||||||
|
@ -135,7 +136,7 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
||||||
.createWorkbasketAccessItemQuery()
|
.createWorkbasketAccessItemQuery()
|
||||||
.workbasketIdIn("WBI:100000000000000000000000000000000006")
|
.workbasketIdIn("WBI:100000000000000000000000000000000006")
|
||||||
.list();
|
.list();
|
||||||
assertThat(results).hasSize(3);
|
assertThat(results).hasSize(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WithAccessId(user = "businessadmin")
|
@WithAccessId(user = "businessadmin")
|
||||||
|
@ -149,7 +150,7 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
||||||
.orderByWorkbasketId(SortDirection.DESCENDING)
|
.orderByWorkbasketId(SortDirection.DESCENDING)
|
||||||
.orderByAccessId(SortDirection.ASCENDING)
|
.orderByAccessId(SortDirection.ASCENDING)
|
||||||
.list();
|
.list();
|
||||||
assertThat(results).hasSize(3);
|
assertThat(results).hasSize(4);
|
||||||
assertThat(results.get(0).getId()).isEqualTo("WAI:100000000000000000000000000000000009");
|
assertThat(results.get(0).getId()).isEqualTo("WAI:100000000000000000000000000000000009");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +161,7 @@ class QueryWorkbasketAccessItemsAccTest extends AbstractAccTest {
|
||||||
String[] expectedIds = {
|
String[] expectedIds = {
|
||||||
"WAI:100000000000000000000000000000000001",
|
"WAI:100000000000000000000000000000000001",
|
||||||
"WAI:100000000000000000000000000000000015",
|
"WAI:100000000000000000000000000000000015",
|
||||||
"WAI:100000000000000000000000000000000007"
|
"WAI:100000000000000000000000000000000006"
|
||||||
};
|
};
|
||||||
List<WorkbasketAccessItem> results =
|
List<WorkbasketAccessItem> results =
|
||||||
workbasketService.createWorkbasketAccessItemQuery().idIn(expectedIds).list();
|
workbasketService.createWorkbasketAccessItemQuery().idIn(expectedIds).list();
|
||||||
|
|
|
@ -70,20 +70,21 @@ class QueryWorkbasketByPermissionAccTest extends AbstractAccTest {
|
||||||
|
|
||||||
@WithAccessId(user = "businessadmin")
|
@WithAccessId(user = "businessadmin")
|
||||||
@Test
|
@Test
|
||||||
void should_GetAllTransferTargetsForUserAndGroup_When_QueryingForSinglePermission()
|
void should_GetAllTransferTargetsForUserGroupPermission_When_QueryingForSinglePermission()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
List<WorkbasketSummary> results =
|
List<WorkbasketSummary> results =
|
||||||
WORKBASKET_SERVICE
|
WORKBASKET_SERVICE
|
||||||
.createWorkbasketQuery()
|
.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();
|
.list();
|
||||||
|
|
||||||
assertThat(results).hasSize(6);
|
assertThat(results).hasSize(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WithAccessId(user = "businessadmin")
|
@WithAccessId(user = "businessadmin")
|
||||||
@Test
|
@Test
|
||||||
void should_GetAllTransferTargetsForUserAndGroup_When_QueryingForMultiplePermissions()
|
void should_GetAllTransferTargetsForUserGroupPermission_When_QueryingForMultiplePermissions()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
List<WorkbasketSummary> results =
|
List<WorkbasketSummary> results =
|
||||||
WORKBASKET_SERVICE
|
WORKBASKET_SERVICE
|
||||||
|
@ -91,21 +92,37 @@ class QueryWorkbasketByPermissionAccTest extends AbstractAccTest {
|
||||||
.accessIdsHavePermissions(
|
.accessIdsHavePermissions(
|
||||||
List.of(WorkbasketPermission.APPEND, WorkbasketPermission.OPEN),
|
List.of(WorkbasketPermission.APPEND, WorkbasketPermission.OPEN),
|
||||||
"user-1-1",
|
"user-1-1",
|
||||||
GROUP_1_DN)
|
GROUP_1_DN, PERM_1)
|
||||||
.list();
|
.list();
|
||||||
|
|
||||||
assertThat(results).hasSize(4);
|
assertThat(results).hasSize(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WithAccessId(user = "businessadmin")
|
@WithAccessId(user = "businessadmin")
|
||||||
@Test
|
@Test
|
||||||
void should_GetAllWorkbasketsForUserAndGroup_When_QueryingForReadTasksPermissions()
|
void should_GetAllWorkbasketsForUserGroupPermission_When_QueryingForReadTasksPermissions()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
List<WorkbasketSummary> results =
|
List<WorkbasketSummary> results =
|
||||||
WORKBASKET_SERVICE
|
WORKBASKET_SERVICE
|
||||||
.createWorkbasketQuery()
|
.createWorkbasketQuery()
|
||||||
.accessIdsHavePermissions(
|
.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();
|
.list();
|
||||||
|
|
||||||
assertThat(results).hasSize(7);
|
assertThat(results).hasSize(7);
|
||||||
|
@ -113,63 +130,52 @@ class QueryWorkbasketByPermissionAccTest extends AbstractAccTest {
|
||||||
|
|
||||||
@WithAccessId(user = "businessadmin")
|
@WithAccessId(user = "businessadmin")
|
||||||
@Test
|
@Test
|
||||||
void should_GetAllWorkbasketsForUserAndGroup_When_QueryingForEditTasksPermissions()
|
void should_GetAllTransferTargetsForUserGroupPermission_When_QueryingForSortedByNameAscending()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
List<WorkbasketSummary> results =
|
List<WorkbasketSummary> results =
|
||||||
WORKBASKET_SERVICE
|
WORKBASKET_SERVICE
|
||||||
.createWorkbasketQuery()
|
.createWorkbasketQuery()
|
||||||
.accessIdsHavePermissions(
|
.accessIdsHavePermissions(List.of(WorkbasketPermission.APPEND),
|
||||||
List.of(WorkbasketPermission.READTASKS), "user-1-1", GROUP_1_DN)
|
"user-1-1", GROUP_1_DN, PERM_1)
|
||||||
.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)
|
|
||||||
.orderByName(SortDirection.ASCENDING)
|
.orderByName(SortDirection.ASCENDING)
|
||||||
.list();
|
.list();
|
||||||
|
|
||||||
assertThat(results).hasSize(6);
|
assertThat(results).hasSize(7);
|
||||||
assertThat(results.get(0).getKey()).isEqualTo("GPK_KSC_1");
|
assertThat(results.get(0).getKey()).isEqualTo("GPK_KSC_1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@WithAccessId(user = "businessadmin")
|
@WithAccessId(user = "businessadmin")
|
||||||
@Test
|
@Test
|
||||||
void should_GetAllTransferTargetsForUserAndGroup_When_QueryingForSortedByNameDescending()
|
void should_GetAllTransferTargetsForUserGroupPermission_When_QueryingForSortedByNameDescending()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
List<WorkbasketSummary> results =
|
List<WorkbasketSummary> results =
|
||||||
WORKBASKET_SERVICE
|
WORKBASKET_SERVICE
|
||||||
.createWorkbasketQuery()
|
.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)
|
.orderByName(SortDirection.DESCENDING)
|
||||||
.orderByKey(SortDirection.ASCENDING)
|
.orderByKey(SortDirection.ASCENDING)
|
||||||
.list();
|
.list();
|
||||||
|
|
||||||
assertThat(results).hasSize(6);
|
assertThat(results).hasSize(7);
|
||||||
assertThat(results.get(0).getKey()).isEqualTo("USER-2-2");
|
assertThat(results.get(0).getKey()).isEqualTo("USER-2-2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@WithAccessId(user = "businessadmin")
|
@WithAccessId(user = "businessadmin")
|
||||||
@Test
|
@Test
|
||||||
void should_GetAllTransferSourcesForUserAndGroup_When_QueryingForSinglePermission()
|
void should_GetAllTransferSourcesForUserGroupPermission_When_QueryingForSinglePermission()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
List<WorkbasketSummary> results =
|
List<WorkbasketSummary> results =
|
||||||
WORKBASKET_SERVICE
|
WORKBASKET_SERVICE
|
||||||
.createWorkbasketQuery()
|
.createWorkbasketQuery()
|
||||||
.accessIdsHavePermissions(
|
.accessIdsHavePermissions(
|
||||||
List.of(WorkbasketPermission.DISTRIBUTE), "user-1-1", GROUP_1_DN)
|
List.of(WorkbasketPermission.DISTRIBUTE),
|
||||||
|
"user-1-1", GROUP_1_DN, PERM_1)
|
||||||
.list();
|
.list();
|
||||||
|
|
||||||
assertThat(results)
|
assertThat(results)
|
||||||
.extracting(WorkbasketSummary::getKey)
|
.extracting(WorkbasketSummary::getKey)
|
||||||
.containsExactlyInAnyOrder("GPK_KSC_1", "USER-1-1");
|
.containsExactlyInAnyOrder("GPK_KSC_1", "USER-1-1", "TEAMLEAD-2");
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
@ -224,28 +230,28 @@ class QueryWorkbasketByPermissionAccTest extends AbstractAccTest {
|
||||||
assertThat(results).hasSize(3);
|
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
|
@Test
|
||||||
void should_GetAllTransferTargetsForSubjectUserAndGroup_When_QueryingForSinglePermission() {
|
void should_GetAllTransferTargetsForSubjectUserGroupPerm_When_QueryingForSinglePermission() {
|
||||||
List<WorkbasketSummary> results =
|
List<WorkbasketSummary> results =
|
||||||
WORKBASKET_SERVICE
|
WORKBASKET_SERVICE
|
||||||
.createWorkbasketQuery()
|
.createWorkbasketQuery()
|
||||||
.callerHasPermissions(WorkbasketPermission.APPEND)
|
.callerHasPermissions(WorkbasketPermission.APPEND)
|
||||||
.list();
|
.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
|
@Test
|
||||||
void should_GetAllTransferTargetsForSubjectUserAndGroup_When_QueryingForMultiplePermissions() {
|
void should_GetAllTransferTargetsForSubjectUserGroupPerm_When_QueryingForMultiplePermissions() {
|
||||||
List<WorkbasketSummary> results =
|
List<WorkbasketSummary> results =
|
||||||
WORKBASKET_SERVICE
|
WORKBASKET_SERVICE
|
||||||
.createWorkbasketQuery()
|
.createWorkbasketQuery()
|
||||||
.callerHasPermissions(WorkbasketPermission.APPEND, WorkbasketPermission.OPEN)
|
.callerHasPermissions(WorkbasketPermission.APPEND, WorkbasketPermission.OPEN)
|
||||||
.list();
|
.list();
|
||||||
|
|
||||||
assertThat(results).hasSize(4);
|
assertThat(results).hasSize(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WithAccessId(user = "businessadmin")
|
@WithAccessId(user = "businessadmin")
|
||||||
|
|
|
@ -31,7 +31,8 @@ class WorkbasketQueryAccTest extends AbstractAccTest {
|
||||||
.createWorkbasketQuery()
|
.createWorkbasketQuery()
|
||||||
.nameLike("%")
|
.nameLike("%")
|
||||||
.accessIdsHavePermissions(
|
.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();
|
.list();
|
||||||
};
|
};
|
||||||
assertThatThrownBy(call).isInstanceOf(NotAuthorizedException.class);
|
assertThatThrownBy(call).isInstanceOf(NotAuthorizedException.class);
|
||||||
|
@ -50,7 +51,8 @@ class WorkbasketQueryAccTest extends AbstractAccTest {
|
||||||
.createWorkbasketQuery()
|
.createWorkbasketQuery()
|
||||||
.nameLike("%")
|
.nameLike("%")
|
||||||
.accessIdsHavePermissions(
|
.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();
|
.list();
|
||||||
};
|
};
|
||||||
assertThatThrownBy(call).isInstanceOf(NotAuthorizedException.class);
|
assertThatThrownBy(call).isInstanceOf(NotAuthorizedException.class);
|
||||||
|
@ -69,7 +71,8 @@ class WorkbasketQueryAccTest extends AbstractAccTest {
|
||||||
.createWorkbasketQuery()
|
.createWorkbasketQuery()
|
||||||
.nameLike("%")
|
.nameLike("%")
|
||||||
.accessIdsHavePermissions(
|
.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();
|
.list();
|
||||||
|
|
||||||
assertThat(results).hasSize(13);
|
assertThat(results).hasSize(13);
|
||||||
|
@ -88,7 +91,8 @@ class WorkbasketQueryAccTest extends AbstractAccTest {
|
||||||
.createWorkbasketQuery()
|
.createWorkbasketQuery()
|
||||||
.nameLike("%")
|
.nameLike("%")
|
||||||
.accessIdsHavePermissions(
|
.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();
|
.list();
|
||||||
|
|
||||||
assertThat(results).hasSize(13);
|
assertThat(results).hasSize(13);
|
||||||
|
|
|
@ -15,6 +15,8 @@ public @interface WithAccessId {
|
||||||
|
|
||||||
String[] groups() default {};
|
String[] groups() default {};
|
||||||
|
|
||||||
|
String[] permissions() default {};
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@interface WithAccessIds {
|
@interface WithAccessIds {
|
||||||
|
|
|
@ -38,6 +38,8 @@ public class BootWebSecurityConfigurer {
|
||||||
private final String ldapUserDnPatterns;
|
private final String ldapUserDnPatterns;
|
||||||
private final String ldapGroupSearchBase;
|
private final String ldapGroupSearchBase;
|
||||||
private final String ldapGroupSearchFilter;
|
private final String ldapGroupSearchFilter;
|
||||||
|
private final String ldapPermissionSearchBase;
|
||||||
|
private final String ldapPermissionSearchFilter;
|
||||||
|
|
||||||
private final boolean devMode;
|
private final boolean devMode;
|
||||||
private final boolean enableCsrf;
|
private final boolean enableCsrf;
|
||||||
|
@ -48,6 +50,9 @@ public class BootWebSecurityConfigurer {
|
||||||
@Value("${taskana.ldap.userDnPatterns:uid={0},cn=users}") String ldapUserDnPatterns,
|
@Value("${taskana.ldap.userDnPatterns:uid={0},cn=users}") String ldapUserDnPatterns,
|
||||||
@Value("${taskana.ldap.groupSearchBase:cn=groups}") String ldapGroupSearchBase,
|
@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=permissions}") String ldapPermissionSearchBase,
|
||||||
|
@Value("${taskana.ldap.permissionSearchFilter:uniqueMember={0}}")
|
||||||
|
String ldapPermissionSearchFilter,
|
||||||
@Value("${enableCsrf:false}") boolean enableCsrf,
|
@Value("${enableCsrf:false}") boolean enableCsrf,
|
||||||
@Value("${devMode:false}") boolean devMode) {
|
@Value("${devMode:false}") boolean devMode) {
|
||||||
this.enableCsrf = enableCsrf;
|
this.enableCsrf = enableCsrf;
|
||||||
|
@ -55,6 +60,8 @@ public class BootWebSecurityConfigurer {
|
||||||
this.ldapBaseDn = ldapBaseDn;
|
this.ldapBaseDn = ldapBaseDn;
|
||||||
this.ldapGroupSearchBase = ldapGroupSearchBase;
|
this.ldapGroupSearchBase = ldapGroupSearchBase;
|
||||||
this.ldapGroupSearchFilter = ldapGroupSearchFilter;
|
this.ldapGroupSearchFilter = ldapGroupSearchFilter;
|
||||||
|
this.ldapPermissionSearchBase = ldapPermissionSearchBase;
|
||||||
|
this.ldapPermissionSearchFilter = ldapPermissionSearchFilter;
|
||||||
this.ldapUserDnPatterns = ldapUserDnPatterns;
|
this.ldapUserDnPatterns = ldapUserDnPatterns;
|
||||||
this.devMode = devMode;
|
this.devMode = devMode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,12 @@ taskana.ldap.groupNameAttribute=cn
|
||||||
taskana.ldap.minSearchForLength=3
|
taskana.ldap.minSearchForLength=3
|
||||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||||
taskana.ldap.groupsOfUser=uniquemember
|
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
|
# Embedded Spring LDAP server
|
||||||
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
||||||
spring.ldap.embedded.credential.username=uid=admin
|
spring.ldap.embedded.credential.username=uid=admin
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
{
|
{
|
||||||
"EN": {
|
"EN": {
|
||||||
|
"global": {
|
||||||
|
"debounceTimeLookupField": 750
|
||||||
|
},
|
||||||
"workbaskets": {
|
"workbaskets": {
|
||||||
"information": {
|
"information": {
|
||||||
"owner": {
|
"owner": {
|
||||||
|
|
|
@ -11,6 +11,11 @@ cn: groups
|
||||||
objectclass: top
|
objectclass: top
|
||||||
objectclass: container
|
objectclass: container
|
||||||
|
|
||||||
|
dn: cn=permissions,OU=Test,O=TASKANA
|
||||||
|
cn: permissions
|
||||||
|
objectclass: top
|
||||||
|
objectclass: container
|
||||||
|
|
||||||
dn: cn=users,OU=Test,O=TASKANA
|
dn: cn=users,OU=Test,O=TASKANA
|
||||||
cn: users
|
cn: users
|
||||||
objectclass: top
|
objectclass: top
|
||||||
|
@ -109,8 +114,6 @@ sn: Toll
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||||
cn: Titus Toll
|
cn: Titus Toll
|
||||||
userPassword: teamlead-1
|
userPassword: teamlead-1
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
|
|
||||||
dn: uid=user-1-1,cn=users,OU=Test,O=TASKANA
|
dn: uid=user-1-1,cn=users,OU=Test,O=TASKANA
|
||||||
objectclass: inetorgperson
|
objectclass: inetorgperson
|
||||||
|
@ -126,8 +129,6 @@ sn: Mustermann
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||||
cn: Max Mustermann
|
cn: Max Mustermann
|
||||||
userPassword: user-1-1
|
userPassword: user-1-1
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
|
|
||||||
dn: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
dn: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
||||||
objectclass: inetorgperson
|
objectclass: inetorgperson
|
||||||
|
@ -137,15 +138,14 @@ objectclass: top
|
||||||
givenName: Elena
|
givenName: Elena
|
||||||
description: desc
|
description: desc
|
||||||
memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA
|
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
|
memberOf: cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||||
uid: user-1-2
|
uid: user-1-2
|
||||||
sn: Eifrig
|
sn: Eifrig
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||||
cn: Elena Eifrig
|
cn: Elena Eifrig
|
||||||
userPassword: user-1-2
|
userPassword: user-1-2
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
permission: program
|
|
||||||
|
|
||||||
dn: uid=user-1-3,cn=users,OU=Test,O=TASKANA
|
dn: uid=user-1-3,cn=users,OU=Test,O=TASKANA
|
||||||
objectclass: inetorgperson
|
objectclass: inetorgperson
|
||||||
|
@ -189,6 +189,7 @@ givenName: Simone
|
||||||
description: desc
|
description: desc
|
||||||
memberOf: cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
memberOf: cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||||
memberOf: cn=ksc-users,cn=groups,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
|
uid: user-2-1
|
||||||
sn: Müller
|
sn: Müller
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||||
|
@ -223,9 +224,6 @@ sn: Bach
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||||
cn: Thomas Bach
|
cn: Thomas Bach
|
||||||
userPassword: user-2-3
|
userPassword: user-2-3
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
permission: program
|
|
||||||
|
|
||||||
dn: uid=user-2-4,cn=users,OU=Test,O=TASKANA
|
dn: uid=user-2-4,cn=users,OU=Test,O=TASKANA
|
||||||
objectclass: inetorgperson
|
objectclass: inetorgperson
|
||||||
|
@ -282,9 +280,6 @@ sn: Meyer
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||||
cn: Wiebke Meyer
|
cn: Wiebke Meyer
|
||||||
userPassword: user-2-7
|
userPassword: user-2-7
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
permission: manage
|
|
||||||
|
|
||||||
dn: uid=user-2-8,cn=users,OU=Test,O=TASKANA
|
dn: uid=user-2-8,cn=users,OU=Test,O=TASKANA
|
||||||
objectclass: inetorgperson
|
objectclass: inetorgperson
|
||||||
|
@ -370,10 +365,6 @@ sn: Bio
|
||||||
ou: Organisationseinheit/Organisationseinheit B
|
ou: Organisationseinheit/Organisationseinheit B
|
||||||
cn: Brunhilde Bio
|
cn: Brunhilde Bio
|
||||||
userPassword: user-b-2
|
userPassword: user-b-2
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
permission: siegen
|
|
||||||
permission: frieden
|
|
||||||
|
|
||||||
########################
|
########################
|
||||||
# Users in other cn
|
# Users in other cn
|
||||||
|
@ -426,6 +417,25 @@ cn: monitor-users
|
||||||
objectclass: groupofuniquenames
|
objectclass: groupofuniquenames
|
||||||
objectclass: top
|
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
|
# 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");
|
+ "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
|
@Test
|
||||||
void should_ReturnFullDnForUser_When_AccessIdOfUserIsGiven() throws Exception {
|
void should_ReturnFullDnForUser_When_AccessIdOfUserIsGiven() throws Exception {
|
||||||
String dn = ldapClient.searchDnForAccessId("otheruser");
|
String dn = ldapClient.searchDnForAccessId("otheruser");
|
||||||
assertThat(dn).isEqualTo("uid=otheruser,cn=other-users,ou=test,o=taskana");
|
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;
|
@Autowired LdapClient ldapClient;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void should_FindAllUsersAndGroup_When_SearchWithSubstringOfName() throws Exception {
|
void should_FindAllUsersAndGroupAndPermissions_When_SearchWithSubstringOfName() throws Exception {
|
||||||
List<AccessIdRepresentationModel> usersAndGroups = ldapClient.searchUsersAndGroups("lead");
|
List<AccessIdRepresentationModel> usersGroupsPermissions =
|
||||||
assertThat(usersAndGroups)
|
ldapClient.searchUsersAndGroupsAndPermissions("lead");
|
||||||
|
assertThat(usersGroupsPermissions)
|
||||||
.extracting(AccessIdRepresentationModel::getAccessId)
|
.extracting(AccessIdRepresentationModel::getAccessId)
|
||||||
.containsExactlyInAnyOrder(
|
.containsExactlyInAnyOrder(
|
||||||
"teamlead-1", "teamlead-2", "cn=ksc-teamleads,cn=groups,ou=test,o=taskana");
|
"teamlead-1", "teamlead-2", "cn=ksc-teamleads,cn=groups,ou=test,o=taskana");
|
||||||
|
@ -30,11 +31,12 @@ class LdapTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void should_FindUser_When_SearchingWithFirstAndLastname() throws Exception {
|
void should_FindUser_When_SearchingWithFirstAndLastname() throws Exception {
|
||||||
List<AccessIdRepresentationModel> usersAndGroups = ldapClient.searchUsersAndGroups("Elena");
|
List<AccessIdRepresentationModel> usersGroupsPermissions =
|
||||||
assertThat(usersAndGroups).hasSize(2);
|
ldapClient.searchUsersAndGroupsAndPermissions("Elena");
|
||||||
|
assertThat(usersGroupsPermissions).hasSize(2);
|
||||||
|
|
||||||
usersAndGroups = ldapClient.searchUsersAndGroups("Elena Faul");
|
usersGroupsPermissions = ldapClient.searchUsersAndGroupsAndPermissions("Elena Faul");
|
||||||
assertThat(usersAndGroups).hasSize(1);
|
assertThat(usersGroupsPermissions).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -46,6 +48,20 @@ class LdapTest {
|
||||||
.containsExactlyInAnyOrder("cn=ksc-users,cn=groups,ou=test,o=taskana");
|
.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
|
@Test
|
||||||
void should_ReturnFullDnForUser_When_AccessIdOfUserIsGiven() throws Exception {
|
void should_ReturnFullDnForUser_When_AccessIdOfUserIsGiven() throws Exception {
|
||||||
String dn = ldapClient.searchDnForAccessId("user-2-2");
|
String dn = ldapClient.searchDnForAccessId("user-2-2");
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
taskana.ldap.userSearchBase=
|
taskana.ldap.userSearchBase=
|
||||||
taskana.ldap.groupSearchBase=
|
taskana.ldap.groupSearchBase=
|
||||||
|
taskana.ldap.permissionSearchBase=
|
||||||
|
|
|
@ -30,14 +30,21 @@ taskana.ldap.userOrglevel3Attribute=someDepartement
|
||||||
taskana.ldap.userOrglevel4Attribute=orgLevel4
|
taskana.ldap.userOrglevel4Attribute=orgLevel4
|
||||||
taskana.ldap.userIdAttribute=uid
|
taskana.ldap.userIdAttribute=uid
|
||||||
taskana.ldap.userMemberOfGroupAttribute=memberOf
|
taskana.ldap.userMemberOfGroupAttribute=memberOf
|
||||||
taskana.ldap.userPermissionsAttribute=permission
|
|
||||||
taskana.ldap.groupSearchBase=cn=groups
|
taskana.ldap.groupSearchBase=cn=groups
|
||||||
taskana.ldap.groupSearchFilterName=objectclass
|
taskana.ldap.groupSearchFilterName=objectclass
|
||||||
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
taskana.ldap.groupSearchFilterValue=groupOfUniqueNames
|
||||||
taskana.ldap.groupNameAttribute=cn
|
taskana.ldap.groupNameAttribute=cn
|
||||||
|
taskana.ldap.groupsOfUser=uniquemember
|
||||||
taskana.ldap.minSearchForLength=3
|
taskana.ldap.minSearchForLength=3
|
||||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
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
|
# Embedded Spring LDAP server
|
||||||
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
||||||
spring.ldap.embedded.credential.username=uid=admin
|
spring.ldap.embedded.credential.username=uid=admin
|
||||||
|
|
|
@ -24,6 +24,12 @@ taskana.ldap.groupNameAttribute=cn
|
||||||
taskana.ldap.minSearchForLength=3
|
taskana.ldap.minSearchForLength=3
|
||||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||||
taskana.ldap.groupsOfUser=uniquemember
|
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
|
####### JobScheduler cron expression that specifies when the JobSchedler runs
|
||||||
taskana.jobscheduler.async.cron=0 * * * * *
|
taskana.jobscheduler.async.cron=0 * * * * *
|
||||||
|
|
|
@ -105,7 +105,7 @@ public class TaskanaWildflyWithUserConfigTest extends AbstractAccTest {
|
||||||
TaskanaUserInfoRepresentationModel currentUser = response.getBody();
|
TaskanaUserInfoRepresentationModel currentUser = response.getBody();
|
||||||
assertThat(currentUser).isNotNull();
|
assertThat(currentUser).isNotNull();
|
||||||
assertThat(currentUser.getUserId()).isEqualTo("user-2-1");
|
assertThat(currentUser.getUserId()).isEqualTo("user-2-1");
|
||||||
assertThat(currentUser.getGroupIds()).hasSize(2);
|
assertThat(currentUser.getGroupIds()).hasSize(3);
|
||||||
assertThat(currentUser.getRoles()).hasSize(1);
|
assertThat(currentUser.getRoles()).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,13 @@ taskana.ldap.groupNameAttribute=cn
|
||||||
taskana.ldap.minSearchForLength=3
|
taskana.ldap.minSearchForLength=3
|
||||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||||
taskana.ldap.groupsOfUser=uniquemember
|
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
|
####### JobScheduler cron expression that specifies when the JobSchedler runs
|
||||||
taskana.jobscheduler.async.cron=0 * * * * *
|
taskana.jobscheduler.async.cron=0 * * * * *
|
||||||
####### cache static resources propertiesgit add --
|
####### cache static resources propertiesgit add --
|
||||||
|
|
|
@ -29,6 +29,12 @@ taskana.ldap.groupNameAttribute=cn
|
||||||
taskana.ldap.minSearchForLength=3
|
taskana.ldap.minSearchForLength=3
|
||||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||||
taskana.ldap.groupsOfUser=uniquemember
|
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
|
####### JobScheduler cron expression that specifies when the JobSchedler runs
|
||||||
taskana.jobscheduler.async.cron=0 * * * * *
|
taskana.jobscheduler.async.cron=0 * * * * *
|
||||||
####### cache static resources propertiesgit add --
|
####### cache static resources propertiesgit add --
|
||||||
|
|
|
@ -133,6 +133,8 @@ objectclass: top
|
||||||
givenName: Elena
|
givenName: Elena
|
||||||
description: desc
|
description: desc
|
||||||
memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA
|
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
|
memberOf: cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||||
uid: user-1-2
|
uid: user-1-2
|
||||||
sn: Eifrig
|
sn: Eifrig
|
||||||
|
@ -182,6 +184,7 @@ givenName: Simone
|
||||||
description: desc
|
description: desc
|
||||||
memberOf: cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
memberOf: cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||||
memberOf: cn=ksc-users,cn=groups,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
|
uid: user-2-1
|
||||||
sn: Müller
|
sn: Müller
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||||
|
@ -409,6 +412,25 @@ cn: monitor-users
|
||||||
objectclass: groupofuniquenames
|
objectclass: groupofuniquenames
|
||||||
objectclass: top
|
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
|
# Organizational Units
|
||||||
######################
|
######################
|
||||||
|
|
|
@ -48,7 +48,10 @@ public class TestWebSecurityConfig {
|
||||||
@Value("${taskana.ldap.baseDn:OU=Test,O=TASKANA}") String ldapBaseDn,
|
@Value("${taskana.ldap.baseDn:OU=Test,O=TASKANA}") String ldapBaseDn,
|
||||||
@Value("${taskana.ldap.userDnPatterns:uid={0},cn=users}") String ldapUserDnPatterns,
|
@Value("${taskana.ldap.userDnPatterns:uid={0},cn=users}") String ldapUserDnPatterns,
|
||||||
@Value("${taskana.ldap.groupSearchBase:cn=groups}") String ldapGroupSearchBase,
|
@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.ldapServerUrl = ldapServerUrl;
|
||||||
this.ldapBaseDn = ldapBaseDn;
|
this.ldapBaseDn = ldapBaseDn;
|
||||||
this.ldapUserDnPatterns = ldapUserDnPatterns;
|
this.ldapUserDnPatterns = ldapUserDnPatterns;
|
||||||
|
|
|
@ -11,6 +11,11 @@ cn: groups
|
||||||
objectclass: top
|
objectclass: top
|
||||||
objectclass: container
|
objectclass: container
|
||||||
|
|
||||||
|
dn: cn=permissions,OU=Test,O=TASKANA
|
||||||
|
cn: permissions
|
||||||
|
objectclass: top
|
||||||
|
objectclass: container
|
||||||
|
|
||||||
dn: cn=users,OU=Test,O=TASKANA
|
dn: cn=users,OU=Test,O=TASKANA
|
||||||
cn: users
|
cn: users
|
||||||
objectclass: top
|
objectclass: top
|
||||||
|
@ -109,8 +114,6 @@ sn: Toll
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||||
cn: Titus Toll
|
cn: Titus Toll
|
||||||
userPassword: teamlead-1
|
userPassword: teamlead-1
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
|
|
||||||
dn: uid=user-1-1,cn=users,OU=Test,O=TASKANA
|
dn: uid=user-1-1,cn=users,OU=Test,O=TASKANA
|
||||||
objectclass: inetorgperson
|
objectclass: inetorgperson
|
||||||
|
@ -126,8 +129,6 @@ sn: Mustermann
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||||
cn: Max Mustermann
|
cn: Max Mustermann
|
||||||
userPassword: user-1-1
|
userPassword: user-1-1
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
|
|
||||||
dn: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
dn: uid=user-1-2,cn=users,OU=Test,O=TASKANA
|
||||||
objectclass: inetorgperson
|
objectclass: inetorgperson
|
||||||
|
@ -137,15 +138,14 @@ objectclass: top
|
||||||
givenName: Elena
|
givenName: Elena
|
||||||
description: desc
|
description: desc
|
||||||
memberOf: cn=ksc-users,cn=groups,OU=Test,O=TASKANA
|
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
|
memberOf: cn=Organisationseinheit KSC 1,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||||
uid: user-1-2
|
uid: user-1-2
|
||||||
sn: Eifrig
|
sn: Eifrig
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 1
|
||||||
cn: Elena Eifrig
|
cn: Elena Eifrig
|
||||||
userPassword: user-1-2
|
userPassword: user-1-2
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
permission: program
|
|
||||||
|
|
||||||
dn: uid=user-1-3,cn=users,OU=Test,O=TASKANA
|
dn: uid=user-1-3,cn=users,OU=Test,O=TASKANA
|
||||||
objectclass: inetorgperson
|
objectclass: inetorgperson
|
||||||
|
@ -189,6 +189,7 @@ givenName: Simone
|
||||||
description: desc
|
description: desc
|
||||||
memberOf: cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
memberOf: cn=Organisationseinheit KSC 2,cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA
|
||||||
memberOf: cn=ksc-users,cn=groups,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
|
uid: user-2-1
|
||||||
sn: Müller
|
sn: Müller
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||||
|
@ -223,9 +224,6 @@ sn: Bach
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||||
cn: Thomas Bach
|
cn: Thomas Bach
|
||||||
userPassword: user-2-3
|
userPassword: user-2-3
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
permission: program
|
|
||||||
|
|
||||||
dn: uid=user-2-4,cn=users,OU=Test,O=TASKANA
|
dn: uid=user-2-4,cn=users,OU=Test,O=TASKANA
|
||||||
objectclass: inetorgperson
|
objectclass: inetorgperson
|
||||||
|
@ -282,9 +280,6 @@ sn: Meyer
|
||||||
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
ou: Organisationseinheit/Organisationseinheit KSC/Organisationseinheit KSC 2
|
||||||
cn: Wiebke Meyer
|
cn: Wiebke Meyer
|
||||||
userPassword: user-2-7
|
userPassword: user-2-7
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
permission: manage
|
|
||||||
|
|
||||||
dn: uid=user-2-8,cn=users,OU=Test,O=TASKANA
|
dn: uid=user-2-8,cn=users,OU=Test,O=TASKANA
|
||||||
objectclass: inetorgperson
|
objectclass: inetorgperson
|
||||||
|
@ -370,10 +365,6 @@ sn: Bio
|
||||||
ou: Organisationseinheit/Organisationseinheit B
|
ou: Organisationseinheit/Organisationseinheit B
|
||||||
cn: Brunhilde Bio
|
cn: Brunhilde Bio
|
||||||
userPassword: user-b-2
|
userPassword: user-b-2
|
||||||
permission: organize
|
|
||||||
permission: inet
|
|
||||||
permission: siegen
|
|
||||||
permission: frieden
|
|
||||||
|
|
||||||
########################
|
########################
|
||||||
# Users in other cn
|
# Users in other cn
|
||||||
|
@ -426,6 +417,25 @@ cn: monitor-users
|
||||||
objectclass: groupofuniquenames
|
objectclass: groupofuniquenames
|
||||||
objectclass: top
|
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
|
# Organizational Units
|
||||||
######################
|
######################
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.taskana.common.rest;
|
package pro.taskana.common.rest;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javax.naming.InvalidNameException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.hateoas.config.EnableHypermediaSupport;
|
import org.springframework.hateoas.config.EnableHypermediaSupport;
|
||||||
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
|
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
|
* @throws InvalidArgumentException if the provided search for Access Id is shorter than the
|
||||||
* configured one.
|
* configured one.
|
||||||
* @throws NotAuthorizedException if the current user is not ADMIN or BUSINESS_ADMIN.
|
* @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)
|
@GetMapping(path = RestEndpoints.URL_ACCESS_ID)
|
||||||
public ResponseEntity<List<AccessIdRepresentationModel>> searchUsersAndGroups(
|
public ResponseEntity<List<AccessIdRepresentationModel>> searchUsersAndGroupsAndPermissions(
|
||||||
@RequestParam("search-for") String searchFor)
|
@RequestParam("search-for") String searchFor)
|
||||||
throws InvalidArgumentException, NotAuthorizedException {
|
throws InvalidArgumentException, NotAuthorizedException, InvalidNameException {
|
||||||
taskanaEngine.checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.BUSINESS_ADMIN);
|
taskanaEngine.checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.BUSINESS_ADMIN);
|
||||||
|
|
||||||
List<AccessIdRepresentationModel> accessIdUsers = ldapClient.searchUsersAndGroups(searchFor);
|
List<AccessIdRepresentationModel> accessIdUsers =
|
||||||
|
ldapClient.searchUsersAndGroupsAndPermissions(searchFor);
|
||||||
return ResponseEntity.ok(accessIdUsers);
|
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
|
* @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 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 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
|
* @title Get groups for Access Id
|
||||||
*/
|
*/
|
||||||
@GetMapping(path = RestEndpoints.URL_ACCESS_ID_GROUPS)
|
@GetMapping(path = RestEndpoints.URL_ACCESS_ID_GROUPS)
|
||||||
public ResponseEntity<List<AccessIdRepresentationModel>> getGroupsByAccessId(
|
public ResponseEntity<List<AccessIdRepresentationModel>> getGroupsByAccessId(
|
||||||
@RequestParam("access-id") String accessId)
|
@RequestParam("access-id") String accessId)
|
||||||
throws InvalidArgumentException, NotAuthorizedException {
|
throws InvalidArgumentException, NotAuthorizedException, InvalidNameException {
|
||||||
taskanaEngine.checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.BUSINESS_ADMIN);
|
taskanaEngine.checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.BUSINESS_ADMIN);
|
||||||
|
|
||||||
List<AccessIdRepresentationModel> accessIds =
|
List<AccessIdRepresentationModel> accessIds =
|
||||||
|
@ -101,4 +105,26 @@ public class AccessIdController {
|
||||||
|
|
||||||
return ResponseEntity.ok(accessIds);
|
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 = 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_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_GROUPS = URL_ACCESS_ID + "/groups";
|
||||||
|
public static final String URL_ACCESS_ID_PERMISSIONS = URL_ACCESS_ID + "/permissions";
|
||||||
|
|
||||||
// import / export endpoints
|
// import / export endpoints
|
||||||
public static final String URL_CLASSIFICATION_DEFINITIONS = API_V1 + "classification-definitions";
|
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.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
import javax.naming.InvalidNameException;
|
||||||
import javax.naming.directory.SearchControls;
|
import javax.naming.directory.SearchControls;
|
||||||
|
import javax.naming.ldap.LdapName;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.core.support.AbstractContextMapper;
|
||||||
import org.springframework.ldap.filter.AndFilter;
|
import org.springframework.ldap.filter.AndFilter;
|
||||||
import org.springframework.ldap.filter.EqualsFilter;
|
import org.springframework.ldap.filter.EqualsFilter;
|
||||||
|
import org.springframework.ldap.filter.NotPresentFilter;
|
||||||
import org.springframework.ldap.filter.OrFilter;
|
import org.springframework.ldap.filter.OrFilter;
|
||||||
|
import org.springframework.ldap.filter.PresentFilter;
|
||||||
import org.springframework.ldap.filter.WhitespaceWildcardsFilter;
|
import org.springframework.ldap.filter.WhitespaceWildcardsFilter;
|
||||||
import org.springframework.ldap.support.LdapNameBuilder;
|
import org.springframework.ldap.support.LdapNameBuilder;
|
||||||
import org.springframework.stereotype.Component;
|
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
|
* @return a list of AccessIdResources sorted by AccessId and limited to
|
||||||
* maxNumberOfReturnedAccessIds
|
* maxNumberOfReturnedAccessIds
|
||||||
* @throws InvalidArgumentException if input is shorter than minSearchForLength
|
* @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)
|
public List<AccessIdRepresentationModel> searchUsersAndGroupsAndPermissions(final String name)
|
||||||
throws InvalidArgumentException {
|
throws InvalidArgumentException, InvalidNameException {
|
||||||
isInitOrFail();
|
isInitOrFail();
|
||||||
testMinSearchForLength(name);
|
testMinSearchForLength(name);
|
||||||
|
|
||||||
|
@ -83,6 +90,7 @@ public class LdapClient {
|
||||||
} else {
|
} else {
|
||||||
accessIds.addAll(searchUsersByNameOrAccessId(name));
|
accessIds.addAll(searchUsersByNameOrAccessId(name));
|
||||||
accessIds.addAll(searchGroupsByName(name));
|
accessIds.addAll(searchGroupsByName(name));
|
||||||
|
accessIds.addAll(searchPermissionsByName(name));
|
||||||
}
|
}
|
||||||
sortListOfAccessIdResources(accessIds);
|
sortListOfAccessIdResources(accessIds);
|
||||||
return getFirstPageOfaResultList(accessIds);
|
return getFirstPageOfaResultList(accessIds);
|
||||||
|
@ -214,19 +222,74 @@ public class LdapClient {
|
||||||
if (!CN.equals(getGroupNameAttribute())) {
|
if (!CN.equals(getGroupNameAttribute())) {
|
||||||
orFilter.or(new WhitespaceWildcardsFilter(CN, name));
|
orFilter.or(new WhitespaceWildcardsFilter(CN, name));
|
||||||
}
|
}
|
||||||
|
final AndFilter andFilter2 = new AndFilter();
|
||||||
|
andFilter2.and(new NotPresentFilter(getUserPermissionsAttribute()));
|
||||||
andFilter.and(orFilter);
|
andFilter.and(orFilter);
|
||||||
|
andFilter2.and(andFilter);
|
||||||
|
|
||||||
LOGGER.debug("Using filter '{}' for LDAP query.", andFilter);
|
LOGGER.debug("Using filter '{}' for LDAP query.", andFilter);
|
||||||
|
|
||||||
return ldapTemplate.search(
|
return ldapTemplate.search(
|
||||||
getGroupSearchBase(),
|
getGroupSearchBase(),
|
||||||
andFilter.encode(),
|
andFilter2.encode(),
|
||||||
SearchControls.SUBTREE_SCOPE,
|
SearchControls.SUBTREE_SCOPE,
|
||||||
getLookUpGroupAttributesToReturn(),
|
getLookUpGroupAttributesToReturn(),
|
||||||
new GroupContextMapper());
|
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();
|
isInitOrFail();
|
||||||
// Obviously Spring LdapTemplate does have a inconsistency and always adds the base name to the
|
// Obviously Spring LdapTemplate does have a inconsistency and always adds the base name to the
|
||||||
// given DN.
|
// given DN.
|
||||||
|
@ -239,11 +302,13 @@ public class LdapClient {
|
||||||
"Removed baseDN {} from given DN. New DN to be used: {}", getBaseDn(), nameWithoutBaseDn);
|
"Removed baseDN {} from given DN. New DN to be used: {}", getBaseDn(), nameWithoutBaseDn);
|
||||||
}
|
}
|
||||||
return ldapTemplate.lookup(
|
return ldapTemplate.lookup(
|
||||||
nameWithoutBaseDn, getLookUpUserAndGroupAttributesToReturn(), new DnContextMapper());
|
new LdapName(nameWithoutBaseDn),
|
||||||
|
getLookUpUserAndGroupAndPermissionAttributesToReturn(),
|
||||||
|
new DnContextMapper());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AccessIdRepresentationModel> searchGroupsAccessIdIsMemberOf(final String accessId)
|
public List<AccessIdRepresentationModel> searchGroupsAccessIdIsMemberOf(final String accessId)
|
||||||
throws InvalidArgumentException {
|
throws InvalidArgumentException, InvalidNameException {
|
||||||
isInitOrFail();
|
isInitOrFail();
|
||||||
testMinSearchForLength(accessId);
|
testMinSearchForLength(accessId);
|
||||||
|
|
||||||
|
@ -259,74 +324,186 @@ public class LdapClient {
|
||||||
orFilter.or(new EqualsFilter(getGroupsOfUserName(), accessId));
|
orFilter.or(new EqualsFilter(getGroupsOfUserName(), accessId));
|
||||||
}
|
}
|
||||||
orFilter.or(new EqualsFilter(getGroupsOfUserName(), dn));
|
orFilter.or(new EqualsFilter(getGroupsOfUserName(), dn));
|
||||||
|
final AndFilter andFilter2 = new AndFilter();
|
||||||
|
andFilter2.and(new NotPresentFilter(getUserPermissionsAttribute()));
|
||||||
andFilter.and(orFilter);
|
andFilter.and(orFilter);
|
||||||
|
andFilter2.and(andFilter);
|
||||||
|
|
||||||
String[] userAttributesToReturn = {getUserIdAttribute(), getGroupNameAttribute()};
|
String[] userAttributesToReturn = {getUserIdAttribute(), getGroupNameAttribute()};
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"Using filter '{}' for LDAP query with group search base {}.",
|
"Using filter '{}' for LDAP query with group search base {}.",
|
||||||
andFilter,
|
andFilter2,
|
||||||
getGroupSearchBase());
|
getGroupSearchBase());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ldapTemplate.search(
|
return ldapTemplate.search(
|
||||||
getGroupSearchBase(),
|
getGroupSearchBase(),
|
||||||
andFilter.encode(),
|
andFilter2.encode(),
|
||||||
SearchControls.SUBTREE_SCOPE,
|
SearchControls.SUBTREE_SCOPE,
|
||||||
userAttributesToReturn,
|
userAttributesToReturn,
|
||||||
new GroupContextMapper());
|
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.
|
* Performs a lookup to retrieve correct DN for the given access id.
|
||||||
*
|
*
|
||||||
* @param accessId The access id to lookup
|
* @param accessId The access id to lookup
|
||||||
* @return the LDAP Distinguished Name for the access id
|
* @return the LDAP Distinguished Name for the access id
|
||||||
* @throws InvalidArgumentException thrown if the given access id is ambiguous.
|
* @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();
|
isInitOrFail();
|
||||||
|
|
||||||
if (nameIsDn(accessId)) {
|
if (nameIsDn(accessId)) {
|
||||||
AccessIdRepresentationModel groupByDn = searchAccessIdByDn(accessId);
|
AccessIdRepresentationModel groupByDn = searchAccessIdByDn(accessId);
|
||||||
return groupByDn.getAccessId();
|
return groupByDn.getAccessId();
|
||||||
} else {
|
} else {
|
||||||
final AndFilter andFilter = new AndFilter();
|
return searchDnForAccessIdIfAccessIdNameIsNotDn(accessId);
|
||||||
andFilter.and(new EqualsFilter(getUserSearchFilterName(), getUserSearchFilterValue()));
|
}
|
||||||
final OrFilter orFilter = new OrFilter();
|
}
|
||||||
orFilter.or(new EqualsFilter(getUserIdAttribute(), accessId));
|
|
||||||
andFilter.and(orFilter);
|
|
||||||
|
|
||||||
LOGGER.debug(
|
private String searchDnForAccessIdIfAccessIdNameIsNotDn(String accessId) {
|
||||||
"Using filter '{}' for LDAP query with user search base {}.",
|
final List<String> distinguishedNames = searchDnForUserAccessId(accessId);
|
||||||
andFilter,
|
if (distinguishedNames == null || distinguishedNames.isEmpty()) {
|
||||||
getUserSearchBase());
|
final List<String> distinguishedNamesPermissions = searchDnForPermissionAccessId(accessId);
|
||||||
|
if (distinguishedNamesPermissions == null || distinguishedNamesPermissions.isEmpty()) {
|
||||||
final List<String> distinguishedNames =
|
final List<String> distinguishedNamesGroups = searchDnForGroupAccessId(accessId);
|
||||||
ldapTemplate.search(
|
if (distinguishedNamesGroups == null || distinguishedNamesGroups.isEmpty()) {
|
||||||
getUserSearchBase(),
|
return null;
|
||||||
andFilter.encode(),
|
} else if (distinguishedNamesGroups.size() > 1) {
|
||||||
SearchControls.SUBTREE_SCOPE,
|
throw new InvalidArgumentException("Ambiguous access id found: " + accessId);
|
||||||
null,
|
} else {
|
||||||
new DnStringContextMapper());
|
return distinguishedNamesGroups.get(0);
|
||||||
|
}
|
||||||
if (distinguishedNames == null || distinguishedNames.isEmpty()) {
|
} else if (distinguishedNamesPermissions.size() > 1) {
|
||||||
return null;
|
|
||||||
} else if (distinguishedNames.size() > 1) {
|
|
||||||
throw new InvalidArgumentException("Ambiguous access id found: " + accessId);
|
throw new InvalidArgumentException("Ambiguous access id found: " + accessId);
|
||||||
} else {
|
} 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.
|
* Validates a given AccessId / name.
|
||||||
*
|
*
|
||||||
* @param name lookup string for names or groups
|
* @param name lookup string for names or groups
|
||||||
* @return whether the given name is valid or not
|
* @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();
|
isInitOrFail();
|
||||||
|
|
||||||
if (nameIsDn(name)) {
|
if (nameIsDn(name)) {
|
||||||
|
@ -417,6 +594,22 @@ public class LdapClient {
|
||||||
return LdapSettings.TASKANA_LDAP_USER_PERMISSIONS_ATTRIBUTE.getValueFromEnv(env);
|
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() {
|
public String getGroupSearchBase() {
|
||||||
return LdapSettings.TASKANA_LDAP_GROUP_SEARCH_BASE.getValueFromEnv(env);
|
return LdapSettings.TASKANA_LDAP_GROUP_SEARCH_BASE.getValueFromEnv(env);
|
||||||
}
|
}
|
||||||
|
@ -458,6 +651,15 @@ public class LdapClient {
|
||||||
return Integer.parseInt(envValue);
|
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() {
|
public int getMaxNumberOfReturnedAccessIds() {
|
||||||
return maxNumberOfReturnedAccessIds;
|
return maxNumberOfReturnedAccessIds;
|
||||||
}
|
}
|
||||||
|
@ -474,6 +676,19 @@ public class LdapClient {
|
||||||
return LdapSettings.TASKANA_LDAP_GROUPS_OF_USER_TYPE.getValueFromEnv(env);
|
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) {
|
public boolean isUser(String accessId) {
|
||||||
return !getUsersByAccessId(accessId).isEmpty();
|
return !getUsersByAccessId(accessId).isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -522,10 +737,19 @@ public class LdapClient {
|
||||||
return new String[] {getGroupNameAttribute(), CN, getGroupSearchFilterName()};
|
return new String[] {getGroupNameAttribute(), CN, getGroupSearchFilterName()};
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] getLookUpUserAndGroupAttributesToReturn() {
|
String[] getLookUpPermissionAttributesToReturn() {
|
||||||
return Stream.concat(
|
return new String[] {
|
||||||
|
getUserPermissionsAttribute(),
|
||||||
|
getPermissionSearchFilterName()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] getLookUpUserAndGroupAndPermissionAttributesToReturn() {
|
||||||
|
return Stream.concat(Stream.concat(
|
||||||
Arrays.stream(getLookUpUserAttributesToReturn()),
|
Arrays.stream(getLookUpUserAttributesToReturn()),
|
||||||
Arrays.stream(getLookUpGroupAttributesToReturn()))
|
Arrays.stream(getLookUpGroupAttributesToReturn())),
|
||||||
|
Arrays.stream(getLookUpPermissionAttributesToReturn())
|
||||||
|
)
|
||||||
.toArray(String[]::new);
|
.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::equals))
|
||||||
.filter(not(LdapSettings.TASKANA_LDAP_GROUPS_OF_USER_NAME::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_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)
|
.filter(p -> p.getValueFromEnv(env) == null)
|
||||||
.toList();
|
.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) {
|
private Set<String> getGroupIdsFromContext(final DirContextOperations context) {
|
||||||
String[] groupAttributes = context.getStringAttributes(getUserMemberOfGroupAttribute());
|
String[] groupAttributes = context.getStringAttributes(getUserMemberOfGroupAttribute());
|
||||||
Set<String> groups = groupAttributes != null ? Set.of(groupAttributes) : Collections.emptySet();
|
Set<String> groups = groupAttributes != null ? Set.of(groupAttributes) : Collections.emptySet();
|
||||||
|
@ -635,6 +871,15 @@ public class LdapClient {
|
||||||
return groups;
|
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) {
|
private Set<String> getPermissionIdsFromContext(final DirContextOperations context) {
|
||||||
String[] permissionAttributes = context.getStringAttributes(getUserPermissionsAttribute());
|
String[] permissionAttributes = context.getStringAttributes(getUserPermissionsAttribute());
|
||||||
Set<String> permissions =
|
Set<String> permissions =
|
||||||
|
@ -655,12 +900,27 @@ public class LdapClient {
|
||||||
@Override
|
@Override
|
||||||
public AccessIdRepresentationModel doMapFromContext(final DirContextOperations context) {
|
public AccessIdRepresentationModel doMapFromContext(final DirContextOperations context) {
|
||||||
final AccessIdRepresentationModel accessId = new AccessIdRepresentationModel();
|
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()));
|
accessId.setName(context.getStringAttribute(getGroupNameAttribute()));
|
||||||
return accessId;
|
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. */
|
/** Context Mapper for user info entries. */
|
||||||
class UserInfoContextMapper extends AbstractContextMapper<User> {
|
class UserInfoContextMapper extends AbstractContextMapper<User> {
|
||||||
|
|
||||||
|
@ -712,9 +972,16 @@ public class LdapClient {
|
||||||
String firstName = context.getStringAttribute(getUserFirstnameAttribute());
|
String firstName = context.getStringAttribute(getUserFirstnameAttribute());
|
||||||
String lastName = context.getStringAttribute(getUserLastnameAttribute());
|
String lastName = context.getStringAttribute(getUserLastnameAttribute());
|
||||||
accessId.setName(String.format("%s, %s", lastName, firstName));
|
accessId.setName(String.format("%s, %s", lastName, firstName));
|
||||||
} else {
|
} else if (context.getStringAttribute(getUserPermissionsAttribute()) == null) {
|
||||||
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()));
|
accessId.setName(context.getStringAttribute(getGroupNameAttribute()));
|
||||||
|
} else {
|
||||||
|
accessId.setAccessId(getPermissionIdFromContext(context));
|
||||||
|
accessId.setName(context.getStringAttribute(getUserPermissionsAttribute()));
|
||||||
}
|
}
|
||||||
return accessId;
|
return accessId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,10 @@ enum LdapSettings {
|
||||||
TASKANA_LDAP_USER_ORG_LEVEL_4_ATTRIBUTE("taskana.ldap.userOrglevel4Attribute"),
|
TASKANA_LDAP_USER_ORG_LEVEL_4_ATTRIBUTE("taskana.ldap.userOrglevel4Attribute"),
|
||||||
TASKANA_LDAP_USER_MEMBER_OF_GROUP_ATTRIBUTE("taskana.ldap.userMemberOfGroupAttribute"),
|
TASKANA_LDAP_USER_MEMBER_OF_GROUP_ATTRIBUTE("taskana.ldap.userMemberOfGroupAttribute"),
|
||||||
TASKANA_LDAP_USER_PERMISSIONS_ATTRIBUTE("taskana.ldap.userPermissionsAttribute"),
|
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_GROUP_SEARCH_BASE("taskana.ldap.groupSearchBase"),
|
||||||
TASKANA_LDAP_BASE_DN("taskana.ldap.baseDn"),
|
TASKANA_LDAP_BASE_DN("taskana.ldap.baseDn"),
|
||||||
TASKANA_LDAP_GROUP_SEARCH_FILTER_NAME("taskana.ldap.groupSearchFilterName"),
|
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_MAX_NUMBER_OF_RETURNED_ACCESS_IDS("taskana.ldap.maxNumberOfReturnedAccessIds"),
|
||||||
TASKANA_LDAP_GROUPS_OF_USER("taskana.ldap.groupsOfUser"),
|
TASKANA_LDAP_GROUPS_OF_USER("taskana.ldap.groupsOfUser"),
|
||||||
TASKANA_LDAP_GROUPS_OF_USER_NAME("taskana.ldap.groupsOfUser.name"),
|
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;
|
private final String key;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class TaskanaUserInfoRepresentationModel
|
||||||
private String userId;
|
private String userId;
|
||||||
/** All groups the current user is a member of. */
|
/** All groups the current user is a member of. */
|
||||||
private List<String> groupIds = new ArrayList<>();
|
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<>();
|
private List<TaskanaRole> roles = new ArrayList<>();
|
||||||
|
|
||||||
public String getUserId() {
|
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("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("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("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 =
|
ThrowingConsumer<Pair<String, String>> test =
|
||||||
pair -> {
|
pair -> {
|
||||||
|
@ -146,6 +150,23 @@ class AccessIdControllerIntTest {
|
||||||
+ "cn=Organisationseinheit KSC,cn=organisation,OU=Test,O=TASKANA");
|
+ "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
|
@Test
|
||||||
void should_ValidateAccessIdWithEqualsFilterAndReturnAccessIdsOfGroupsTheAccessIdIsMemberOf() {
|
void should_ValidateAccessIdWithEqualsFilterAndReturnAccessIdsOfGroupsTheAccessIdIsMemberOf() {
|
||||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID_GROUPS) + "?access-id=user-2-1";
|
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");
|
+ "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
|
@Test
|
||||||
void should_ReturnBadRequest_ifAccessIdOfUserContainsInvalidCharacter() {
|
void should_ReturnBadRequest_ifAccessIdOfUserContainsInvalidCharacter() {
|
||||||
String url =
|
String url =
|
||||||
|
@ -212,6 +249,21 @@ class AccessIdControllerIntTest {
|
||||||
.isEqualTo(HttpStatus.FORBIDDEN);
|
.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
|
@Test
|
||||||
void should_ThrowNotAuthorizedException_ifCallerOfValidationIsNotAdminOrBusinessAdmin() {
|
void should_ThrowNotAuthorizedException_ifCallerOfValidationIsNotAdminOrBusinessAdmin() {
|
||||||
String url = restHelper.toUrl(RestEndpoints.URL_ACCESS_ID) + "?search-for=al";
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import pro.taskana.common.api.TaskanaRole;
|
import pro.taskana.common.api.TaskanaRole;
|
||||||
|
@ -85,6 +87,25 @@ class TaskanaEngineControllerIntTest {
|
||||||
assertThat(response.getBody()).containsExactly("EXTERNAL");
|
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
|
@Test
|
||||||
void testGetCurrentUserInfo() {
|
void testGetCurrentUserInfo() {
|
||||||
String url = restHelper.toUrl(RestEndpoints.URL_CURRENT_USER);
|
String url = restHelper.toUrl(RestEndpoints.URL_CURRENT_USER);
|
||||||
|
@ -105,6 +126,29 @@ class TaskanaEngineControllerIntTest {
|
||||||
.doesNotContain(TaskanaRole.ADMIN);
|
.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
|
@Test
|
||||||
void should_ReturnCustomAttributes() {
|
void should_ReturnCustomAttributes() {
|
||||||
String url = restHelper.toUrl(RestEndpoints.URL_CUSTOM_ATTRIBUTES);
|
String url = restHelper.toUrl(RestEndpoints.URL_CUSTOM_ATTRIBUTES);
|
||||||
|
|
|
@ -17,11 +17,14 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
import java.util.stream.Stream;
|
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.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
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.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
|
@ -45,37 +48,39 @@ class LdapClientTest {
|
||||||
|
|
||||||
@Spy @InjectMocks LdapClient cut;
|
@Spy @InjectMocks LdapClient cut;
|
||||||
|
|
||||||
@Test
|
@ParameterizedTest
|
||||||
void should_SearchGroupByDn_For_LdapCall() {
|
@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();
|
setUpEnvMock();
|
||||||
cut.init();
|
cut.init();
|
||||||
|
|
||||||
cut.searchAccessIdByDn("cn=developersgroup,ou=groups,o=taskanatest");
|
cut.searchAccessIdByDn(arg1);
|
||||||
|
|
||||||
verify(ldapTemplate)
|
verify(ldapTemplate)
|
||||||
.lookup(eq("cn=developersgroup,ou=groups"), any(), any(LdapClient.DnContextMapper.class));
|
.lookup(eq(new LdapName(arg2)), any(), any(LdapClient.DnContextMapper.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void should_ConvertAccessIdToLowercase_When_SearchingGroupByDn() {
|
void testLdap_searchUsersAndGroupsAndPermissions() throws Exception {
|
||||||
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 {
|
|
||||||
|
|
||||||
setUpEnvMock();
|
setUpEnvMock();
|
||||||
cut.init();
|
cut.init();
|
||||||
|
|
||||||
|
AccessIdRepresentationModel permission = new AccessIdRepresentationModel("testP", "testPId");
|
||||||
AccessIdRepresentationModel group = new AccessIdRepresentationModel("testG", "testGId");
|
AccessIdRepresentationModel group = new AccessIdRepresentationModel("testG", "testGId");
|
||||||
AccessIdRepresentationModel user = new AccessIdRepresentationModel("testU", "testUId");
|
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(
|
when(ldapTemplate.search(
|
||||||
any(String.class), any(), anyInt(), any(), any(LdapClient.GroupContextMapper.class)))
|
any(String.class), any(), anyInt(), any(), any(LdapClient.GroupContextMapper.class)))
|
||||||
.thenReturn(List.of(group));
|
.thenReturn(List.of(group));
|
||||||
|
@ -83,7 +88,9 @@ class LdapClientTest {
|
||||||
any(String.class), any(), anyInt(), any(), any(LdapClient.UserContextMapper.class)))
|
any(String.class), any(), anyInt(), any(), any(LdapClient.UserContextMapper.class)))
|
||||||
.thenReturn(List.of(user));
|
.thenReturn(List.of(user));
|
||||||
|
|
||||||
assertThat(cut.searchUsersAndGroups("test")).hasSize(2).containsExactlyInAnyOrder(user, group);
|
assertThat(cut.searchUsersAndGroupsAndPermissions("test"))
|
||||||
|
.hasSize(3)
|
||||||
|
.containsExactlyInAnyOrder(user, group, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -105,19 +112,21 @@ class LdapClientTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void should_ReturnAllUsersAndMembersOfGroupsWithTaskanaUserRole() throws Exception {
|
void should_ReturnAllUsersAndMembersOfGroupsAndMemberOfPermissionsWithTaskanaUserRole() {
|
||||||
|
|
||||||
setUpEnvMock();
|
setUpEnvMock();
|
||||||
cut.init();
|
cut.init();
|
||||||
|
|
||||||
AccessIdRepresentationModel user = new AccessIdRepresentationModel("testU", "testUId");
|
|
||||||
|
|
||||||
Set<String> groupsOfUserRole = new HashSet<>();
|
Set<String> groupsOfUserRole = new HashSet<>();
|
||||||
Map<TaskanaRole, Set<String>> roleMap = new HashMap<>();
|
Map<TaskanaRole, Set<String>> roleMap = new HashMap<>();
|
||||||
roleMap.put(TaskanaRole.USER, groupsOfUserRole);
|
roleMap.put(TaskanaRole.USER, groupsOfUserRole);
|
||||||
|
Set<String> permissionsOfUserRole = new HashSet<>();
|
||||||
|
roleMap.put(TaskanaRole.USER, permissionsOfUserRole);
|
||||||
|
|
||||||
when(taskanaConfiguration.getRoleMap()).thenReturn(roleMap);
|
when(taskanaConfiguration.getRoleMap()).thenReturn(roleMap);
|
||||||
|
|
||||||
|
AccessIdRepresentationModel user = new AccessIdRepresentationModel("testU", "testUId");
|
||||||
|
|
||||||
when(ldapTemplate.search(
|
when(ldapTemplate.search(
|
||||||
any(String.class), any(), anyInt(), any(), any(LdapClient.UserContextMapper.class)))
|
any(String.class), any(), anyInt(), any(), any(LdapClient.UserContextMapper.class)))
|
||||||
.thenReturn(List.of(user));
|
.thenReturn(List.of(user));
|
||||||
|
@ -126,7 +135,7 @@ class LdapClientTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testLdap_getNameWithoutBaseDn() {
|
void testLdap_getNameWithoutBaseDnForGroup() {
|
||||||
|
|
||||||
setUpEnvMock();
|
setUpEnvMock();
|
||||||
cut.init();
|
cut.init();
|
||||||
|
@ -135,11 +144,23 @@ class LdapClientTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldNot_CreateOrCriteriaWithDnAndAccessIdString_When_PropertyTypeIsSet()
|
void testLdap_getNameWithoutBaseDnForPermission() {
|
||||||
throws InvalidArgumentException {
|
|
||||||
|
|
||||||
setUpEnvMock();
|
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()
|
lenient()
|
||||||
.when(
|
.when(
|
||||||
ldapTemplate.search(
|
ldapTemplate.search(
|
||||||
|
@ -153,9 +174,10 @@ class LdapClientTest {
|
||||||
cut.init();
|
cut.init();
|
||||||
|
|
||||||
cut.searchGroupsAccessIdIsMemberOf("user-1-1");
|
cut.searchGroupsAccessIdIsMemberOf("user-1-1");
|
||||||
|
cut.searchPermissionsAccessIdHas("user-1-1");
|
||||||
|
|
||||||
String expectedFilterValue =
|
String expectedFilterValue = "(&(!(permission=*))"
|
||||||
"(&(objectclass=groupOfUniqueNames)(memberUid=uid=user-1-1,cn=users,OU=Test,O=TASKANA))";
|
+ "(&(objectclass=groupOfUniqueNames)(memberUid=uid=user-1-1,cn=users,OU=Test,O=TASKANA)))";
|
||||||
verify(ldapTemplate)
|
verify(ldapTemplate)
|
||||||
.search(
|
.search(
|
||||||
any(String.class),
|
any(String.class),
|
||||||
|
@ -163,6 +185,16 @@ class LdapClientTest {
|
||||||
anyInt(),
|
anyInt(),
|
||||||
any(),
|
any(),
|
||||||
any(LdapClient.GroupContextMapper.class));
|
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
|
@Test
|
||||||
|
@ -173,7 +205,7 @@ class LdapClientTest {
|
||||||
List<AccessIdRepresentationModel> result =
|
List<AccessIdRepresentationModel> result =
|
||||||
IntStream.range(0, 100)
|
IntStream.range(0, 100)
|
||||||
.mapToObj(i -> new AccessIdRepresentationModel("" + i, "" + i))
|
.mapToObj(i -> new AccessIdRepresentationModel("" + i, "" + i))
|
||||||
.collect(Collectors.toList());
|
.toList();
|
||||||
|
|
||||||
assertThat(cut.getFirstPageOfaResultList(result))
|
assertThat(cut.getFirstPageOfaResultList(result))
|
||||||
.hasSize(cut.getMaxNumberOfReturnedAccessIds());
|
.hasSize(cut.getMaxNumberOfReturnedAccessIds());
|
||||||
|
@ -193,7 +225,7 @@ class LdapClientTest {
|
||||||
// userMobilePhoneAttribute, userEmailAttribute, userOrglevel1Attribute, userOrglevel2Attribute,
|
// userMobilePhoneAttribute, userEmailAttribute, userOrglevel1Attribute, userOrglevel2Attribute,
|
||||||
// userOrglevel3Attribute, userOrglevel4Attribute, groupsOfUser, groupsOfUserName,
|
// userOrglevel3Attribute, userOrglevel4Attribute, groupsOfUser, groupsOfUserName,
|
||||||
// groupOfUserType
|
// groupOfUserType
|
||||||
assertThat(cut.checkForMissingConfigurations()).hasSize(LdapSettings.values().length - 12);
|
assertThat(cut.checkForMissingConfigurations()).hasSize(LdapSettings.values().length - 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -231,7 +263,14 @@ class LdapClientTest {
|
||||||
{"taskana.ldap.userOrglevel1Attribute", "orgLevel1"},
|
{"taskana.ldap.userOrglevel1Attribute", "orgLevel1"},
|
||||||
{"taskana.ldap.userOrglevel2Attribute", "orgLevel2"},
|
{"taskana.ldap.userOrglevel2Attribute", "orgLevel2"},
|
||||||
{"taskana.ldap.userOrglevel3Attribute", "orgLevel3"},
|
{"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(
|
.forEach(
|
||||||
strings ->
|
strings ->
|
||||||
|
|
|
@ -4,7 +4,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import static pro.taskana.rest.test.RestHelper.TEMPLATE;
|
import static pro.taskana.rest.test.RestHelper.TEMPLATE;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
@ -42,7 +41,7 @@ class WorkbasketControllerIntTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetWorkbasket() throws UnsupportedEncodingException {
|
void testGetWorkbasket() {
|
||||||
final String url =
|
final String url =
|
||||||
restHelper.toUrl(
|
restHelper.toUrl(
|
||||||
RestEndpoints.URL_WORKBASKET_ID, "WBI%3A100000000000000000000000000000000006");
|
RestEndpoints.URL_WORKBASKET_ID, "WBI%3A100000000000000000000000000000000006");
|
||||||
|
@ -278,7 +277,7 @@ class WorkbasketControllerIntTest {
|
||||||
assertThat(response.getBody()).isNotNull();
|
assertThat(response.getBody()).isNotNull();
|
||||||
assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull();
|
assertThat(response.getBody().getLink(IanaLinkRelations.SELF)).isNotNull();
|
||||||
assertThat(response.getHeaders().getContentType()).isEqualTo(MediaTypes.HAL_JSON);
|
assertThat(response.getHeaders().getContentType()).isEqualTo(MediaTypes.HAL_JSON);
|
||||||
assertThat(response.getBody().getContent()).hasSize(3);
|
assertThat(response.getBody().getContent()).hasSize(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -37,6 +37,13 @@ taskana.ldap.minSearchForLength=3
|
||||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||||
taskana.ldap.groupsOfUser=uniquemember
|
taskana.ldap.groupsOfUser=uniquemember
|
||||||
taskana.ldap.groupsOfUser.type=
|
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
|
# Embedded Spring LDAP server
|
||||||
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
spring.ldap.embedded.base-dn=OU=Test,O=TASKANA
|
||||||
spring.ldap.embedded.credential.username=uid=admin
|
spring.ldap.embedded.credential.username=uid=admin
|
||||||
|
|
|
@ -42,6 +42,12 @@ taskana.ldap.groupNameAttribute=cn
|
||||||
taskana.ldap.minSearchForLength=3
|
taskana.ldap.minSearchForLength=3
|
||||||
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
taskana.ldap.maxNumberOfReturnedAccessIds=50
|
||||||
taskana.ldap.groupsOfUser=uniquemember
|
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
|
# Embedded Spring LDAP server
|
||||||
spring.ldap.embedded.base-dn= OU=Test,O=TASKANA
|
spring.ldap.embedded.base-dn= OU=Test,O=TASKANA
|
||||||
spring.ldap.embedded.credential.username= uid=admin
|
spring.ldap.embedded.credential.username= uid=admin
|
||||||
|
|
|
@ -34,6 +34,29 @@
|
||||||
<ng-template #noGroups>The user is not associated to any groups </ng-template>
|
<ng-template #noGroups>The user is not associated to any groups </ng-template>
|
||||||
</mat-expansion-panel>
|
</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 -->
|
<!-- EXPANSION PANEL AUTHORIZATION -->
|
||||||
<mat-expansion-panel *ngIf="accessItemsForm" [expanded]="true" class="access-items__authorization-expansion-panel">
|
<mat-expansion-panel *ngIf="accessItemsForm" [expanded]="true" class="access-items__authorization-expansion-panel">
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
|
|
|
@ -45,6 +45,11 @@ tr:first-child > td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__permission-table-cell {
|
||||||
|
height: 48px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
&__table {
|
&__table {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
|
@ -67,6 +72,11 @@ tr:first-child > td {
|
||||||
left: 1%;
|
left: 1%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__permissions-expansion-panel {
|
||||||
|
width: 98%;
|
||||||
|
left: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
&__authorization-expansion-panel {
|
&__authorization-expansion-panel {
|
||||||
width: 98%;
|
width: 98%;
|
||||||
left: 1%;
|
left: 1%;
|
||||||
|
|
|
@ -146,6 +146,9 @@ describe('AccessItemsManagementComponent', () => {
|
||||||
|
|
||||||
const groups = store.selectSnapshot((state) => state.accessItemsManagement);
|
const groups = store.selectSnapshot((state) => state.accessItemsManagement);
|
||||||
expect(groups).toBeDefined();
|
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', () => {
|
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({});
|
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) => {
|
it('should dispatch GetAccessItems action in searchForAccessItemsWorkbaskets', async((done) => {
|
||||||
app.accessId = { accessId: '1', name: 'max' };
|
app.accessId = { accessId: '1', name: 'max' };
|
||||||
app.groups = [
|
app.groups = [
|
||||||
{ accessId: '1', name: 'users' },
|
{ accessId: '1', name: 'users' },
|
||||||
{ accessId: '2', name: 'users' }
|
{ accessId: '2', name: 'users' }
|
||||||
];
|
];
|
||||||
|
app.permissions = [
|
||||||
|
{ accessId: '1', name: 'perm' },
|
||||||
|
{ accessId: '2', name: 'perm' }
|
||||||
|
];
|
||||||
app.sortModel = {
|
app.sortModel = {
|
||||||
'sort-by': WorkbasketAccessItemQuerySortParameter.ACCESS_ID,
|
'sort-by': WorkbasketAccessItemQuerySortParameter.ACCESS_ID,
|
||||||
order: Direction.DESC
|
order: Direction.DESC
|
||||||
|
@ -175,6 +196,7 @@ describe('AccessItemsManagementComponent', () => {
|
||||||
actionDispatched = true;
|
actionDispatched = true;
|
||||||
expect(actionDispatched).toBe(true);
|
expect(actionDispatched).toBe(true);
|
||||||
expect(app.setAccessItemsGroups).toHaveBeenCalled();
|
expect(app.setAccessItemsGroups).toHaveBeenCalled();
|
||||||
|
expect(app.setAccessItemsPermissions).toHaveBeenCalled();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -194,6 +216,12 @@ describe('AccessItemsManagementComponent', () => {
|
||||||
expect(app.accessItemsForm).not.toBeNull();
|
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', () => {
|
it('should invoke sorting function correctly', () => {
|
||||||
const newSort: Sorting<WorkbasketAccessItemQuerySortParameter> = {
|
const newSort: Sorting<WorkbasketAccessItemQuerySortParameter> = {
|
||||||
'sort-by': WorkbasketAccessItemQuerySortParameter.ACCESS_ID,
|
'sort-by': WorkbasketAccessItemQuerySortParameter.ACCESS_ID,
|
||||||
|
@ -201,6 +229,7 @@ describe('AccessItemsManagementComponent', () => {
|
||||||
};
|
};
|
||||||
app.accessId = { accessId: '1', name: 'max' };
|
app.accessId = { accessId: '1', name: 'max' };
|
||||||
app.groups = [{ accessId: '1', name: 'users' }];
|
app.groups = [{ accessId: '1', name: 'users' }];
|
||||||
|
app.permissions = [{ accessId: '1', name: 'perm' }];
|
||||||
app.sorting(newSort);
|
app.sorting(newSort);
|
||||||
expect(app.sortModel).toMatchObject(newSort);
|
expect(app.sortModel).toMatchObject(newSort);
|
||||||
});
|
});
|
||||||
|
@ -209,4 +238,9 @@ describe('AccessItemsManagementComponent', () => {
|
||||||
app.accessItemsForm = null;
|
app.accessItemsForm = null;
|
||||||
expect(app.accessItemsGroups).toBeNull();
|
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 { customFieldCount } from '../../../shared/models/workbasket-access-items';
|
||||||
import {
|
import {
|
||||||
GetAccessItems,
|
GetAccessItems,
|
||||||
|
GetPermissionsByAccessId,
|
||||||
GetGroupsByAccessId,
|
GetGroupsByAccessId,
|
||||||
RemoveAccessItemsPermissions
|
RemoveAccessItemsPermissions
|
||||||
} from '../../../shared/store/access-items-management-store/access-items-management.actions';
|
} from '../../../shared/store/access-items-management-store/access-items-management.actions';
|
||||||
|
@ -38,6 +39,7 @@ export class AccessItemsManagementComponent implements OnInit {
|
||||||
accessItemsForm: FormGroup;
|
accessItemsForm: FormGroup;
|
||||||
accessId: AccessId;
|
accessId: AccessId;
|
||||||
groups: AccessId[];
|
groups: AccessId[];
|
||||||
|
permissions: AccessId[];
|
||||||
defaultSortBy: WorkbasketAccessItemQuerySortParameter = WorkbasketAccessItemQuerySortParameter.ACCESS_ID;
|
defaultSortBy: WorkbasketAccessItemQuerySortParameter = WorkbasketAccessItemQuerySortParameter.ACCESS_ID;
|
||||||
sortingFields: Map<WorkbasketAccessItemQuerySortParameter, string> = WORKBASKET_ACCESS_ITEM_SORT_PARAMETER_NAMING;
|
sortingFields: Map<WorkbasketAccessItemQuerySortParameter, string> = WORKBASKET_ACCESS_ITEM_SORT_PARAMETER_NAMING;
|
||||||
sortModel: Sorting<WorkbasketAccessItemQuerySortParameter> = {
|
sortModel: Sorting<WorkbasketAccessItemQuerySortParameter> = {
|
||||||
|
@ -46,11 +48,13 @@ export class AccessItemsManagementComponent implements OnInit {
|
||||||
};
|
};
|
||||||
accessItems: WorkbasketAccessItems[];
|
accessItems: WorkbasketAccessItems[];
|
||||||
isGroup: boolean = false;
|
isGroup: boolean = false;
|
||||||
|
isPermission: boolean = false;
|
||||||
|
|
||||||
@Select(EngineConfigurationSelectors.accessItemsCustomisation)
|
@Select(EngineConfigurationSelectors.accessItemsCustomisation)
|
||||||
accessItemsCustomization$: Observable<AccessItemsCustomisation>;
|
accessItemsCustomization$: Observable<AccessItemsCustomisation>;
|
||||||
@Select(AccessItemsManagementSelector.groups) groups$: Observable<AccessId[]>;
|
@Select(AccessItemsManagementSelector.groups) groups$: Observable<AccessId[]>;
|
||||||
customFields$: Observable<CustomField[]>;
|
customFields$: Observable<CustomField[]>;
|
||||||
|
@Select(AccessItemsManagementSelector.permissions) permissions$: Observable<AccessId[]>;
|
||||||
destroy$ = new Subject<void>();
|
destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -65,6 +69,9 @@ export class AccessItemsManagementComponent implements OnInit {
|
||||||
this.groups$.pipe(takeUntil(this.destroy$)).subscribe((groups) => {
|
this.groups$.pipe(takeUntil(this.destroy$)).subscribe((groups) => {
|
||||||
this.groups = groups;
|
this.groups = groups;
|
||||||
});
|
});
|
||||||
|
this.permissions$.pipe(takeUntil(this.destroy$)).subscribe((permissions) => {
|
||||||
|
this.permissions = permissions;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectAccessId(selected: AccessId) {
|
onSelectAccessId(selected: AccessId) {
|
||||||
|
@ -79,6 +86,12 @@ export class AccessItemsManagementComponent implements OnInit {
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.searchForAccessItemsWorkbaskets();
|
this.searchForAccessItemsWorkbaskets();
|
||||||
});
|
});
|
||||||
|
this.store
|
||||||
|
.dispatch(new GetPermissionsByAccessId(selected.accessId))
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe(() => {
|
||||||
|
this.searchForAccessItemsWorkbaskets();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.accessItemsForm = null;
|
this.accessItemsForm = null;
|
||||||
|
@ -88,19 +101,40 @@ export class AccessItemsManagementComponent implements OnInit {
|
||||||
|
|
||||||
searchForAccessItemsWorkbaskets() {
|
searchForAccessItemsWorkbaskets() {
|
||||||
this.removeFocus();
|
this.removeFocus();
|
||||||
const filterParameter: WorkbasketAccessItemQueryFilterParameter = {
|
if (this.permissions == null) {
|
||||||
'access-id': [this.accessId, ...this.groups].map((a) => a.accessId)
|
const filterParameter: WorkbasketAccessItemQueryFilterParameter = {
|
||||||
};
|
'access-id': [this.accessId, ...this.groups].map((a) => a.accessId)
|
||||||
this.store
|
};
|
||||||
.dispatch(new GetAccessItems(filterParameter, this.sortModel))
|
this.store
|
||||||
.pipe(takeUntil(this.destroy$))
|
.dispatch(new GetAccessItems(filterParameter, this.sortModel))
|
||||||
.subscribe((state) => {
|
.pipe(takeUntil(this.destroy$))
|
||||||
this.setAccessItemsGroups(
|
.subscribe((state) => {
|
||||||
state['accessItemsManagement'].accessItemsResource
|
this.setAccessItemsGroups(
|
||||||
? state['accessItemsManagement'].accessItemsResource.accessItems
|
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>) {
|
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() {
|
filterAccessItems() {
|
||||||
if (this.accessItemsForm.value.accessIdFilter) {
|
if (this.accessItemsForm.value.accessIdFilter) {
|
||||||
this.accessItems = this.accessItems.filter((value) =>
|
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;
|
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 {
|
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>) {
|
sorting(sort: Sorting<WorkbasketAccessItemQuerySortParameter>) {
|
||||||
|
|
|
@ -157,7 +157,13 @@ export class WorkbasketAccessItemsComponent implements OnInit, OnChanges, OnDest
|
||||||
this.selectedWorkbasket$.pipe(take(1)).subscribe((workbasket) => {
|
this.selectedWorkbasket$.pipe(take(1)).subscribe((workbasket) => {
|
||||||
this.accessItemsRepresentation._links = { self: { href: workbasket._links.accessItems.href } };
|
this.accessItemsRepresentation._links = { self: { href: workbasket._links.accessItems.href } };
|
||||||
this.setWorkbasketIdForCopy(workbasket.workbasketId);
|
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 { TypeAheadComponent } from './type-ahead.component';
|
||||||
import { AccessIdsService } from '../../services/access-ids/access-ids.service';
|
import { AccessIdsService } from '../../services/access-ids/access-ids.service';
|
||||||
import { of } from 'rxjs';
|
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 { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
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> = {
|
const accessIdService: Partial<AccessIdsService> = {
|
||||||
searchForAccessId: jest.fn().mockReturnValue(of([{ accessId: 'user-g-1', name: 'Gerda' }]))
|
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 fixture: ComponentFixture<TypeAheadComponent>;
|
||||||
let debugElement: DebugElement;
|
let debugElement: DebugElement;
|
||||||
let component: TypeAheadComponent;
|
let component: TypeAheadComponent;
|
||||||
|
let store: Store;
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(waitForAsync(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
NgxsModule.forRoot([]),
|
NgxsModule.forRoot([EngineConfigurationState]),
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatAutocompleteModule,
|
MatAutocompleteModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
NoopAnimationsModule,
|
NoopAnimationsModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule
|
ReactiveFormsModule,
|
||||||
|
HttpClientModule
|
||||||
],
|
],
|
||||||
declarations: [TypeAheadComponent],
|
declarations: [TypeAheadComponent],
|
||||||
providers: [{ provide: AccessIdsService, useValue: accessIdService }]
|
providers: [{ provide: AccessIdsService, useValue: accessIdService }, ClassificationCategoriesService]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
|
store = TestBed.inject(Store);
|
||||||
|
store.reset({
|
||||||
|
engineConfiguration: engineConfigurationMock
|
||||||
|
});
|
||||||
fixture = TestBed.createComponent(TypeAheadComponent);
|
fixture = TestBed.createComponent(TypeAheadComponent);
|
||||||
debugElement = fixture.debugElement;
|
debugElement = fixture.debugElement;
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
@ -53,7 +63,7 @@ describe('TypeAheadComponent with AccessId input', () => {
|
||||||
input.dispatchEvent(new Event('input'));
|
input.dispatchEvent(new Event('input'));
|
||||||
component.accessIdForm.get('accessId').updateValueAndValidity({ emitEvent: true });
|
component.accessIdForm.get('accessId').updateValueAndValidity({ emitEvent: true });
|
||||||
|
|
||||||
tick();
|
tick(50);
|
||||||
expect(component.name).toBe('Gerda');
|
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').setValue('invalid-user');
|
||||||
component.accessIdForm.get('accessId').updateValueAndValidity({ emitEvent: true });
|
component.accessIdForm.get('accessId').updateValueAndValidity({ emitEvent: true });
|
||||||
|
|
||||||
tick();
|
tick(50);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(emitSpy).toHaveBeenCalledWith(false);
|
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').setValue('user-g-1');
|
||||||
component.accessIdForm.get('accessId').updateValueAndValidity({ emitEvent: true });
|
component.accessIdForm.get('accessId').updateValueAndValidity({ emitEvent: true });
|
||||||
|
|
||||||
tick();
|
tick(50);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(emitSpy).toHaveBeenCalledWith(true);
|
expect(emitSpy).toHaveBeenCalledWith(true);
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core';
|
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core';
|
||||||
import { AccessIdsService } from '../../services/access-ids/access-ids.service';
|
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 { FormControl, FormGroup } from '@angular/forms';
|
||||||
import { AccessId } from '../../models/access-id';
|
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 { Select } from '@ngxs/store';
|
||||||
import { WorkbasketSelectors } from '../../store/workbasket-store/workbasket.selectors';
|
import { WorkbasketSelectors } from '../../store/workbasket-store/workbasket.selectors';
|
||||||
import { ButtonAction } from '../../../administration/models/button-action';
|
import { ButtonAction } from '../../../administration/models/button-action';
|
||||||
|
import { EngineConfigurationSelectors } from '../../store/engine-configuration-store/engine-configuration.selectors';
|
||||||
|
import { GlobalCustomisation } from '../../models/customisation';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'taskana-shared-type-ahead',
|
selector: 'taskana-shared-type-ahead',
|
||||||
|
@ -24,12 +26,16 @@ export class TypeAheadComponent implements OnInit, OnDestroy {
|
||||||
@Output() accessIdEventEmitter = new EventEmitter<AccessId>();
|
@Output() accessIdEventEmitter = new EventEmitter<AccessId>();
|
||||||
@Output() isFormValid = new EventEmitter<boolean>();
|
@Output() isFormValid = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
@Select(EngineConfigurationSelectors.globalCustomisation)
|
||||||
|
globalCustomisation$: Observable<GlobalCustomisation>;
|
||||||
|
|
||||||
@Select(WorkbasketSelectors.buttonAction)
|
@Select(WorkbasketSelectors.buttonAction)
|
||||||
buttonAction$: Observable<ButtonAction>;
|
buttonAction$: Observable<ButtonAction>;
|
||||||
|
|
||||||
name: string = '';
|
name: string = '';
|
||||||
lastSavedAccessId: string = '';
|
lastSavedAccessId: string = '';
|
||||||
filteredAccessIds: AccessId[] = [];
|
filteredAccessIds: AccessId[] = [];
|
||||||
|
debounceTime: number = 750;
|
||||||
destroy$ = new Subject<void>();
|
destroy$ = new Subject<void>();
|
||||||
accessIdForm = new FormGroup({
|
accessIdForm = new FormGroup({
|
||||||
accessId: new FormControl('')
|
accessId: new FormControl('')
|
||||||
|
@ -57,14 +63,27 @@ export class TypeAheadComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.accessIdForm.controls['accessId'].valueChanges.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
this.globalCustomisation$
|
||||||
const value = this.accessIdForm.controls['accessId'].value;
|
.pipe(
|
||||||
if (value === '') {
|
take(1),
|
||||||
this.handleEmptyAccessId();
|
map((customisation) => customisation?.debounceTimeLookupField)
|
||||||
return;
|
)
|
||||||
}
|
.subscribe((debounceTime) => {
|
||||||
this.searchForAccessId(value);
|
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();
|
this.setAccessIdFromInput();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ export interface Customisation {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CustomisationContent {
|
export interface CustomisationContent {
|
||||||
|
global?: GlobalCustomisation;
|
||||||
workbaskets?: WorkbasketsCustomisation;
|
workbaskets?: WorkbasketsCustomisation;
|
||||||
classifications?: ClassificationsCustomisation;
|
classifications?: ClassificationsCustomisation;
|
||||||
tasks?: TasksCustomisation;
|
tasks?: TasksCustomisation;
|
||||||
|
@ -31,6 +32,10 @@ export interface WorkbasketsCustomisation {
|
||||||
'access-items'?: AccessItemsCustomisation;
|
'access-items'?: AccessItemsCustomisation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GlobalCustomisation {
|
||||||
|
debounceTimeLookupField: number;
|
||||||
|
}
|
||||||
|
|
||||||
export type AccessItemsCustomisation = { accessId?: LookupField } & CustomFields;
|
export type AccessItemsCustomisation = { accessId?: LookupField } & CustomFields;
|
||||||
|
|
||||||
export interface CustomFields {
|
export interface CustomFields {
|
||||||
|
|
|
@ -34,6 +34,13 @@ export class AccessIdsService {
|
||||||
return this.httpClient.get<AccessId[]>(`${this.url}/groups?access-id=${accessId}`);
|
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(
|
getAccessItems(
|
||||||
filterParameter?: WorkbasketAccessItemQueryFilterParameter,
|
filterParameter?: WorkbasketAccessItemQueryFilterParameter,
|
||||||
sortParameter?: Sorting<WorkbasketAccessItemQuerySortParameter>,
|
sortParameter?: Sorting<WorkbasketAccessItemQuerySortParameter>,
|
||||||
|
|
|
@ -90,7 +90,8 @@ export class FormsValidatorService {
|
||||||
}
|
}
|
||||||
|
|
||||||
form.controls.forEach((control) => {
|
form.controls.forEach((control) => {
|
||||||
const { permEditTasks, permReadTasks, permRead } = control.value;
|
const { permEditTasks, permReadTasks, permRead, permOpen, permDistribute, permAppend, permTransfer } =
|
||||||
|
control.value;
|
||||||
|
|
||||||
if (permEditTasks && (!permReadTasks || !permRead)) {
|
if (permEditTasks && (!permReadTasks || !permRead)) {
|
||||||
this.notificationsService.showWarning('PERM_EDIT_TASKS_MISSING_DEPENDING_PERMISSION');
|
this.notificationsService.showWarning('PERM_EDIT_TASKS_MISSING_DEPENDING_PERMISSION');
|
||||||
|
@ -99,6 +100,14 @@ export class FormsValidatorService {
|
||||||
if (permReadTasks && !permRead) {
|
if (permReadTasks && !permRead) {
|
||||||
this.notificationsService.showWarning('PERM_READ_TASKS_MISSING_DEPENDING_PERMISSIONS');
|
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;
|
return result;
|
||||||
|
|
|
@ -109,6 +109,12 @@ export const messageByErrorCode = {
|
||||||
PERM_READ_TASKS_MISSING_DEPENDING_PERMISSIONS:
|
PERM_READ_TASKS_MISSING_DEPENDING_PERMISSIONS:
|
||||||
'"Read tasks" permission was selected without the required "Read" permission. ' +
|
'"Read tasks" permission was selected without the required "Read" permission. ' +
|
||||||
'Your changes will still be saved but they might lead to unexpected behavior.',
|
'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:
|
REPORT_DATA_WRONG_HEADER:
|
||||||
'The received header of the Report data does not match the expected header. ' +
|
'The received header of the Report data does not match the expected header. ' +
|
||||||
'The data might be displayed incorrectly. Please contact your administrator.',
|
'The data might be displayed incorrectly. Please contact your administrator.',
|
||||||
|
|
|
@ -13,6 +13,11 @@ export class GetGroupsByAccessId {
|
||||||
constructor(public accessId: string) {}
|
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 {
|
export class GetAccessItems {
|
||||||
static readonly type = '[Access Items Management] Get access items';
|
static readonly type = '[Access Items Management] Get access items';
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -7,4 +7,9 @@ export class AccessItemsManagementSelector {
|
||||||
static groups(state: AccessItemsManagementStateModel): AccessId[] {
|
static groups(state: AccessItemsManagementStateModel): AccessId[] {
|
||||||
return state.groups;
|
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 { Action, NgxsAfterBootstrap, State, StateContext } from '@ngxs/store';
|
||||||
import {
|
import {
|
||||||
GetAccessItems,
|
GetAccessItems,
|
||||||
|
GetPermissionsByAccessId,
|
||||||
GetGroupsByAccessId,
|
GetGroupsByAccessId,
|
||||||
RemoveAccessItemsPermissions,
|
RemoveAccessItemsPermissions,
|
||||||
SelectAccessId
|
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)
|
@Action(GetAccessItems)
|
||||||
getAccessItems(ctx: StateContext<AccessItemsManagementStateModel>, action: GetAccessItems): Observable<any> {
|
getAccessItems(ctx: StateContext<AccessItemsManagementStateModel>, action: GetAccessItems): Observable<any> {
|
||||||
this.requestInProgressService.setRequestInProgress(true);
|
this.requestInProgressService.setRequestInProgress(true);
|
||||||
|
@ -108,4 +129,5 @@ export interface AccessItemsManagementStateModel {
|
||||||
accessItemsResource: WorkbasketAccessItemsRepresentation;
|
accessItemsResource: WorkbasketAccessItemsRepresentation;
|
||||||
selectedAccessId: AccessId;
|
selectedAccessId: AccessId;
|
||||||
groups: AccessId[];
|
groups: AccessId[];
|
||||||
|
permissions: AccessId[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,18 @@ import {
|
||||||
ClassificationsCustomisation,
|
ClassificationsCustomisation,
|
||||||
AccessItemsCustomisation,
|
AccessItemsCustomisation,
|
||||||
TasksCustomisation,
|
TasksCustomisation,
|
||||||
ClassificationCategoryImages
|
ClassificationCategoryImages,
|
||||||
|
GlobalCustomisation
|
||||||
} from 'app/shared/models/customisation';
|
} from 'app/shared/models/customisation';
|
||||||
import { Selector } from '@ngxs/store';
|
import { Selector } from '@ngxs/store';
|
||||||
import { EngineConfigurationStateModel, EngineConfigurationState } from './engine-configuration.state';
|
import { EngineConfigurationStateModel, EngineConfigurationState } from './engine-configuration.state';
|
||||||
|
|
||||||
export class EngineConfigurationSelectors {
|
export class EngineConfigurationSelectors {
|
||||||
|
@Selector([EngineConfigurationState])
|
||||||
|
static globalCustomisation(state: EngineConfigurationStateModel): GlobalCustomisation {
|
||||||
|
return state.customisation[state.language].global;
|
||||||
|
}
|
||||||
|
|
||||||
@Selector([EngineConfigurationState])
|
@Selector([EngineConfigurationState])
|
||||||
static workbasketsCustomisation(state: EngineConfigurationStateModel): WorkbasketsCustomisation {
|
static workbasketsCustomisation(state: EngineConfigurationStateModel): WorkbasketsCustomisation {
|
||||||
return state.customisation[state.language].workbaskets;
|
return state.customisation[state.language].workbaskets;
|
||||||
|
|
|
@ -17,6 +17,9 @@ export const classificationStateMock = {
|
||||||
export const engineConfigurationMock = {
|
export const engineConfigurationMock = {
|
||||||
customisation: {
|
customisation: {
|
||||||
EN: {
|
EN: {
|
||||||
|
global: {
|
||||||
|
debounceTimeLookupField: 50
|
||||||
|
},
|
||||||
workbaskets: {
|
workbaskets: {
|
||||||
information: {
|
information: {
|
||||||
owner: {
|
owner: {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
{
|
{
|
||||||
"EN": {
|
"EN": {
|
||||||
|
"global": {
|
||||||
|
"debounceTimeLookupField": 750
|
||||||
|
},
|
||||||
"workbaskets": {
|
"workbaskets": {
|
||||||
"information": {
|
"information": {
|
||||||
"owner": {
|
"owner": {
|
||||||
|
|
Loading…
Reference in New Issue