From 4c81ec307f4cf66277929d3b9af9197d3e75b425 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 12 Aug 2015 21:38:29 +0200 Subject: [PATCH] Fixed support for searching for disabled and locked-out objects. --- build-system/pom.xml | 1 + .../security/MidPointApplication.properties | 3 + .../midpoint/prism/query/EqualFilter.java | 6 +- .../midpoint/prism/query/ValueFilter.java | 8 +- .../midpoint/schema/util/ActivationUtil.java | 17 + model/model-intest/testng.xml | 3 + .../ucf/impl/ConnectorInstanceIcfImpl.java | 4 + .../ucf/query/ValueOperation.java | 46 +- .../provisioning/test/impl/TestDummy.java | 278 ++++++--- .../test/impl/TestDummyNoActivation.java | 41 +- .../test/AbstractIntegrationTest.java | 25 + .../testing/conntest/Abstract389DsTest.java | 2 +- .../testing/conntest/AbstractEDirTest.java | 341 +++++++++++ .../conntest/AbstractLdapConnTest.java | 392 +----------- .../testing/conntest/AbstractLdapTest.java | 566 ++++++++++++++++++ .../testing/conntest/TestEDirAthena.java | 53 ++ .../test/resources/edir/resource-athena.xml | 251 ++++++++ .../src/test/resources/truststore.jks | Bin 0 -> 1390 bytes testing/conntest/testng.xml | 5 +- .../testng/AlphabeticalMethodInterceptor.java | 4 +- 20 files changed, 1553 insertions(+), 493 deletions(-) create mode 100644 testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractEDirTest.java create mode 100644 testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapTest.java create mode 100644 testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestEDirAthena.java create mode 100644 testing/conntest/src/test/resources/edir/resource-athena.xml create mode 100644 testing/conntest/src/test/resources/truststore.jks diff --git a/build-system/pom.xml b/build-system/pom.xml index 180992040a3..520748dd182 100644 --- a/build-system/pom.xml +++ b/build-system/pom.xml @@ -828,6 +828,7 @@ + src/test/resources/truststore.jks target/midpoint-home ${project.build.directory}/test-classes/logging.properties diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.properties index 5aff7694f6c..8122a846bb6 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.properties @@ -270,6 +270,9 @@ ActivationType.effectiveStatus=Effective status ActivationType.validFrom=Valid from ActivationType.validTo=Valid to +LockoutStatusType.NORMAL=Normal +LockoutStatusType.LOCKED=Locked + operation.com.evolveum.midpoint.common.operation.import.object=Import object operation.com.evolveum.midpoint.common.validator.Validator.objectBasicsCheck=Basic checks operation.com.evolveum.midpoint.common.validator.Validator.resourceNamespaceCheck=Resource namespace check diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/EqualFilter.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/EqualFilter.java index 1d24b5ae28b..2ab201488f8 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/EqualFilter.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/EqualFilter.java @@ -124,10 +124,10 @@ public static EqualFilter createEqual(ItemPath p return createEqual(parentPath, propertyDef, values); } - public static EqualFilter createEqual(ItemPath parentPath, PrismContainerDefinition containerDef, + public static EqualFilter createEqual(ItemPath itemPath, PrismContainerDefinition containerDef, T realValues) throws SchemaException { - PrismPropertyDefinition propertyDef = (PrismPropertyDefinition) findItemDefinition(parentPath, containerDef); - return createEqual(parentPath, propertyDef, realValues); + PrismPropertyDefinition propertyDef = (PrismPropertyDefinition) findItemDefinition(itemPath, containerDef); + return createEqual(itemPath, propertyDef, realValues); } public static EqualFilter createEqual(QName propertyName, Class type, PrismContext prismContext, T realValues) diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ValueFilter.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ValueFilter.java index 7a4c1444585..1b40b231031 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ValueFilter.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ValueFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Evolveum + * Copyright (c) 2010-2015 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -119,10 +119,10 @@ public MatchingRule getMatchingRuleFromRegistry(MatchingRuleRegistry matchingRul } - static ItemDefinition findItemDefinition(ItemPath parentPath, PrismContainerDefinition containerDef) { - ItemDefinition itemDef = containerDef.findItemDefinition(parentPath); + static ItemDefinition findItemDefinition(ItemPath itemPath, PrismContainerDefinition containerDef) { + ItemDefinition itemDef = containerDef.findItemDefinition(itemPath); if (itemDef == null) { - throw new IllegalStateException("No definition for item " + parentPath + " in container definition " + throw new IllegalStateException("No definition for item " + itemPath + " in container definition " + containerDef); } diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ActivationUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ActivationUtil.java index 5429ecbfcee..defd625a76d 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ActivationUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ActivationUtil.java @@ -17,6 +17,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.LockoutStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; /** @@ -57,5 +58,21 @@ public static boolean hasValidTo(ShadowType objectType) { ActivationType activation = objectType.getActivation(); return activation != null && activation.getValidTo() != null; } + + public static boolean hasLockoutStatus(ShadowType objectType) { + ActivationType activation = objectType.getActivation(); + return activation != null && activation.getLockoutStatus() != null; + } + + public static boolean isLockedOut(ShadowType objectType) { + return isLockedOut(objectType.getActivation()); + } + public static boolean isLockedOut(ActivationType activation) { + if (activation == null) { + return false; + } + return activation.getLockoutStatus() == LockoutStatusType.LOCKED; + } + } diff --git a/model/model-intest/testng.xml b/model/model-intest/testng.xml index 5a55fa45a5b..e20a980ae8a 100644 --- a/model/model-intest/testng.xml +++ b/model/model-intest/testng.xml @@ -16,6 +16,9 @@ --> + + + diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java index aa53815aaad..8525a4d5a27 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java @@ -1308,6 +1308,10 @@ public Collection> addObject(PrismObject Filter interpret(ObjectFilter objectFilter, IcfNameMapper icfNameMapp OperationResult parentResult = new OperationResult("interpret"); ValueFilter valueFilter= (ValueFilter) objectFilter; - if (valueFilter.getParentPath() != null && !valueFilter.getParentPath().isEmpty() - && valueFilter.getParentPath().equivalent(new ItemPath(ShadowType.F_ATTRIBUTES))) { + if (valueFilter.getParentPath() == null || valueFilter.getParentPath().isEmpty()) { + throw new UnsupportedOperationException("Empty path is not supported (filter: " + objectFilter+")"); + } + if (valueFilter.getParentPath().equivalent(new ItemPath(ShadowType.F_ATTRIBUTES))) { try { QName propName = valueFilter.getDefinition().getName(); String icfName = icfNameMapper.convertAttributeNameToIcf(propName, getInterpreter() @@ -100,14 +107,45 @@ public Filter interpret(ObjectFilter objectFilter, IcfNameMapper icfNameMapp return FilterBuilder.contains(AttributeBuilder.build(icfName, convertedValues.iterator().next())); } } else { - throw new UnsupportedOperationException("Unsupported filter type: " + objectFilter.debugDump()); + throw new UnsupportedOperationException("Unsupported filter type: " + objectFilter); } } catch (SchemaException ex) { throw ex; } + } else if (valueFilter.getParentPath().equivalent(new ItemPath(ShadowType.F_ACTIVATION))) { + + if (objectFilter instanceof EqualFilter) { + QName propName = valueFilter.getDefinition().getName(); + EqualFilter eq = (EqualFilter) objectFilter; + List> values = eq.getValues(); + if (values.size() != 1) { + throw new SchemaException("Unexpected number of values in filter "+objectFilter); + } + PrismPropertyValue pval = values.get(0); + String icfName; + Object convertedValue; + if (propName.equals(ActivationType.F_ADMINISTRATIVE_STATUS)) { + icfName = OperationalAttributes.ENABLE_NAME; + convertedValue = pval.getValue() == ActivationStatusType.ENABLED; + } else if (propName.equals(ActivationType.F_LOCKOUT_STATUS)) { + icfName = OperationalAttributes.LOCK_OUT_NAME; + convertedValue = pval.getValue() == LockoutStatusType.LOCKED; + } else { + throw new UnsupportedOperationException("Unsupported activation property "+propName+" in filter: " + objectFilter); + } + Attribute attr = AttributeBuilder.build(icfName, convertedValue); + if (valueFilter.getDefinition().isSingleValue()) { + return FilterBuilder.equalTo(attr); + } else { + return FilterBuilder.containsAllValues(attr); + } + + } else { + throw new UnsupportedOperationException("Unsupported filter type in filter: " + objectFilter); + } } else { - throw new UnsupportedOperationException("Unsupported parent path "+valueFilter.getParentPath()+" in filter: " + objectFilter.debugDump()); + throw new UnsupportedOperationException("Unsupported parent path "+valueFilter.getParentPath()+" in filter: " + objectFilter); } } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java index 1fa42d78201..16df82a3cbb 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java @@ -101,6 +101,7 @@ import com.evolveum.midpoint.schema.DeltaConvertor; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.ResultHandler; +import com.evolveum.midpoint.schema.SearchResultList; import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.constants.MidPointConstants; import com.evolveum.midpoint.schema.constants.SchemaConstants; @@ -1980,7 +1981,7 @@ public void test135ExecuteScript() throws Exception { assertSteadyResource(); } - @Test + @Test public void test150DisableAccount() throws Exception { final String TEST_NAME = "test150DisableAccount"; TestUtil.displayTestTile(TEST_NAME); @@ -2024,54 +2025,85 @@ public void test150DisableAccount() throws Exception { assertSteadyResource(); } + + @Test + public void test151SearchDisabledAccounts() throws Exception { + final String TEST_NAME = "test151SearchDisabledAccounts"; + TestUtil.displayTestTile(TEST_NAME); + // GIVEN + + Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(RESOURCE_DUMMY_OID, ProvisioningTestUtil.getDefaultAccountObjectClass(resourceType), prismContext); + ObjectQueryUtil.filterAnd(query.getFilter(), + EqualFilter.createEqual(new ItemPath(ShadowType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS), getShadowDefinition(), ActivationStatusType.DISABLED)); - @Test - public void test151ActivationStatusUndefinedAccount() throws Exception { - final String TEST_NAME = "test151ActivationStatusUndefinedAccount"; - TestUtil.displayTestTile(TEST_NAME); - // GIVEN + syncServiceMock.reset(); - Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); - OperationResult result = task.getResult(); + // WHEN + SearchResultList> resultList = provisioningService.searchObjects(ShadowType.class, query, null, result); - ShadowType accountType = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, task, - result).asObjectable(); - assertNotNull(accountType); - display("Retrieved account shadow", accountType); + // THEN + result.computeStatus(); + display(result); + TestUtil.assertSuccess(result); + + assertEquals("Unexpected number of search results", 1, resultList.size()); + PrismObject shadow = resultList.get(0); + display("Shadow", shadow); + assertActivationAdministrativeStatus(shadow, ActivationStatusType.DISABLED); + + assertSteadyResource(); + } + + @Test + public void test152ActivationStatusUndefinedAccount() throws Exception { + final String TEST_NAME = "test152ActivationStatusUndefinedAccount"; + TestUtil.displayTestTile(TEST_NAME); + // GIVEN + + Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + ShadowType accountType = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, task, + result).asObjectable(); + assertNotNull(accountType); + display("Retrieved account shadow", accountType); + + DummyAccount dummyAccount = getDummyAccountAssert(transformNameFromResource(ACCOUNT_WILL_USERNAME), willIcfUid); + assertFalse("Account is not disabled", dummyAccount.isEnabled()); + + syncServiceMock.reset(); + + ObjectDelta delta = ObjectDelta.createModificationDeleteProperty(ShadowType.class, + ACCOUNT_WILL_OID, SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS, prismContext, + ActivationStatusType.DISABLED); + display("ObjectDelta", delta); + delta.checkConsistence(); + + // WHEN + provisioningService.modifyObject(ShadowType.class, delta.getOid(), delta.getModifications(), + new OperationProvisioningScriptsType(), null, task, result); + + // THEN + result.computeStatus(); + display("modifyObject result", result); + TestUtil.assertSuccess(result); + + delta.checkConsistence(); + // check if activation was changed + dummyAccount = getDummyAccountAssert(transformNameFromResource(ACCOUNT_WILL_USERNAME), willIcfUid); + assertFalse("Dummy account "+transformNameFromResource(ACCOUNT_WILL_USERNAME)+" is enabled, expected disabled", dummyAccount.isEnabled()); + + syncServiceMock.assertNotifySuccessOnly(); + + assertSteadyResource(); + } - DummyAccount dummyAccount = getDummyAccountAssert(transformNameFromResource(ACCOUNT_WILL_USERNAME), willIcfUid); - assertFalse("Account is not disabled", dummyAccount.isEnabled()); - - syncServiceMock.reset(); - - ObjectDelta delta = ObjectDelta.createModificationDeleteProperty(ShadowType.class, - ACCOUNT_WILL_OID, SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS, prismContext, - ActivationStatusType.DISABLED); - display("ObjectDelta", delta); - delta.checkConsistence(); - - // WHEN - provisioningService.modifyObject(ShadowType.class, delta.getOid(), delta.getModifications(), - new OperationProvisioningScriptsType(), null, task, result); - - // THEN - result.computeStatus(); - display("modifyObject result", result); - TestUtil.assertSuccess(result); - - delta.checkConsistence(); - // check if activation was changed - dummyAccount = getDummyAccountAssert(transformNameFromResource(ACCOUNT_WILL_USERNAME), willIcfUid); - assertFalse("Dummy account "+transformNameFromResource(ACCOUNT_WILL_USERNAME)+" is enabled, expected disabled", dummyAccount.isEnabled()); - - syncServiceMock.assertNotifySuccessOnly(); - - assertSteadyResource(); - } - @Test - public void test151EnableAccount() throws Exception { - final String TEST_NAME = "test151EnableAccount"; + public void test154EnableAccount() throws Exception { + final String TEST_NAME = "test154EnableAccount"; TestUtil.displayTestTile(TEST_NAME); // GIVEN @@ -2113,11 +2145,38 @@ public void test151EnableAccount() throws Exception { assertSteadyResource(); } + @Test + public void test155SearchDisabledAccounts() throws Exception { + final String TEST_NAME = "test155SearchDisabledAccounts"; + TestUtil.displayTestTile(TEST_NAME); + // GIVEN + + Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(RESOURCE_DUMMY_OID, ProvisioningTestUtil.getDefaultAccountObjectClass(resourceType), prismContext); + ObjectQueryUtil.filterAnd(query.getFilter(), + EqualFilter.createEqual(new ItemPath(ShadowType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS), getShadowDefinition(), ActivationStatusType.DISABLED)); + + syncServiceMock.reset(); + + // WHEN + SearchResultList> resultList = provisioningService.searchObjects(ShadowType.class, query, null, result); + + // THEN + result.computeStatus(); + display(result); + TestUtil.assertSuccess(result); + + assertEquals("Unexpected number of search results", 0, resultList.size()); + + assertSteadyResource(); + } @Test - public void test152SetValidFrom() throws Exception { - final String TEST_NAME = "test152SetValidFrom"; + public void test156SetValidFrom() throws Exception { + final String TEST_NAME = "test156SetValidFrom"; TestUtil.displayTestTile(TEST_NAME); // GIVEN @@ -2163,8 +2222,8 @@ public void test152SetValidFrom() throws Exception { } @Test - public void test153SetValidTo() throws Exception { - final String TEST_NAME = "test153SetValidTo"; + public void test157SetValidTo() throws Exception { + final String TEST_NAME = "test157SetValidTo"; TestUtil.displayTestTile(TEST_NAME); // GIVEN @@ -2211,8 +2270,8 @@ public void test153SetValidTo() throws Exception { } @Test - public void test154DeleteValidToValidFrom() throws Exception { - final String TEST_NAME = "test154DeleteValidToValidFrom"; + public void test158DeleteValidToValidFrom() throws Exception { + final String TEST_NAME = "test158DeleteValidToValidFrom"; TestUtil.displayTestTile(TEST_NAME); // GIVEN @@ -2262,8 +2321,8 @@ public void test154DeleteValidToValidFrom() throws Exception { } @Test - public void test155GetLockedoutAccount() throws Exception { - final String TEST_NAME = "test155GetLockedoutAccount"; + public void test159GetLockedoutAccount() throws Exception { + final String TEST_NAME = "test159GetLockedoutAccount"; TestUtil.displayTestTile(TEST_NAME); // GIVEN OperationResult result = new OperationResult(TestDummy.class.getName() @@ -2300,8 +2359,39 @@ public void test155GetLockedoutAccount() throws Exception { } @Test - public void test156UnlockAccount() throws Exception { - final String TEST_NAME = "test156UnlockAccount"; + public void test160SearchLockedAccounts() throws Exception { + final String TEST_NAME = "test160SearchLockedAccounts"; + TestUtil.displayTestTile(TEST_NAME); + // GIVEN + + Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(RESOURCE_DUMMY_OID, ProvisioningTestUtil.getDefaultAccountObjectClass(resourceType), prismContext); + ObjectQueryUtil.filterAnd(query.getFilter(), + EqualFilter.createEqual(new ItemPath(ShadowType.F_ACTIVATION, ActivationType.F_LOCKOUT_STATUS), getShadowDefinition(), LockoutStatusType.LOCKED)); + + syncServiceMock.reset(); + + // WHEN + SearchResultList> resultList = provisioningService.searchObjects(ShadowType.class, query, null, result); + + // THEN + result.computeStatus(); + display(result); + TestUtil.assertSuccess(result); + + assertEquals("Unexpected number of search results", 1, resultList.size()); + PrismObject shadow = resultList.get(0); + display("Shadow", shadow); + assertLockout(shadow, LockoutStatusType.LOCKED); + + assertSteadyResource(); + } + + @Test + public void test162UnlockAccount() throws Exception { + final String TEST_NAME = "test162UnlockAccount"; TestUtil.displayTestTile(TEST_NAME); // GIVEN @@ -2346,8 +2436,8 @@ public void test156UnlockAccount() throws Exception { } @Test - public void test159GetAccount() throws Exception { - final String TEST_NAME = "test159GetAccount"; + public void test163GetAccount() throws Exception { + final String TEST_NAME = "test163GetAccount"; TestUtil.displayTestTile(TEST_NAME); // GIVEN OperationResult result = new OperationResult(TestDummy.class.getName() @@ -2384,16 +2474,44 @@ public void test159GetAccount() throws Exception { } @Test - public void test160SearchNull() throws Exception { - final String TEST_NAME = "test160SearchNull"; + public void test163SearchLockedAccounts() throws Exception { + final String TEST_NAME = "test163SearchLockedAccounts"; + TestUtil.displayTestTile(TEST_NAME); + // GIVEN + + Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(RESOURCE_DUMMY_OID, ProvisioningTestUtil.getDefaultAccountObjectClass(resourceType), prismContext); + ObjectQueryUtil.filterAnd(query.getFilter(), + EqualFilter.createEqual(new ItemPath(ShadowType.F_ACTIVATION, ActivationType.F_LOCKOUT_STATUS), getShadowDefinition(), LockoutStatusType.LOCKED)); + + syncServiceMock.reset(); + + // WHEN + SearchResultList> resultList = provisioningService.searchObjects(ShadowType.class, query, null, result); + + // THEN + result.computeStatus(); + display(result); + TestUtil.assertSuccess(result); + + assertEquals("Unexpected number of search results", 0, resultList.size()); + + assertSteadyResource(); + } + + @Test + public void test170SearchNull() throws Exception { + final String TEST_NAME = "test170SearchNull"; TestUtil.displayTestTile(TEST_NAME); testSeachIterative(TEST_NAME, null, null, true, true, false, "meathook", "daemon", transformNameFromResource("morgan"), transformNameFromResource("Will")); } @Test - public void test161SearchShipSeaMonkey() throws Exception { - final String TEST_NAME = "test161SearchShipSeaMonkey"; + public void test171SearchShipSeaMonkey() throws Exception { + final String TEST_NAME = "test171SearchShipSeaMonkey"; TestUtil.displayTestTile(TEST_NAME); testSeachIterativeSingleAttrFilter(TEST_NAME, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_SHIP_NAME, "Sea Monkey", null, true, @@ -2402,8 +2520,8 @@ public void test161SearchShipSeaMonkey() throws Exception { // See MID-1460 @Test(enabled=false) - public void test162SearchShipNull() throws Exception { - final String TEST_NAME = "test162SearchShipNull"; + public void test172SearchShipNull() throws Exception { + final String TEST_NAME = "test172SearchShipNull"; TestUtil.displayTestTile(TEST_NAME); testSeachIterativeSingleAttrFilter(TEST_NAME, DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_SHIP_NAME, null, null, true, @@ -2411,8 +2529,8 @@ public void test162SearchShipNull() throws Exception { } @Test - public void test163SearchWeaponCutlass() throws Exception { - final String TEST_NAME = "test163SearchWeaponCutlass"; + public void test173SearchWeaponCutlass() throws Exception { + final String TEST_NAME = "test173SearchWeaponCutlass"; TestUtil.displayTestTile(TEST_NAME); // Make sure there is an account on resource that the provisioning has @@ -2433,8 +2551,8 @@ public void test163SearchWeaponCutlass() throws Exception { } @Test - public void test165SearchUidExact() throws Exception { - final String TEST_NAME = "test165SearchUidExact"; + public void test175SearchUidExact() throws Exception { + final String TEST_NAME = "test175SearchUidExact"; TestUtil.displayTestTile(TEST_NAME); testSeachIterativeSingleAttrFilter(TEST_NAME, ConnectorFactoryIcfImpl.ICFS_UID, willIcfUid, null, true, @@ -2442,8 +2560,8 @@ public void test165SearchUidExact() throws Exception { } @Test - public void test166SearchUidExactNoFetch() throws Exception { - final String TEST_NAME = "test166SearchUidExactNoFetch"; + public void test176SearchUidExactNoFetch() throws Exception { + final String TEST_NAME = "test176SearchUidExactNoFetch"; TestUtil.displayTestTile(TEST_NAME); testSeachIterativeSingleAttrFilter(TEST_NAME, ConnectorFactoryIcfImpl.ICFS_UID, willIcfUid, GetOperationOptions.createNoFetch(), false, @@ -2451,8 +2569,8 @@ public void test166SearchUidExactNoFetch() throws Exception { } @Test - public void test167SearchIcfNameRepoized() throws Exception { - final String TEST_NAME = "test167SearchIcfNameRepoized"; + public void test177SearchIcfNameRepoized() throws Exception { + final String TEST_NAME = "test177SearchIcfNameRepoized"; TestUtil.displayTestTile(TEST_NAME); testSeachIterativeSingleAttrFilter(TEST_NAME, ConnectorFactoryIcfImpl.ICFS_NAME, getWillRepoIcfName(), null, true, @@ -2460,8 +2578,8 @@ ConnectorFactoryIcfImpl.ICFS_NAME, getWillRepoIcfName(), null, true, } @Test - public void test167aSearchIcfNameRepoizedNoFetch() throws Exception { - final String TEST_NAME = "test167aSearchIcfNameRepoizedNoFetch"; + public void test180SearchIcfNameRepoizedNoFetch() throws Exception { + final String TEST_NAME = "test180SearchIcfNameRepoizedNoFetch"; TestUtil.displayTestTile(TEST_NAME); testSeachIterativeSingleAttrFilter(TEST_NAME, ConnectorFactoryIcfImpl.ICFS_NAME, getWillRepoIcfName(), GetOperationOptions.createNoFetch(), false, @@ -2469,8 +2587,8 @@ public void test167aSearchIcfNameRepoizedNoFetch() throws Exception { } @Test - public void test168SearchIcfNameExact() throws Exception { - final String TEST_NAME = "test168SearchIcfNameExact"; + public void test181SearchIcfNameExact() throws Exception { + final String TEST_NAME = "test181SearchIcfNameExact"; TestUtil.displayTestTile(TEST_NAME); testSeachIterativeSingleAttrFilter(TEST_NAME, ConnectorFactoryIcfImpl.ICFS_NAME, transformNameFromResource(ACCOUNT_WILL_USERNAME), null, true, @@ -2478,8 +2596,8 @@ ConnectorFactoryIcfImpl.ICFS_NAME, transformNameFromResource(ACCOUNT_WILL_USERNA } @Test - public void test168aSearchIcfNameExactNoFetch() throws Exception { - final String TEST_NAME = "test168aSearchIcfNameExactNoFetch"; + public void test182SearchIcfNameExactNoFetch() throws Exception { + final String TEST_NAME = "test182SearchIcfNameExactNoFetch"; TestUtil.displayTestTile(TEST_NAME); testSeachIterativeSingleAttrFilter(TEST_NAME, ConnectorFactoryIcfImpl.ICFS_NAME, transformNameFromResource(ACCOUNT_WILL_USERNAME), GetOperationOptions.createNoFetch(), false, @@ -2488,8 +2606,8 @@ public void test168aSearchIcfNameExactNoFetch() throws Exception { // TEMPORARY todo move to more appropriate place (model-intest?) @Test - public void test168bSearchIcfNameAndUidExactNoFetch() throws Exception { - final String TEST_NAME = "test168bSearchIcfNameAndUidExactNoFetch"; + public void test183SearchIcfNameAndUidExactNoFetch() throws Exception { + final String TEST_NAME = "test183SearchIcfNameAndUidExactNoFetch"; TestUtil.displayTestTile(TEST_NAME); testSeachIterativeAlternativeAttrFilter(TEST_NAME, ConnectorFactoryIcfImpl.ICFS_NAME, transformNameFromResource(ACCOUNT_WILL_USERNAME), ConnectorFactoryIcfImpl.ICFS_UID, willIcfUid, @@ -2499,8 +2617,8 @@ public void test168bSearchIcfNameAndUidExactNoFetch() throws Exception { @Test - public void test170SearchNone() throws Exception { - final String TEST_NAME = "test170SearchNone"; + public void test190SearchNone() throws Exception { + final String TEST_NAME = "test190SearchNone"; TestUtil.displayTestTile(TEST_NAME); ObjectFilter attrFilter = NoneFilter.createNone(); testSeachIterative(TEST_NAME, attrFilter, null, true, true, false); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummyNoActivation.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummyNoActivation.java index 88877cc4863..a8fc3815bb7 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummyNoActivation.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummyNoActivation.java @@ -127,8 +127,13 @@ public void test150DisableAccount() throws Exception { } @Override - public void test151ActivationStatusUndefinedAccount() throws Exception { - final String TEST_NAME = "test151EnableAccount"; + public void test151SearchDisabledAccounts() throws Exception { + // N/A + } + + @Override + public void test152ActivationStatusUndefinedAccount() throws Exception { + final String TEST_NAME = "test152ActivationStatusUndefinedAccount"; TestUtil.displayTestTile(TEST_NAME); // GIVEN @@ -171,8 +176,8 @@ public void test151ActivationStatusUndefinedAccount() throws Exception { @Test @Override - public void test151EnableAccount() throws Exception { - final String TEST_NAME = "test151EnableAccount"; + public void test154EnableAccount() throws Exception { + final String TEST_NAME = "test154EnableAccount"; TestUtil.displayTestTile(TEST_NAME); // GIVEN @@ -213,10 +218,15 @@ public void test151EnableAccount() throws Exception { assertSteadyResource(); } + @Override + public void test155SearchDisabledAccounts() throws Exception { + // N/A + } + @Test @Override - public void test152SetValidFrom() throws Exception { - final String TEST_NAME = "test152SetValidFrom"; + public void test156SetValidFrom() throws Exception { + final String TEST_NAME = "test156SetValidFrom"; TestUtil.displayTestTile(TEST_NAME); // GIVEN @@ -261,8 +271,8 @@ public void test152SetValidFrom() throws Exception { @Test @Override - public void test153SetValidTo() throws Exception { - final String TEST_NAME = "test153SetValidTo"; + public void test157SetValidTo() throws Exception { + final String TEST_NAME = "test157SetValidTo"; TestUtil.displayTestTile(TEST_NAME); // GIVEN @@ -306,8 +316,8 @@ public void test153SetValidTo() throws Exception { } @Override - public void test154DeleteValidToValidFrom() throws Exception { - final String TEST_NAME = "test153SetValidTo"; + public void test158DeleteValidToValidFrom() throws Exception { + final String TEST_NAME = "test158DeleteValidToValidFrom"; TestUtil.displayTestTile(TEST_NAME); // GIVEN @@ -356,14 +366,19 @@ public void test154DeleteValidToValidFrom() throws Exception { @Test @Override - public void test155GetLockedoutAccount() throws Exception { + public void test159GetLockedoutAccount() throws Exception { // Not relevant } + @Override + public void test160SearchLockedAccounts() throws Exception { + // N/A + } + @Test @Override - public void test156UnlockAccount() throws Exception { - final String TEST_NAME = "test156UnlockAccount"; + public void test162UnlockAccount() throws Exception { + final String TEST_NAME = "test162UnlockAccount"; TestUtil.displayTestTile(TEST_NAME); // GIVEN diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java index dc386b637a4..143bec6c60e 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java @@ -1023,4 +1023,29 @@ protected void assertShadows(int expected, OperationResult result) throws Schema assertEquals("Unexpected number of (repository) shadows", expected, actual); } + protected void assertActivationAdministrativeStatus(PrismObject shadow, ActivationStatusType expectedStatus) { + ActivationType activationType = shadow.asObjectable().getActivation(); + if (activationType == null) { + if (expectedStatus == null) { + return; + } else { + AssertJUnit.fail("Expected activation administrative status of "+shadow+" to be "+expectedStatus+", but there was no activation administrative status"); + } + } else { + assertEquals("Wrong activation administrative status of "+shadow, expectedStatus, activationType.getAdministrativeStatus()); + } + } + + protected void assertLockout(PrismObject shadow, LockoutStatusType expectedStatus) { + ActivationType activationType = shadow.asObjectable().getActivation(); + if (activationType == null) { + if (expectedStatus == null) { + return; + } else { + AssertJUnit.fail("Expected lockout status of "+shadow+" to be "+expectedStatus+", but there was no lockout status"); + } + } else { + assertEquals("Wrong lockout status of "+shadow, expectedStatus, activationType.getLockoutStatus()); + } + } } diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/Abstract389DsTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/Abstract389DsTest.java index 0685056853b..b5538d432a8 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/Abstract389DsTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/Abstract389DsTest.java @@ -85,7 +85,7 @@ protected boolean isIdmAdminInteOrgPerson() { } @Override - public String getAttributeEntryIdName() { + public String getPrimaryIdentifierAttributeName() { return "nsUniqueId"; } diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractEDirTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractEDirTest.java new file mode 100644 index 00000000000..2d0bad918b9 --- /dev/null +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractEDirTest.java @@ -0,0 +1,341 @@ +/** + * Copyright (c) 2015 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.testing.conntest; + +import static org.testng.AssertJUnit.assertNotNull; +import static com.evolveum.midpoint.test.IntegrationTestTools.display; +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; + +import java.io.File; + +import org.apache.directory.api.ldap.model.exception.LdapException; +import org.apache.directory.ldap.client.api.LdapNetworkConnection; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.EqualFilter; +import com.evolveum.midpoint.prism.query.ObjectFilter; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.schema.SearchResultList; +import com.evolveum.midpoint.schema.SearchResultMetadata; +import com.evolveum.midpoint.schema.processor.ResourceAttribute; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectQueryUtil; +import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.test.util.MidPointTestConstants; +import com.evolveum.midpoint.test.util.TestUtil; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.LockoutStatusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; + +/** + * @author semancik + * + */ +@Listeners({com.evolveum.midpoint.tools.testng.AlphabeticalMethodInterceptor.class}) +public abstract class AbstractEDirTest extends AbstractLdapTest { + + protected static final String ACCOUNT_JACK_UID = "jack"; + protected static final int NUMBER_OF_ACCOUNTS = 5; + protected static final int LOCKOUT_EXPIRATION_SECONDS = 65; + + protected long jackLockoutTimestamp; + + + @Override + public String getStartSystemCommand() { + return null; + } + + @Override + public String getStopSystemCommand() { + return null; + } + + @Override + protected File getBaseDir() { + return new File(MidPointTestConstants.TEST_RESOURCES_DIR, "edir"); + } + + @Override + protected String getSyncTaskOid() { + return null; + } + + @Override + protected boolean useSsl() { + return true; + } + + @Override + protected String getLdapSuffix() { + return "o=example"; + } + + @Override + protected String getLdapBindDn() { + return "cn=admin,o=example"; + } + + @Override + protected String getLdapBindPassword() { + return "secret"; + } + + @Override + protected int getSearchSizeLimit() { + return -1; + } + + @Override + public String getPrimaryIdentifierAttributeName() { + return "GUID"; + } + + @Override + protected String getLdapGroupObjectClass() { + return "groupOfNames"; + } + + @Override + protected String getLdapGroupMemberAttribute() { + return "member"; + } + + @Test + public void test100SeachJackByLdapUid() throws Exception { + final String TEST_NAME = "test100SeachJackByLdapUid"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(this.getClass().getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + ResourceAttributeDefinition ldapUidAttrDef = accountObjectClassDefinition.findAttributeDefinition("uid"); + + ObjectQuery query = createUidQuery(ACCOUNT_JACK_UID); + + rememberConnectorOperationCount(); + rememberConnectorSimulatedPagingSearchCount(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + SearchResultList> shadows = modelService.searchObjects(ShadowType.class, query, null, task, result); + + // THEN + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertEquals("Unexpected search result: "+shadows, 1, shadows.size()); + + PrismObject shadow = shadows.get(0); + display("Shadow", shadow); + assertAccountShadow(shadow, toDn(ACCOUNT_JACK_UID)); + assertLockout(shadow, LockoutStatusType.NORMAL); + + assertConnectorOperationIncrement(2); + assertConnectorSimulatedPagingSearchIncrement(0); + + SearchResultMetadata metadata = shadows.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + } + + @Test + public void test110JackLockout() throws Exception { + final String TEST_NAME = "test110JackLockout"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(this.getClass().getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + makeBadLoginAttempt(ACCOUNT_JACK_UID); + makeBadLoginAttempt(ACCOUNT_JACK_UID); + makeBadLoginAttempt(ACCOUNT_JACK_UID); + makeBadLoginAttempt(ACCOUNT_JACK_UID); + + jackLockoutTimestamp = System.currentTimeMillis(); + + ObjectQuery query = createUidQuery(ACCOUNT_JACK_UID); + + rememberConnectorOperationCount(); + rememberConnectorSimulatedPagingSearchCount(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + SearchResultList> shadows = modelService.searchObjects(ShadowType.class, query, null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertEquals("Unexpected search result: "+shadows, 1, shadows.size()); + + PrismObject shadow = shadows.get(0); + display("Shadow", shadow); + assertAccountShadow(shadow, toDn(ACCOUNT_JACK_UID)); + assertLockout(shadow, LockoutStatusType.LOCKED); + + assertConnectorOperationIncrement(2); + assertConnectorSimulatedPagingSearchIncrement(0); + + SearchResultMetadata metadata = shadows.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + } + + /** + * No paging. It should return all accounts. + */ + @Test + public void test150SeachAllAccounts() throws Exception { + final String TEST_NAME = "test150SeachAllAccounts"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(this.getClass().getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + + SearchResultList> searchResultList = doSearch(TEST_NAME, query, NUMBER_OF_ACCOUNTS, task, result); + + assertConnectorOperationIncrement(6); + assertConnectorSimulatedPagingSearchIncrement(0); + + SearchResultMetadata metadata = searchResultList.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + } + + @Test + public void test190SeachLockedAccounts() throws Exception { + final String TEST_NAME = "test190SeachLockedAccounts"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(this.getClass().getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + ObjectQueryUtil.filterAnd(query.getFilter(), + EqualFilter.createEqual(new ItemPath(ShadowType.F_ACTIVATION, ActivationType.F_LOCKOUT_STATUS), getShadowDefinition(), LockoutStatusType.LOCKED)); + + SearchResultList> searchResultList = doSearch(TEST_NAME, query, 1, task, result); + + assertConnectorOperationIncrement(2); + assertConnectorSimulatedPagingSearchIncrement(0); + + PrismObject shadow = searchResultList.get(0); + display("Shadow", shadow); + assertAccountShadow(shadow, toDn(ACCOUNT_JACK_UID)); + assertLockout(shadow, LockoutStatusType.LOCKED); + + SearchResultMetadata metadata = searchResultList.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + } + + // TODO: Search all locked accounts. Jack should be there. + + // TODO: test rename + + // Wait until the lockout of Jack expires, check status + @Test + public void test800JackLockoutExpires() throws Exception { + final String TEST_NAME = "test800JackLockoutExpires"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(this.getClass().getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + long now = System.currentTimeMillis(); + long lockoutExpires = jackLockoutTimestamp + LOCKOUT_EXPIRATION_SECONDS*1000; + if (now < lockoutExpires) { + display("Sleeping for "+(lockoutExpires-now)+"ms (waiting for lockout expiration)"); + Thread.sleep(lockoutExpires-now); + } + now = System.currentTimeMillis(); + display("Time is now "+now); + + ObjectQuery query = createUidQuery(ACCOUNT_JACK_UID); + + rememberConnectorOperationCount(); + rememberConnectorSimulatedPagingSearchCount(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + SearchResultList> shadows = modelService.searchObjects(ShadowType.class, query, null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertEquals("Unexpected search result: "+shadows, 1, shadows.size()); + + PrismObject shadow = shadows.get(0); + display("Shadow", shadow); + assertAccountShadow(shadow, toDn(ACCOUNT_JACK_UID)); + assertLockout(shadow, LockoutStatusType.NORMAL); + + assertConnectorOperationIncrement(2); + assertConnectorSimulatedPagingSearchIncrement(0); + + SearchResultMetadata metadata = shadows.getMetadata(); + if (metadata != null) { + assertFalse(metadata.isPartialResults()); + } + } + + // TODO: Search all locked accounts. Jack should not be there. + + // TODO: lock out jack again, explicitly reset the lock, see that he can login + + @Override + protected void assertAccountShadow(PrismObject shadow, String dn) throws SchemaException { + super.assertAccountShadow(shadow, dn); + ResourceAttribute primaryIdAttr = ShadowUtil.getAttribute(shadow, getPrimaryIdentifierAttributeQName()); + assertNotNull("No primary identifier ("+getPrimaryIdentifierAttributeQName()+" in "+shadow, primaryIdAttr); + String primaryId = primaryIdAttr.getRealValue(); + assertTrue("Unexpected chars in primary ID: '"+primaryId+"'", primaryId.matches("[a-z0-9]+")); + } + + private void makeBadLoginAttempt(String uid) throws LdapException { + LdapNetworkConnection conn = ldapConnect(toDn(uid), "thisIsAwRoNgPASSW0RD"); + if (conn.isAuthenticated()) { + AssertJUnit.fail("Bad authentication went good for "+uid); + } + } + +} diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapConnTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapConnTest.java index 6d4c2dff33f..14f7f0599f3 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapConnTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapConnTest.java @@ -127,22 +127,10 @@ */ @ContextConfiguration(locations = {"classpath:ctx-conntest-test-main.xml"}) @DirtiesContext(classMode = ClassMode.AFTER_CLASS) -public abstract class AbstractLdapConnTest extends AbstractModelIntegrationTest { +public abstract class AbstractLdapConnTest extends AbstractLdapTest { private static final Trace LOGGER = TraceManager.getTrace(AbstractLdapConnTest.class); - - public static final File TEST_DIR = new File(MidPointTestConstants.TEST_RESOURCES_DIR, "ldap"); - - public static final File SYSTEM_CONFIGURATION_FILE = new File(COMMON_DIR, "system-configuration.xml"); - public static final String SYSTEM_CONFIGURATION_OID = SystemObjectsType.SYSTEM_CONFIGURATION.value(); - - protected static final File USER_ADMINISTRATOR_FILE = new File(COMMON_DIR, "user-administrator.xml"); - protected static final String USER_ADMINISTRATOR_OID = "00000000-0000-0000-0000-000000000002"; - protected static final String USER_ADMINISTRATOR_USERNAME = "administrator"; - - protected static final File ROLE_SUPERUSER_FILE = new File(COMMON_DIR, "role-superuser.xml"); - protected static final String ROLE_SUPERUSER_OID = "00000000-0000-0000-0000-000000000004"; - + protected static final File USER_BARBOSSA_FILE = new File(COMMON_DIR, "user-barbossa.xml"); protected static final String USER_BARBOSSA_OID = "c0c010c0-d34d-b33f-f00d-111111111112"; protected static final String USER_BARBOSSA_USERNAME = "barbossa"; @@ -156,9 +144,7 @@ public abstract class AbstractLdapConnTest extends AbstractModelIntegrationTest private static final String USER_LECHUCK_NAME = "lechuck"; private static final String ACCOUNT_LECHUCK_NAME = "lechuck"; private static final String ACCOUNT_CHARLES_NAME = "charles"; - - private static final String LDAP_ACCOUNT_OBJECTCLASS = "inetOrgPerson"; - + private static final String LDAP_GROUP_PIRATES_DN = "cn=Pirates,ou=groups,dc=example,dc=com"; protected static final String ACCOUNT_IDM_DN = "uid=idm,ou=Administrators,dc=example,dc=com"; @@ -180,42 +166,12 @@ public abstract class AbstractLdapConnTest extends AbstractModelIntegrationTest private static final String GROUP_MONKEYS_CN = "monkeys"; private static final String GROUP_MONKEYS_DESCRIPTION = "Monkeys of Monkey Island"; - @Autowired(required = true) - protected MatchingRuleRegistry matchingRuleRegistry; - - protected ResourceType resourceType; - protected PrismObject resource; - - protected MatchingRule ciMatchingRule; - - private static String stopCommand; - - protected ObjectClassComplexTypeDefinition accountObjectClassDefinition; protected String account0Oid; protected String accountBarbossaOid; @Autowired protected ReconciliationTaskHandler reconciliationTaskHandler; - - @Override - protected void startResources() throws Exception { - super.startResources(); - - String command = getStartSystemCommand(); - if (command != null) { - TestUtil.execSystemCommand(command); - } - stopCommand = getStopSystemCommand(); - } - - public String getAttributeEntryIdName() { - return "entryUuid"; - } - public abstract String getStartSystemCommand(); - - public abstract String getStopSystemCommand(); - protected abstract void assertStepSyncToken(String syncTaskOid, int step, long tsStart, long tsEnd) throws ObjectNotFoundException, SchemaException; protected boolean isIdmAdminInteOrgPerson() { @@ -225,166 +181,25 @@ protected boolean isIdmAdminInteOrgPerson() { protected boolean syncCanDetectDelete() { return true; } - - - @AfterClass - public static void stopResources() throws Exception { - //end profiling - ProfilingDataManager.getInstance().printMapAfterTest(); - ProfilingDataManager.getInstance().stopProfilingAfterTest(); - - if (stopCommand != null) { - TestUtil.execSystemCommand(stopCommand); - } - } - - protected abstract String getResourceOid(); - - protected abstract File getBaseDir(); protected File getResourceFile() { return new File(getBaseDir(), "resource.xml"); } - - protected File getSyncTaskFile() { - return new File(getBaseDir(), "task-sync.xml"); - } - - protected File getSyncTaskInetOrgPersonFile() { - return new File(getBaseDir(), "task-sync-inetorgperson.xml"); - } - - protected abstract String getSyncTaskOid(); - - protected QName getAccountObjectClass() { - return new QName(MidPointConstants.NS_RI, "inetOrgPerson"); - } - - - protected abstract String getLdapServerHost(); - - protected abstract int getLdapServerPort(); - - protected abstract String getLdapBindDn(); - - protected abstract String getLdapBindPassword(); - - protected abstract int getSearchSizeLimit(); - - protected String getLdapSuffix() { - return "dc=example,dc=com"; - } - - protected String getPeopleLdapSuffix() { - return "ou=people,"+getLdapSuffix(); - } - - protected String getGroupsLdapSuffix() { - return "ou=groups,"+getLdapSuffix(); - } - - protected abstract String getLdapGroupObjectClass(); - - protected abstract String getLdapGroupMemberAttribute(); - - protected String getScriptDirectoryName() { - return "/opt/Bamboo/local/conntest"; - } - + protected abstract String getAccount0Cn(); @Override public void initSystem(Task initTask, OperationResult initResult) throws Exception { super.initSystem(initTask, initResult); - // System Configuration - PrismObject config; - try { - config = repoAddObjectFromFile(SYSTEM_CONFIGURATION_FILE, SystemConfigurationType.class, initResult); - } catch (ObjectAlreadyExistsException e) { - throw new ObjectAlreadyExistsException("System configuration already exists in repository;" + - "looks like the previous test haven't cleaned it up", e); - } - - modelService.postInit(initResult); - - // to get profiling facilities (until better API is available) -// LoggingConfigurationManager.configure( -// ProfilingConfigurationManager.checkSystemProfilingConfiguration(config), -// config.asObjectable().getVersion(), initResult); - - // administrator - PrismObject userAdministrator = repoAddObjectFromFile(USER_ADMINISTRATOR_FILE, UserType.class, initResult); - repoAddObjectFromFile(ROLE_SUPERUSER_FILE, RoleType.class, initResult); - login(userAdministrator); - // Users repoAddObjectFromFile(USER_BARBOSSA_FILE, UserType.class, initResult); repoAddObjectFromFile(USER_GUYBRUSH_FILE, UserType.class, initResult); // Roles - // Resources - resource = importAndGetObjectFromFile(ResourceType.class, getResourceFile(), getResourceOid(), initTask, initResult); - resourceType = resource.asObjectable(); - - assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); - - //initProfiling - start - ProfilingDataManager profilingManager = ProfilingDataManager.getInstance(); - - Map subsystems = new HashMap<>(); - subsystems.put(ProfilingDataManager.Subsystem.MODEL, true); - subsystems.put(ProfilingDataManager.Subsystem.REPOSITORY, true); - profilingManager.configureProfilingDataManagerForTest(subsystems, true); - - profilingManager.appendProfilingToTest(); - //initProfiling - end - - ciMatchingRule = matchingRuleRegistry.getMatchingRule(StringIgnoreCaseMatchingRule.NAME, DOMUtil.XSD_STRING); } - - @Test - public void test010Connection() throws Exception { - final String TEST_NAME = "test010Connection"; - TestUtil.displayTestTile(TEST_NAME); - - OperationResult result = new OperationResult(this.getClass().getName()+"."+TEST_NAME); - - OperationResult operationResult = provisioningService.testResource(getResourceOid()); - display("Test connection result",operationResult); - TestUtil.assertSuccess("Test connection failed",operationResult); - } - - @Test - public void test020Schema() throws Exception { - final String TEST_NAME = "test020Schema"; - TestUtil.displayTestTile(this, TEST_NAME); - - // GIVEN - Task task = taskManager.createTaskInstance(this.getClass().getName() + "." + TEST_NAME); - OperationResult result = task.getResult(); - - RefinedResourceSchema refinedSchema = RefinedResourceSchema.getRefinedSchema(resource); - accountObjectClassDefinition = refinedSchema.findObjectClassDefinition(getAccountObjectClass()); - assertNotNull("No definition for object class "+getAccountObjectClass(), accountObjectClassDefinition); - - ResourceAttributeDefinition cnDef = accountObjectClassDefinition.findAttributeDefinition("cn"); - PrismAsserts.assertDefinition(cnDef, new QName(MidPointConstants.NS_RI, "cn"), DOMUtil.XSD_STRING, 1, -1); - assertTrue("createTimestampDef read", cnDef.canRead()); - assertTrue("createTimestampDef read", cnDef.canModify()); - assertTrue("createTimestampDef read", cnDef.canAdd()); - - ResourceAttributeDefinition createTimestampDef = accountObjectClassDefinition.findAttributeDefinition("createTimestamp"); - PrismAsserts.assertDefinition(createTimestampDef, new QName(MidPointConstants.NS_RI, "createTimestamp"), - DOMUtil.XSD_LONG, 0, 1); - assertTrue("createTimestampDef read", createTimestampDef.canRead()); - assertFalse("createTimestampDef read", createTimestampDef.canModify()); - assertFalse("createTimestampDef read", createTimestampDef.canAdd()); - - } - @Test public void test100SeachAccount0ByLdapUid() throws Exception { final String TEST_NAME = "test100SeachAccount0ByLdapUid"; @@ -396,10 +211,7 @@ public void test100SeachAccount0ByLdapUid() throws Exception { ResourceAttributeDefinition ldapUidAttrDef = accountObjectClassDefinition.findAttributeDefinition("uid"); - ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); - ObjectFilter additionalFilter = EqualFilter.createEqual( - new ItemPath(ShadowType.F_ATTRIBUTES, ldapUidAttrDef.getName()), ldapUidAttrDef, ACCOUNT_0_UID); - ObjectQueryUtil.filterAnd(query.getFilter(), additionalFilter); + ObjectQuery query = createUidQuery(ACCOUNT_0_UID); rememberConnectorOperationCount(); rememberConnectorSimulatedPagingSearchCount(); @@ -693,52 +505,7 @@ public void test190SeachAllAccountsSizelimit() throws Exception { } // TODO: scoped search - - private SearchResultList> doSearch(final String TEST_NAME, ObjectQuery query, int expectedSize, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { - return doSearch(TEST_NAME, query, null, expectedSize, task, result); - } - - private SearchResultList> doSearch(final String TEST_NAME, ObjectQuery query, GetOperationOptions rootOptions, int expectedSize, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { - final List> foundObjects = new ArrayList>(expectedSize); - ResultHandler handler = new ResultHandler() { - @Override - public boolean handle(PrismObject object, OperationResult parentResult) { -// LOGGER.trace("Found {}", object); - String name = object.asObjectable().getName().getOrig(); - for(PrismObject foundShadow: foundObjects) { - if (foundShadow.asObjectable().getName().getOrig().equals(name)) { - AssertJUnit.fail("Duplicate name "+name); - } - } - foundObjects.add(object); - return true; - } - }; - - Collection> options = null; - if (rootOptions != null) { - options = SelectorOptions.createCollection(rootOptions); - } - - rememberConnectorOperationCount(); - rememberConnectorSimulatedPagingSearchCount(); - - // WHEN - TestUtil.displayWhen(TEST_NAME); - SearchResultMetadata searchResultMetadata = modelService.searchObjectsIterative(ShadowType.class, query, handler, options, task, result); - - // THEN - result.computeStatus(); - TestUtil.assertSuccess(result); - - assertEquals("Unexpected number of accounts", expectedSize, foundObjects.size()); - - SearchResultList> resultList = new SearchResultList<>(foundObjects, searchResultMetadata); - - return resultList; - } - // TODO: count shadows @Test @@ -774,7 +541,7 @@ public void test200AssignAccountToBarbossa() throws Exception { String accountBarbossaIcfUid = (String) identifiers.iterator().next().getRealValue(); assertNotNull("No identifier in "+shadow, accountBarbossaIcfUid); - assertEquals("Wrong ICFS UID", entry.get(getAttributeEntryIdName()).getString(), accountBarbossaIcfUid); + assertEquals("Wrong ICFS UID", entry.get(getPrimaryIdentifierAttributeName()).getString(), accountBarbossaIcfUid); assertLdapPassword(USER_BARBOSSA_USERNAME, "deadjacktellnotales"); @@ -1333,151 +1100,4 @@ public void test839DeleteSyncTask() throws Exception { assertNoObject(TaskType.class, getSyncTaskOid(), task, result); } - protected Entry getLdapAccountByUid(String uid) throws LdapException, IOException, CursorException { - LdapNetworkConnection connection = ldapConnect(); - List entries = ldapSearch(connection, "(uid="+uid+")"); - ldapDisconnect(connection); - - assertEquals("Unexpected number of entries for uid="+uid+": "+entries, 1, entries.size()); - Entry entry = entries.get(0); - - return entry; - } - - protected Entry assertLdapAccount(String uid, String cn) throws LdapException, IOException, CursorException { - Entry entry = getLdapAccountByUid(uid); - assertAttribute(entry, "cn", cn); - return entry; - } - - protected void assertAttribute(Entry entry, String attrName, String expectedValue) throws LdapInvalidAttributeValueException { - String dn = entry.getDn().toString(); - Attribute ldapAttribute = entry.get(attrName); - if (ldapAttribute == null) { - if (expectedValue == null) { - return; - } else { - AssertJUnit.fail("No attribute "+attrName+" in "+dn+", expected: "+expectedValue); - } - } else { - assertEquals("Wrong attribute "+attrName+" in "+dn, expectedValue, ldapAttribute.getString()); - } - } - - protected void assertNoLdapAccount(String uid) throws LdapException, IOException, CursorException { - LdapNetworkConnection connection = ldapConnect(); - List entries = ldapSearch(connection, "(uid="+uid+")"); - ldapDisconnect(connection); - - assertEquals("Unexpected number of entries for uid="+uid+": "+entries, 0, entries.size()); - } - - protected List ldapSearch(LdapNetworkConnection connection, String filter) throws LdapException, CursorException { - return ldapSearch(connection, getLdapSuffix(), filter, SearchScope.SUBTREE, "*", getAttributeEntryIdName()); - } - - protected List ldapSearch(LdapNetworkConnection connection, String baseDn, String filter, SearchScope scope, String... attributes) throws LdapException, CursorException { - List entries = new ArrayList(); - EntryCursor entryCursor = connection.search( baseDn, filter, scope, attributes ); - Entry entry = null; - while (entryCursor.next()) { - entries.add(entryCursor.get()); - } - return entries; - } - - protected void assertLdapPassword(String uid, String password) throws LdapException, IOException, CursorException { - Entry entry = getLdapAccountByUid(uid); - LdapNetworkConnection conn = ldapConnect(entry.getDn().toString(), password); - assertTrue("Not connected", conn.isConnected()); - assertTrue("Not authenticated", conn.isAuthenticated()); - } - - protected Entry addLdapAccount(String uid, String cn, String givenName, String sn) throws LdapException, IOException, CursorException { - LdapNetworkConnection connection = ldapConnect(); - Entry entry = createAccountEntry(uid, cn, givenName, sn); - connection.add(entry); - display("Added LDAP account:"+entry); - ldapDisconnect(connection); - return entry; - } - - protected Entry createAccountEntry(String uid, String cn, String givenName, String sn) throws LdapException { - Entry entry = new DefaultEntry(toDn(uid), - "objectclass", LDAP_ACCOUNT_OBJECTCLASS, - "uid", uid, - "cn", cn, - "givenName", givenName, - "sn", sn); - return entry; - } - - protected Entry addLdapGroup(String cn, String description, String memberDn) throws LdapException, IOException, CursorException { - LdapNetworkConnection connection = ldapConnect(); - Entry entry = createGroupEntry(cn, description, memberDn); - connection.add(entry); - display("Added LDAP group:"+entry); - ldapDisconnect(connection); - return entry; - } - - protected Entry createGroupEntry(String cn, String description, String memberDn) throws LdapException { - Entry entry = new DefaultEntry(toGroupDn(cn), - "objectclass", getLdapGroupObjectClass(), - "cn", cn, - "description", description, - getLdapGroupMemberAttribute(), memberDn); - return entry; - } - - protected void deleteLdapEntry(String dn) throws LdapException, IOException { - LdapNetworkConnection connection = ldapConnect(); - connection.delete(dn); - display("Deleted LDAP entry: "+dn); - ldapDisconnect(connection); - } - - protected String toDn(String username) { - return "uid="+username+","+getPeopleLdapSuffix(); - } - - protected String toGroupDn(String cn) { - return "cn="+cn+","+getGroupsLdapSuffix(); - } - - protected LdapNetworkConnection ldapConnect() throws LdapException { - return ldapConnect(getLdapBindDn(), getLdapBindPassword()); - } - - protected LdapNetworkConnection ldapConnect(String bindDn, String bindPassword) throws LdapException { - LdapConnectionConfig config = new LdapConnectionConfig(); - config.setLdapHost(getLdapServerHost()); - config.setLdapPort(getLdapServerPort()); - LdapNetworkConnection connection = new LdapNetworkConnection(config); - boolean connected = connection.connect(); - if (!connected) { - AssertJUnit.fail("Cannot connect to LDAP server "+getLdapServerHost()+":"+getLdapServerPort()); - } - BindRequest bindRequest = new BindRequestImpl(); - bindRequest.setDn(new Dn(bindDn)); - bindRequest.setCredentials(bindPassword); - BindResponse bindResponse = connection.bind(bindRequest); - return connection; - } - - protected void ldapDisconnect(LdapNetworkConnection connection) throws IOException { - connection.close(); - } - - protected void assertAccountShadow(PrismObject shadow, String dn) throws SchemaException { - assertShadowCommon(shadow, null, dn, resourceType, getAccountObjectClass(), ciMatchingRule); - } - - protected long roundTsDown(long ts) { - return (((long)(ts/1000))*1000); - } - - protected long roundTsUp(long ts) { - return (((long)(ts/1000))*1000)+1; - } } diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapTest.java new file mode 100644 index 00000000000..359c1f638b7 --- /dev/null +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapTest.java @@ -0,0 +1,566 @@ +package com.evolveum.midpoint.testing.conntest; +/* + * Copyright (c) 2010-2015 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import static org.testng.AssertJUnit.assertNull; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.assertNotNull; +import static com.evolveum.midpoint.test.IntegrationTestTools.display; +import static org.testng.AssertJUnit.assertEquals; + +import java.io.File; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import javax.xml.namespace.QName; + +import com.evolveum.midpoint.common.refinery.RefinedResourceSchema; +import com.evolveum.midpoint.model.impl.sync.ReconciliationTaskHandler; +import com.evolveum.midpoint.util.DOMUtil; +import com.evolveum.midpoint.util.Holder; +import com.evolveum.midpoint.util.aspect.ProfilingDataManager; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; +import org.apache.commons.lang.mutable.MutableInt; +import org.apache.directory.api.ldap.model.cursor.CursorException; +import org.apache.directory.api.ldap.model.cursor.EntryCursor; +import org.apache.directory.api.ldap.model.entry.Attribute; +import org.apache.directory.api.ldap.model.entry.DefaultEntry; +import org.apache.directory.api.ldap.model.entry.DefaultModification; +import org.apache.directory.api.ldap.model.entry.Entry; +import org.apache.directory.api.ldap.model.entry.Modification; +import org.apache.directory.api.ldap.model.entry.ModificationOperation; +import org.apache.directory.api.ldap.model.exception.LdapException; +import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException; +import org.apache.directory.api.ldap.model.message.BindRequest; +import org.apache.directory.api.ldap.model.message.BindRequestImpl; +import org.apache.directory.api.ldap.model.message.BindResponse; +import org.apache.directory.api.ldap.model.message.ModifyDnRequest; +import org.apache.directory.api.ldap.model.message.ModifyDnRequestImpl; +import org.apache.directory.api.ldap.model.message.ModifyDnResponse; +import org.apache.directory.api.ldap.model.message.SearchScope; +import org.apache.directory.api.ldap.model.name.Dn; +import org.apache.directory.api.ldap.model.name.Rdn; +import org.apache.directory.ldap.client.api.LdapConnectionConfig; +import org.apache.directory.ldap.client.api.LdapNetworkConnection; + +import com.evolveum.midpoint.model.test.AbstractModelIntegrationTest; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.delta.PropertyDelta; +import com.evolveum.midpoint.prism.match.MatchingRule; +import com.evolveum.midpoint.prism.match.MatchingRuleRegistry; +import com.evolveum.midpoint.prism.match.StringIgnoreCaseMatchingRule; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.EqualFilter; +import com.evolveum.midpoint.prism.query.ObjectFilter; +import com.evolveum.midpoint.prism.query.ObjectPaging; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.util.PrismAsserts; +import com.evolveum.midpoint.prism.util.PrismTestUtil; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.ResultHandler; +import com.evolveum.midpoint.schema.SearchResultList; +import com.evolveum.midpoint.schema.SearchResultMetadata; +import com.evolveum.midpoint.schema.SelectorOptions; +import com.evolveum.midpoint.schema.constants.MidPointConstants; +import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceAttribute; +import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.MiscSchemaUtil; +import com.evolveum.midpoint.schema.util.ObjectQueryUtil; +import com.evolveum.midpoint.schema.util.SchemaTestConstants; +import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.test.util.MidPointTestConstants; +import com.evolveum.midpoint.test.util.TestUtil; +import com.evolveum.midpoint.util.exception.CommunicationException; +import com.evolveum.midpoint.util.exception.ConfigurationException; +import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPolicyEnforcementType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemObjectsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; + +/** + * @author Radovan Semancik + * + */ +@ContextConfiguration(locations = {"classpath:ctx-conntest-test-main.xml"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public abstract class AbstractLdapTest extends AbstractModelIntegrationTest { + + private static final Trace LOGGER = TraceManager.getTrace(AbstractLdapTest.class); + + public static final File SYSTEM_CONFIGURATION_FILE = new File(COMMON_DIR, "system-configuration.xml"); + public static final String SYSTEM_CONFIGURATION_OID = SystemObjectsType.SYSTEM_CONFIGURATION.value(); + + protected static final File USER_ADMINISTRATOR_FILE = new File(COMMON_DIR, "user-administrator.xml"); + protected static final String USER_ADMINISTRATOR_OID = "00000000-0000-0000-0000-000000000002"; + protected static final String USER_ADMINISTRATOR_USERNAME = "administrator"; + + protected static final File ROLE_SUPERUSER_FILE = new File(COMMON_DIR, "role-superuser.xml"); + protected static final String ROLE_SUPERUSER_OID = "00000000-0000-0000-0000-000000000004"; + + private static final String LDAP_ACCOUNT_OBJECTCLASS = "inetOrgPerson"; + + @Autowired(required = true) + protected MatchingRuleRegistry matchingRuleRegistry; + + @Autowired + protected ReconciliationTaskHandler reconciliationTaskHandler; + + protected ResourceType resourceType; + protected PrismObject resource; + + protected MatchingRule ciMatchingRule; + + private static String stopCommand; + + protected ObjectClassComplexTypeDefinition accountObjectClassDefinition; + + @Override + protected void startResources() throws Exception { + super.startResources(); + + String command = getStartSystemCommand(); + if (command != null) { + TestUtil.execSystemCommand(command); + } + stopCommand = getStopSystemCommand(); + } + + + public abstract String getStartSystemCommand(); + + public abstract String getStopSystemCommand(); + + @AfterClass + public static void stopResources() throws Exception { + //end profiling + ProfilingDataManager.getInstance().printMapAfterTest(); + ProfilingDataManager.getInstance().stopProfilingAfterTest(); + + if (stopCommand != null) { + TestUtil.execSystemCommand(stopCommand); + } + } + + protected abstract String getResourceOid(); + + protected abstract File getBaseDir(); + + protected File getResourceFile() { + return new File(getBaseDir(), "resource.xml"); + } + + protected File getSyncTaskFile() { + return new File(getBaseDir(), "task-sync.xml"); + } + + protected File getSyncTaskInetOrgPersonFile() { + return new File(getBaseDir(), "task-sync-inetorgperson.xml"); + } + + protected abstract String getSyncTaskOid(); + + protected QName getAccountObjectClass() { + return new QName(MidPointConstants.NS_RI, LDAP_ACCOUNT_OBJECTCLASS); + } + + protected abstract String getLdapServerHost(); + + protected abstract int getLdapServerPort(); + + protected boolean useSsl() { + return false; + } + + protected abstract String getLdapBindDn(); + + protected abstract String getLdapBindPassword(); + + protected abstract int getSearchSizeLimit(); + + protected String getLdapSuffix() { + return "dc=example,dc=com"; + } + + protected String getPeopleLdapSuffix() { + return "ou=people,"+getLdapSuffix(); + } + + protected String getGroupsLdapSuffix() { + return "ou=groups,"+getLdapSuffix(); + } + + public String getPrimaryIdentifierAttributeName() { + return "entryUuid"; + } + + public QName getPrimaryIdentifierAttributeQName() { + return new QName(MidPointConstants.NS_RI,getPrimaryIdentifierAttributeName()); + } + + protected abstract String getLdapGroupObjectClass(); + + protected abstract String getLdapGroupMemberAttribute(); + + protected String getScriptDirectoryName() { + return "/opt/Bamboo/local/conntest"; + } + + @Override + public void initSystem(Task initTask, OperationResult initResult) throws Exception { + super.initSystem(initTask, initResult); + + // System Configuration + PrismObject config; + try { + config = repoAddObjectFromFile(SYSTEM_CONFIGURATION_FILE, SystemConfigurationType.class, initResult); + } catch (ObjectAlreadyExistsException e) { + throw new ObjectAlreadyExistsException("System configuration already exists in repository;" + + "looks like the previous test haven't cleaned it up", e); + } + + modelService.postInit(initResult); + + // to get profiling facilities (until better API is available) +// LoggingConfigurationManager.configure( +// ProfilingConfigurationManager.checkSystemProfilingConfiguration(config), +// config.asObjectable().getVersion(), initResult); + + // administrator + PrismObject userAdministrator = repoAddObjectFromFile(USER_ADMINISTRATOR_FILE, UserType.class, initResult); + repoAddObjectFromFile(ROLE_SUPERUSER_FILE, RoleType.class, initResult); + login(userAdministrator); + + // Roles + + // Resources + resource = importAndGetObjectFromFile(ResourceType.class, getResourceFile(), getResourceOid(), initTask, initResult); + resourceType = resource.asObjectable(); + + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + //initProfiling - start + ProfilingDataManager profilingManager = ProfilingDataManager.getInstance(); + + Map subsystems = new HashMap<>(); + subsystems.put(ProfilingDataManager.Subsystem.MODEL, true); + subsystems.put(ProfilingDataManager.Subsystem.REPOSITORY, true); + profilingManager.configureProfilingDataManagerForTest(subsystems, true); + + profilingManager.appendProfilingToTest(); + //initProfiling - end + + ciMatchingRule = matchingRuleRegistry.getMatchingRule(StringIgnoreCaseMatchingRule.NAME, DOMUtil.XSD_STRING); + } + + @Test + public void test010Connection() throws Exception { + final String TEST_NAME = "test010Connection"; + TestUtil.displayTestTile(TEST_NAME); + + OperationResult result = new OperationResult(this.getClass().getName()+"."+TEST_NAME); + + OperationResult operationResult = provisioningService.testResource(getResourceOid()); + + display("Test connection result",operationResult); + TestUtil.assertSuccess("Test connection failed",operationResult); + } + + @Test + public void test020Schema() throws Exception { + final String TEST_NAME = "test020Schema"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(this.getClass().getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + RefinedResourceSchema refinedSchema = RefinedResourceSchema.getRefinedSchema(resource); + accountObjectClassDefinition = refinedSchema.findObjectClassDefinition(getAccountObjectClass()); + assertNotNull("No definition for object class "+getAccountObjectClass(), accountObjectClassDefinition); + display("Account object class def", accountObjectClassDefinition); + + ResourceAttributeDefinition cnDef = accountObjectClassDefinition.findAttributeDefinition("cn"); + PrismAsserts.assertDefinition(cnDef, new QName(MidPointConstants.NS_RI, "cn"), DOMUtil.XSD_STRING, 1, -1); + assertTrue("createTimestampDef read", cnDef.canRead()); + assertTrue("createTimestampDef read", cnDef.canModify()); + assertTrue("createTimestampDef read", cnDef.canAdd()); + + ResourceAttributeDefinition createTimestampDef = accountObjectClassDefinition.findAttributeDefinition("createTimestamp"); + PrismAsserts.assertDefinition(createTimestampDef, new QName(MidPointConstants.NS_RI, "createTimestamp"), + DOMUtil.XSD_LONG, 0, 1); + assertTrue("createTimestampDef read", createTimestampDef.canRead()); + assertFalse("createTimestampDef read", createTimestampDef.canModify()); + assertFalse("createTimestampDef read", createTimestampDef.canAdd()); + + } + + protected ObjectFilter createAttributeFilter(String attrName, T attrVal) throws SchemaException { + ResourceAttributeDefinition ldapUidAttrDef = accountObjectClassDefinition.findAttributeDefinition(attrName); + return EqualFilter.createEqual( + new ItemPath(ShadowType.F_ATTRIBUTES, ldapUidAttrDef.getName()), ldapUidAttrDef, attrVal); + } + + protected ObjectQuery createUidQuery(String uid) throws SchemaException { + ObjectQuery query = ObjectQueryUtil.createResourceAndObjectClassQuery(getResourceOid(), getAccountObjectClass(), prismContext); + ObjectQueryUtil.filterAnd(query.getFilter(), createAttributeFilter("uid", uid)); + return query; + } + + protected SearchResultList> doSearch(final String TEST_NAME, ObjectQuery query, int expectedSize, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { + return doSearch(TEST_NAME, query, null, expectedSize, task, result); + } + + protected SearchResultList> doSearch(final String TEST_NAME, ObjectQuery query, GetOperationOptions rootOptions, int expectedSize, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { + final List> foundObjects = new ArrayList>(expectedSize); + ResultHandler handler = new ResultHandler() { + @Override + public boolean handle(PrismObject object, OperationResult parentResult) { +// LOGGER.trace("Found {}", object); + String name = object.asObjectable().getName().getOrig(); + for(PrismObject foundShadow: foundObjects) { + if (foundShadow.asObjectable().getName().getOrig().equals(name)) { + AssertJUnit.fail("Duplicate name "+name); + } + } + foundObjects.add(object); + return true; + } + }; + + Collection> options = null; + if (rootOptions != null) { + options = SelectorOptions.createCollection(rootOptions); + } + + rememberConnectorOperationCount(); + rememberConnectorSimulatedPagingSearchCount(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + SearchResultMetadata searchResultMetadata = modelService.searchObjectsIterative(ShadowType.class, query, handler, options, task, result); + + // THEN + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertEquals("Unexpected number of accounts", expectedSize, foundObjects.size()); + + SearchResultList> resultList = new SearchResultList<>(foundObjects, searchResultMetadata); + + return resultList; + } + + protected Entry getLdapAccountByUid(String uid) throws LdapException, IOException, CursorException { + LdapNetworkConnection connection = ldapConnect(); + List entries = ldapSearch(connection, "(uid="+uid+")"); + ldapDisconnect(connection); + + assertEquals("Unexpected number of entries for uid="+uid+": "+entries, 1, entries.size()); + Entry entry = entries.get(0); + + return entry; + } + + protected Entry assertLdapAccount(String uid, String cn) throws LdapException, IOException, CursorException { + Entry entry = getLdapAccountByUid(uid); + assertAttribute(entry, "cn", cn); + return entry; + } + + protected void assertAttribute(Entry entry, String attrName, String expectedValue) throws LdapInvalidAttributeValueException { + String dn = entry.getDn().toString(); + Attribute ldapAttribute = entry.get(attrName); + if (ldapAttribute == null) { + if (expectedValue == null) { + return; + } else { + AssertJUnit.fail("No attribute "+attrName+" in "+dn+", expected: "+expectedValue); + } + } else { + assertEquals("Wrong attribute "+attrName+" in "+dn, expectedValue, ldapAttribute.getString()); + } + } + + protected void assertNoLdapAccount(String uid) throws LdapException, IOException, CursorException { + LdapNetworkConnection connection = ldapConnect(); + List entries = ldapSearch(connection, "(uid="+uid+")"); + ldapDisconnect(connection); + + assertEquals("Unexpected number of entries for uid="+uid+": "+entries, 0, entries.size()); + } + + protected List ldapSearch(LdapNetworkConnection connection, String filter) throws LdapException, CursorException { + return ldapSearch(connection, getLdapSuffix(), filter, SearchScope.SUBTREE, "*", getPrimaryIdentifierAttributeName()); + } + + protected List ldapSearch(LdapNetworkConnection connection, String baseDn, String filter, SearchScope scope, String... attributes) throws LdapException, CursorException { + List entries = new ArrayList(); + EntryCursor entryCursor = connection.search( baseDn, filter, scope, attributes ); + Entry entry = null; + while (entryCursor.next()) { + entries.add(entryCursor.get()); + } + return entries; + } + + protected void assertLdapPassword(String uid, String password) throws LdapException, IOException, CursorException { + Entry entry = getLdapAccountByUid(uid); + LdapNetworkConnection conn = ldapConnect(entry.getDn().toString(), password); + assertTrue("Not connected", conn.isConnected()); + assertTrue("Not authenticated", conn.isAuthenticated()); + } + + protected Entry addLdapAccount(String uid, String cn, String givenName, String sn) throws LdapException, IOException, CursorException { + LdapNetworkConnection connection = ldapConnect(); + Entry entry = createAccountEntry(uid, cn, givenName, sn); + connection.add(entry); + display("Added LDAP account:"+entry); + ldapDisconnect(connection); + return entry; + } + + protected Entry createAccountEntry(String uid, String cn, String givenName, String sn) throws LdapException { + Entry entry = new DefaultEntry(toDn(uid), + "objectclass", LDAP_ACCOUNT_OBJECTCLASS, + "uid", uid, + "cn", cn, + "givenName", givenName, + "sn", sn); + return entry; + } + + protected Entry addLdapGroup(String cn, String description, String memberDn) throws LdapException, IOException, CursorException { + LdapNetworkConnection connection = ldapConnect(); + Entry entry = createGroupEntry(cn, description, memberDn); + connection.add(entry); + display("Added LDAP group:"+entry); + ldapDisconnect(connection); + return entry; + } + + protected Entry createGroupEntry(String cn, String description, String memberDn) throws LdapException { + Entry entry = new DefaultEntry(toGroupDn(cn), + "objectclass", getLdapGroupObjectClass(), + "cn", cn, + "description", description, + getLdapGroupMemberAttribute(), memberDn); + return entry; + } + + protected void deleteLdapEntry(String dn) throws LdapException, IOException { + LdapNetworkConnection connection = ldapConnect(); + connection.delete(dn); + display("Deleted LDAP entry: "+dn); + ldapDisconnect(connection); + } + + protected String toDn(String username) { + return "uid="+username+","+getPeopleLdapSuffix(); + } + + protected String toGroupDn(String cn) { + return "cn="+cn+","+getGroupsLdapSuffix(); + } + + protected LdapNetworkConnection ldapConnect() throws LdapException { + return ldapConnect(getLdapBindDn(), getLdapBindPassword()); + } + + protected LdapNetworkConnection ldapConnect(String bindDn, String bindPassword) throws LdapException { + LdapConnectionConfig config = new LdapConnectionConfig(); + config.setLdapHost(getLdapServerHost()); + config.setLdapPort(getLdapServerPort()); + + if (useSsl()) { + config.setUseSsl(true); + TrustManager trustManager = new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + + } + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + }; + config.setTrustManagers(trustManager); + } + + LdapNetworkConnection connection = new LdapNetworkConnection(config); + boolean connected = connection.connect(); + if (!connected) { + AssertJUnit.fail("Cannot connect to LDAP server "+getLdapServerHost()+":"+getLdapServerPort()); + } + BindRequest bindRequest = new BindRequestImpl(); + bindRequest.setDn(new Dn(bindDn)); + bindRequest.setCredentials(bindPassword); + BindResponse bindResponse = connection.bind(bindRequest); + return connection; + } + + protected void ldapDisconnect(LdapNetworkConnection connection) throws IOException { + connection.close(); + } + + protected void assertAccountShadow(PrismObject shadow, String dn) throws SchemaException { + assertShadowCommon(shadow, null, dn, resourceType, getAccountObjectClass(), ciMatchingRule); + } + + protected long roundTsDown(long ts) { + return (((long)(ts/1000))*1000); + } + + protected long roundTsUp(long ts) { + return (((long)(ts/1000))*1000)+1; + } +} diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestEDirAthena.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestEDirAthena.java new file mode 100644 index 00000000000..d77099a4ee1 --- /dev/null +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/TestEDirAthena.java @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2015 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.testing.conntest; + +import java.io.File; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.Listeners; + +import com.evolveum.midpoint.test.util.MidPointTestConstants; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; + +/** + * @author semancik + * + */ +public class TestEDirAthena extends AbstractEDirTest { + + @Override + protected String getResourceOid() { + return "0893372c-3c42-11e5-9179-001e8c717e5b"; + } + + @Override + protected File getResourceFile() { + return new File(getBaseDir(), "resource-athena.xml"); + } + + @Override + protected String getLdapServerHost() { + return "athena.evolveum.com"; + } + + @Override + protected int getLdapServerPort() { + return 33636; + } + +} diff --git a/testing/conntest/src/test/resources/edir/resource-athena.xml b/testing/conntest/src/test/resources/edir/resource-athena.xml new file mode 100644 index 00000000000..554c8766448 --- /dev/null +++ b/testing/conntest/src/test/resources/edir/resource-athena.xml @@ -0,0 +1,251 @@ + + + + + + + + eDirectory deimos/athena + + Novell/NetIQ eDirectory + + + + + c:connectorType + com.evolveum.polygon.connector.ldap.edirectory.EDirectoryLdapConnector + + + + + + + 33636 + athena.evolveum.com + ssl + o=example + cn=admin,o=example + + secret + + createTimestamp + + + + false + false + false + + + + + + + account + Default Account + true + ri:inetOrgPerson + + dn + Distinguished Name + + 0 + + mr:distinguishedName + + + $user/name + + + + + + + + ri:cn + + 0 + + + + fullName + + + + + ri:sn + + 0 + + + + familyName + + + + + ri:givenName + + + givenName + + + + + ri:uid + mr:stringIgnoreCase + + weak + + name + + + + + + ri:mail + + + emailAddress + + + + + ri:telephoneNumber + + + telephoneNumber + + + + + + ri:group + LDAP Group Membership + entitlement + ldapGroup + objectToSubject + ri:member + ri:dn + + + + + + attributes/dn + + cn=admin,o=example + + + + + + + + + + + weak + + + + + + + + + + + + + + + + + + + + + entitlement + ldapGroup + LDAP Group + ri:groupOfNames + + dn + mr:distinguishedName + + + $focus/name + + + + + + + + ri:cn + mr:stringIgnoreCase + + weak + + $focus/name + + + + + ri:description + + + description + + + + + + + + + + diff --git a/testing/conntest/src/test/resources/truststore.jks b/testing/conntest/src/test/resources/truststore.jks new file mode 100644 index 0000000000000000000000000000000000000000..4d49dba311848569d22be797d3e87d9e4806a4fc GIT binary patch literal 1390 zcmezO_TO6u1_mY|W(3nLsVSL7K#sq{hq-(VtPy&q29^vAtcC_nthxqGETRjTnHZUv zRG4H0|1bMnQ+#m~vq`C*;=M|bBP|+%43EnSjkynNGch@Fm##P9W#iOp^Jx3d%gD&e z%3xq@C}kkQ#vIDREiC9?l%ANES(R9lnV*-Kqu}glC~6=KlH(HQagA{F4e)W*4GD5} zHINhMH8e3WGcYwYG%_0SRRbcW-U1za5)XDrTX)5)*@!F}(>7pCqH zOBex;LVv`&((`=W|(YZlfKRRO`vkSaED64?Se1czgFyVI#iODlW}DY$Mvaa z=Y1$U|1JDt56>FOsQE%C?Nz12XKX&VGFQT<;?nXLf8IPfoD=*Z;%8XB*8#hG~-8i2V72ADbFTmuOM z0iXgVj{5%)0JNBih3&(A58N^fQB8J$84IL=Cd0Vc^@DOJZka`X20kEH1Kj|0I38CE zVY=D?n;2?N2j(kA2G&12gH(NfDYxpK?O3m_5hHzMM^|YR`#*+>#^2U`Ufk*TBE_gX zsOd~f^0(O%Yze>W=6p^wca9dR+ob=iLzVY4zHv zGj9BjUNU#;=eXcc6ZF_uuU8^0+Sye5=it^|{Z|_;au6@b}*m98rtvMeo_a)YE>n#^|<; z<{9 literal 0 HcmV?d00001 diff --git a/testing/conntest/testng.xml b/testing/conntest/testng.xml index bb263414835..cb1e58670f0 100644 --- a/testing/conntest/testng.xml +++ b/testing/conntest/testng.xml @@ -1,6 +1,6 @@ + + + diff --git a/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/AlphabeticalMethodInterceptor.java b/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/AlphabeticalMethodInterceptor.java index 89bd38eb49f..635094cebba 100644 --- a/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/AlphabeticalMethodInterceptor.java +++ b/tools/test-ng/src/main/java/com/evolveum/midpoint/tools/testng/AlphabeticalMethodInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Evolveum + * Copyright (c) 2014-2015 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,6 +58,8 @@ public int compare(IMethodInstance o1, IMethodInstance o2) { Arrays.sort(array, comparator); result.addAll(Arrays.asList(array)); } + + System.out.println("AlphabeticalMethodInterceptor: "+result); return result; }