/*
* Copyright (c) 2010-2017 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.provisioning.ucf.impl.connid;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.crypto.Protector;
import com.evolveum.midpoint.prism.delta.PropertyDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.schema.PrismSchema;
import com.evolveum.midpoint.prism.util.PrismAsserts;
import com.evolveum.midpoint.prism.util.PrismTestUtil;
import com.evolveum.midpoint.prism.xnode.MapXNode;
import com.evolveum.midpoint.provisioning.ucf.api.*;
import com.evolveum.midpoint.schema.CapabilityUtil;
import com.evolveum.midpoint.schema.DeltaConvertor;
import com.evolveum.midpoint.schema.MidPointPrismContextFactory;
import com.evolveum.midpoint.schema.constants.MidPointConstants;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.processor.*;
import com.evolveum.midpoint.schema.result.AsynchronousOperationReturnValue;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ShadowUtil;
import com.evolveum.midpoint.schema.util.SchemaDebugUtil;
import com.evolveum.midpoint.schema.util.ResourceTypeUtil;
import com.evolveum.midpoint.test.IntegrationTestTools;
import com.evolveum.midpoint.test.ldap.OpenDJController;
import com.evolveum.midpoint.test.util.TestUtil;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.PrettyPrinter;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType;
import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.PagedSearchCapabilityType;
import com.evolveum.prism.xml.ns._public.types_3.ItemDeltaType;
import com.evolveum.prism.xml.ns._public.types_3.ItemPathType;
import com.evolveum.prism.xml.ns._public.types_3.ModificationTypeType;
import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;
import com.evolveum.prism.xml.ns._public.types_3.RawType;
import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.Uid;
import org.opends.server.types.Entry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.AssertJUnit;
import org.testng.annotations.*;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import javax.xml.namespace.QName;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.evolveum.midpoint.test.IntegrationTestTools.*;
import static org.testng.AssertJUnit.*;
/**
* Test UCF implementation with OpenDJ and ICF LDAP connector.
* <p/>
* This test is using embedded OpenDJ as a resource and ICF LDAP connector. The
* test is executed by direct calls to the UCF interface.
*
* @author Radovan Semancik
* @author Katka Valalikova
* <p/>
* This is an UCF test. It shold not need repository or other things
* from the midPoint spring context except from the provisioning beans.
* But due to a general issue with spring context initialization this is
* a lesser evil for now (MID-392)
*/
@ContextConfiguration(locations = { "classpath:ctx-ucf-connid-test.xml" })
public class TestUcfOpenDj extends AbstractTestNGSpringContextTests {
private static final File RESOURCE_OPENDJ_FILE = new File(UcfTestUtil.TEST_DIR, "resource-opendj.xml");
private static final File RESOURCE_OPENDJ_BAD_FILE = new File(UcfTestUtil.TEST_DIR, "resource-opendj-bad.xml");
private static final File CONNECTOR_LDAP_FILE = new File(UcfTestUtil.TEST_DIR, "connector-ldap.xml");
private ResourceType resourceType;
private ResourceType badResourceType;
private ConnectorType connectorType;
private ConnectorFactory factory;
private ConnectorInstance cc;
private PrismSchema connectorSchema;
private ResourceSchema resourceSchema;
private static Trace LOGGER = TraceManager.getTrace(TestUcfOpenDj.class);
@Autowired(required = true)
ConnectorFactory connectorFactoryIcfImpl;
@Autowired(required = true)
Protector protector;
@Autowired(required = true)
PrismContext prismContext;
protected static OpenDJController openDJController = new OpenDJController();
public TestUcfOpenDj() {
System.setProperty("midpoint.home", "target/midPointHome/");
}
@BeforeSuite
public void setup() throws SchemaException, SAXException, IOException {
PrettyPrinter.setDefaultNamespacePrefix(MidPointConstants.NS_MIDPOINT_PUBLIC_PREFIX);
PrismTestUtil.resetPrismContext(MidPointPrismContextFactory.FACTORY);
}
@BeforeClass
public static void startLdap() throws Exception {
LOGGER.info("------------------------------------------------------------------------------");
LOGGER.info("START: OpenDjUcfTest");
LOGGER.info("------------------------------------------------------------------------------");
openDJController.startCleanServer();
}
@AfterClass
public static void stopLdap() throws Exception {
openDJController.stop();
LOGGER.info("------------------------------------------------------------------------------");
LOGGER.info("STOP: OpenDjUcfTest");
LOGGER.info("------------------------------------------------------------------------------");
}
@BeforeMethod
public void initUcf() throws Exception {
TestUtil.displayTestTile("initUcf");
// Resource
PrismObject<ResourceType> resource = PrismTestUtil.parseObject(RESOURCE_OPENDJ_FILE);
resourceType = resource.asObjectable();
// Resource: Second copy for negative test cases
PrismObject<ResourceType> badResource = PrismTestUtil.parseObject(RESOURCE_OPENDJ_BAD_FILE);
badResourceType = badResource.asObjectable();
// Connector
PrismObject<ConnectorType> connector = PrismTestUtil.parseObject(CONNECTOR_LDAP_FILE);
connectorType = connector.asObjectable();
factory = connectorFactoryIcfImpl;
connectorSchema = factory.generateConnectorConfigurationSchema(connectorType);
AssertJUnit.assertNotNull("Cannot generate connector schema", connectorSchema);
display("Connector schema", connectorSchema);
cc = factory.createConnectorInstance(connectorType, ResourceTypeUtil.getResourceNamespace(resourceType), "ldap connector");
OperationResult result = new OperationResult("initUcf");
cc.configure(resourceType.getConnectorConfiguration().asPrismContainerValue(), result);
cc.initialize(null, null, false, result);
// TODO: assert something
resourceSchema = cc.fetchResourceSchema(null, result);
display("Resource schema", resourceSchema);
AssertJUnit.assertNotNull(resourceSchema);
}
@AfterMethod
public void shutdownUcf() throws Exception {
}
@Test
public void test010ConnectorSchemaSanity() throws Exception {
final String TEST_NAME = "test010ConnectorSchemaSanity";
TestUtil.displayTestTile(TEST_NAME);
IntegrationTestTools.assertConnectorSchemaSanity(connectorSchema, "LDAP connector", true);
PrismContainerDefinition configurationDefinition =
connectorSchema.findItemDefinition(ResourceType.F_CONNECTOR_CONFIGURATION.getLocalPart(), PrismContainerDefinition.class);
PrismContainerDefinition configurationPropertiesDefinition =
configurationDefinition.findContainerDefinition(SchemaConstants.CONNECTOR_SCHEMA_CONFIGURATION_PROPERTIES_ELEMENT_QNAME);
PrismPropertyDefinition<String> propHost = configurationPropertiesDefinition.findPropertyDefinition(new QName(UcfTestUtil.CONNECTOR_LDAP_NS,"host"));
assertNotNull("No definition for configuration property 'host' in connector schema", propHost);
PrismAsserts.assertDefinition(propHost, new QName(UcfTestUtil.CONNECTOR_LDAP_NS,"host"), DOMUtil.XSD_STRING, 1, 1);
assertEquals("Wrong property 'host' display name", "Host", propHost.getDisplayName());
assertEquals("Wrong property 'host' help", "The name or IP address of the LDAP server host.", propHost.getHelp());
assertEquals("Wrong property 'host' display order", (Integer)1, propHost.getDisplayOrder()); // MID-2642
PrismPropertyDefinition<String> propPort = configurationPropertiesDefinition.findPropertyDefinition(new QName(UcfTestUtil.CONNECTOR_LDAP_NS,"port"));
assertNotNull("No definition for configuration property 'port' in connector schema", propPort);
PrismAsserts.assertDefinition(propPort, new QName(UcfTestUtil.CONNECTOR_LDAP_NS,"port"), DOMUtil.XSD_INT, 0, 1);
assertEquals("Wrong property 'port' display name", "Port number", propPort.getDisplayName());
assertEquals("Wrong property 'port' help", "LDAP server port number.", propPort.getHelp());
assertEquals("Wrong property 'port' display order", (Integer)2, propPort.getDisplayOrder()); // MID-2642
}
@Test
public void test020ResourceSchemaSanity() throws Exception {
final String TEST_NAME = "test020ResourceSchemaSanity";
TestUtil.displayTestTile(TEST_NAME);
QName objectClassQname = new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.OBJECT_CLASS_INETORGPERSON_NAME);
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findObjectClassDefinition(objectClassQname);
assertNotNull("No object class definition " + objectClassQname, accountDefinition);
// assertEquals("Object class " + objectClassQname + " is not account", ShadowKindType.ACCOUNT, accountDefinition.getKind());
// assertTrue("Object class " + objectClassQname + " is not default account", accountDefinition.isDefaultInAKind());
assertFalse("Object class " + objectClassQname + " is empty", accountDefinition.isEmpty());
assertFalse("Object class " + objectClassQname + " is empty", accountDefinition.isIgnored());
Collection<? extends ResourceAttributeDefinition> identifiers = accountDefinition.getPrimaryIdentifiers();
assertNotNull("Null identifiers for " + objectClassQname, identifiers);
assertFalse("Empty identifiers for " + objectClassQname, identifiers.isEmpty());
ResourceAttributeDefinition<String> idPrimaryDef = accountDefinition.findAttributeDefinition(
new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.RESOURCE_OPENDJ_PRIMARY_IDENTIFIER_LOCAL_NAME));
assertNotNull("No definition for attribute "+OpenDJController.RESOURCE_OPENDJ_PRIMARY_IDENTIFIER_LOCAL_NAME, idPrimaryDef);
assertTrue("Attribute "+OpenDJController.RESOURCE_OPENDJ_PRIMARY_IDENTIFIER_LOCAL_NAME+" in not an identifier",idPrimaryDef.isIdentifier(accountDefinition));
assertTrue("Attribute "+OpenDJController.RESOURCE_OPENDJ_PRIMARY_IDENTIFIER_LOCAL_NAME+" in not in identifiers list",identifiers.contains(idPrimaryDef));
assertEquals("Attribute "+OpenDJController.RESOURCE_OPENDJ_PRIMARY_IDENTIFIER_LOCAL_NAME+" has wrong native name", OpenDJController.RESOURCE_OPENDJ_PRIMARY_IDENTIFIER_LOCAL_NAME, idPrimaryDef.getNativeAttributeName());
assertEquals("Attribute "+OpenDJController.RESOURCE_OPENDJ_PRIMARY_IDENTIFIER_LOCAL_NAME+" has wrong framework name", Uid.NAME, idPrimaryDef.getFrameworkAttributeName());
ResourceAttributeDefinition<String> idSecondaryDef = accountDefinition.findAttributeDefinition(
new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.RESOURCE_OPENDJ_SECONDARY_IDENTIFIER_LOCAL_NAME));
assertNotNull("No definition for attribute "+SchemaConstants.ICFS_NAME, idSecondaryDef);
assertTrue("Attribute "+OpenDJController.RESOURCE_OPENDJ_SECONDARY_IDENTIFIER_LOCAL_NAME+" in not secondary identifier",idSecondaryDef.isSecondaryIdentifier(accountDefinition));
assertFalse("Attribute "+OpenDJController.RESOURCE_OPENDJ_SECONDARY_IDENTIFIER_LOCAL_NAME+" in in identifiers list and it should NOT be",identifiers.contains(idSecondaryDef));
assertTrue("Attribute "+OpenDJController.RESOURCE_OPENDJ_SECONDARY_IDENTIFIER_LOCAL_NAME+" in not in secomdary identifiers list",accountDefinition.getSecondaryIdentifiers().contains(idSecondaryDef));
assertEquals("Attribute "+OpenDJController.RESOURCE_OPENDJ_SECONDARY_IDENTIFIER_LOCAL_NAME+" has wrong native name", OpenDJController.RESOURCE_OPENDJ_SECONDARY_IDENTIFIER_LOCAL_NAME, idSecondaryDef.getNativeAttributeName());
assertEquals("Attribute "+OpenDJController.RESOURCE_OPENDJ_SECONDARY_IDENTIFIER_LOCAL_NAME+" has wrong framework name", Name.NAME, idSecondaryDef.getFrameworkAttributeName());
assertEquals("Unexpected identifiers: "+identifiers, 1, identifiers.size());
assertEquals("Unexpected secondary identifiers: "+accountDefinition.getSecondaryIdentifiers(), 1, accountDefinition.getSecondaryIdentifiers().size());
}
private Collection<ResourceAttribute<?>> addSampleResourceObject(String name, String givenName, String familyName)
throws CommunicationException, GenericFrameworkException, SchemaException,
ObjectAlreadyExistsException, ConfigurationException {
OperationResult result = new OperationResult(this.getClass().getName() + ".testAdd");
QName objectClassQname = new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.OBJECT_CLASS_INETORGPERSON_NAME);
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findObjectClassDefinition(objectClassQname);
assertNotNull("No object class definition "+objectClassQname, accountDefinition);
ResourceAttributeContainer resourceObject = accountDefinition.instantiate(ShadowType.F_ATTRIBUTES);
ResourceAttributeDefinition<String> attributeDefinition = accountDefinition
.findAttributeDefinition(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.RESOURCE_OPENDJ_SECONDARY_IDENTIFIER_LOCAL_NAME));
ResourceAttribute<String> attribute = attributeDefinition.instantiate();
attribute.setValue(new PrismPropertyValue<String>("uid=" + name + ",ou=people,dc=example,dc=com"));
resourceObject.add(attribute);
attributeDefinition = accountDefinition
.findAttributeDefinition(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "sn"));
attribute = attributeDefinition.instantiate();
attribute.setValue(new PrismPropertyValue(familyName));
resourceObject.add(attribute);
attributeDefinition = accountDefinition
.findAttributeDefinition(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "cn"));
attribute = attributeDefinition.instantiate();
attribute.setValue(new PrismPropertyValue(givenName + " " + familyName));
resourceObject.add(attribute);
attributeDefinition = accountDefinition.findAttributeDefinition(new QName(ResourceTypeUtil.getResourceNamespace(resourceType),
"givenName"));
attribute = attributeDefinition.instantiate();
attribute.setValue(new PrismPropertyValue(givenName));
resourceObject.add(attribute);
PrismObject<ShadowType> shadow = wrapInShadow(ShadowType.class, resourceObject);
Set<Operation> operation = new HashSet<Operation>();
AsynchronousOperationReturnValue<Collection<ResourceAttribute<?>>> ret = cc.addObject(shadow, operation, null, result);
Collection<ResourceAttribute<?>> resourceAttributes = ret.getReturnValue();
return resourceAttributes;
}
private String getEntryUuid(Collection<ResourceAttribute<?>> identifiers) {
for (ResourceAttribute<?> identifier : identifiers) {
if (identifier.getElementName().equals(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.RESOURCE_OPENDJ_PRIMARY_IDENTIFIER_LOCAL_NAME))) {
return identifier.getValue(String.class).getValue();
}
}
return null;
}
@Test
public void test100AddDeleteObject() throws Exception {
final String TEST_NAME = "test100AddDeleteObject";
TestUtil.displayTestTile(this, TEST_NAME);
OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
Collection<ResourceAttribute<?>> identifiers = addSampleResourceObject("john", "John", "Smith");
String uid = null;
for (ResourceAttribute<?> resourceAttribute : identifiers) {
if (SchemaConstants.ICFS_UID.equals(resourceAttribute.getElementName())) {
uid = resourceAttribute.getValue(String.class).getValue();
System.out.println("uuuuid:" + uid);
assertNotNull(uid);
}
}
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findObjectClassDefinition(OpenDJController.OBJECT_CLASS_INETORGPERSON_NAME);
cc.deleteObject(accountDefinition, null, identifiers, null, result);
ResourceObjectIdentification identification = ResourceObjectIdentification.createFromAttributes(
accountDefinition, identifiers);
PrismObject<ShadowType> resObj = null;
try {
resObj = cc.fetchObject(ShadowType.class, identification, null, null,
result);
Assert.fail();
} catch (ObjectNotFoundException ex) {
AssertJUnit.assertNull(resObj);
}
}
@Test
public void test110ChangeModifyObject() throws Exception {
final String TEST_NAME = "test110ChangeModifyObject";
TestUtil.displayTestTile(this, TEST_NAME);
OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
Collection<ResourceAttribute<?>> identifiers = addSampleResourceObject("john", "John", "Smith");
Set<Operation> changes = new HashSet<Operation>();
changes.add(createAddAttributeChange("employeeNumber", "123123123"));
changes.add(createReplaceAttributeChange("sn", "Smith007"));
changes.add(createAddAttributeChange("street", "Wall Street"));
changes.add(createDeleteAttributeChange("givenName", "John"));
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findObjectClassDefinition(OpenDJController.OBJECT_CLASS_INETORGPERSON_NAME);
cc.modifyObject(accountDefinition, identifiers, changes, null, result);
ResourceObjectIdentification identification = ResourceObjectIdentification.createFromAttributes(
accountDefinition, identifiers);
PrismObject<ShadowType> shadow = cc.fetchObject(ShadowType.class, identification, null, null, result);
ResourceAttributeContainer resObj = ShadowUtil.getAttributesContainer(shadow);
AssertJUnit.assertNull(resObj.findAttribute(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "givenName")));
String addedEmployeeNumber = resObj
.findAttribute(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "employeeNumber")).getValue(String.class)
.getValue();
String changedSn = resObj.findAttribute(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "sn"))
.getValues(String.class).iterator().next().getValue();
String addedStreet = resObj.findAttribute(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "street"))
.getValues(String.class).iterator().next().getValue();
System.out.println("changed employee number: " + addedEmployeeNumber);
System.out.println("changed sn: " + changedSn);
System.out.println("added street: " + addedStreet);
AssertJUnit.assertEquals("123123123", addedEmployeeNumber);
AssertJUnit.assertEquals("Smith007", changedSn);
AssertJUnit.assertEquals("Wall Street", addedStreet);
}
@Test
public void test200FetchChanges() throws Exception {
final String TEST_NAME = "test200FetchChanges";
TestUtil.displayTestTile(this, TEST_NAME);
OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findObjectClassDefinition(OpenDJController.OBJECT_CLASS_INETORGPERSON_NAME);
PrismProperty<Integer> lastToken = cc.fetchCurrentToken(accountDefinition, null, result);
System.out.println("Property:");
System.out.println(SchemaDebugUtil.prettyPrint(lastToken));
System.out.println("token " + lastToken.toString());
assertNotNull("No last token", lastToken);
assertNotNull("No last token value", lastToken.getRealValue());
List<Change> changes = cc.fetchChanges(accountDefinition, lastToken, null, null, result);
display("Changes", changes);
// Just one pseudo-change that updates the token
AssertJUnit.assertEquals(1, changes.size());
Change change = changes.get(0);
assertNull(change.getCurrentShadow());
assertNull(change.getIdentifiers());
assertNull(change.getObjectDelta());
assertNotNull(change.getToken());
}
private PrismProperty createProperty(String propertyName, String propertyValue) {
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findObjectClassDefinition(
new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.OBJECT_CLASS_INETORGPERSON_NAME));
ResourceAttributeDefinition propertyDef = accountDefinition.findAttributeDefinition(new QName(
ResourceTypeUtil.getResourceNamespace(resourceType), propertyName));
ResourceAttribute property = propertyDef.instantiate();
property.setValue(new PrismPropertyValue(propertyValue));
return property;
}
private PropertyModificationOperation createReplaceAttributeChange(String propertyName, String propertyValue) {
PrismProperty property = createProperty(propertyName, propertyValue);
ItemPath propertyPath = new ItemPath(ShadowType.F_ATTRIBUTES,
new QName(ResourceTypeUtil.getResourceNamespace(resourceType), propertyName));
PropertyDelta delta = new PropertyDelta(propertyPath, property.getDefinition(), prismContext);
delta.setValueToReplace(new PrismPropertyValue(propertyValue));
PropertyModificationOperation attributeModification = new PropertyModificationOperation(delta);
return attributeModification;
}
private PropertyModificationOperation createAddAttributeChange(String propertyName, String propertyValue) {
PrismProperty property = createProperty(propertyName, propertyValue);
ItemPath propertyPath = new ItemPath(ShadowType.F_ATTRIBUTES,
new QName(ResourceTypeUtil.getResourceNamespace(resourceType), propertyName));
PropertyDelta delta = new PropertyDelta(propertyPath, property.getDefinition(), prismContext);
delta.addValueToAdd(new PrismPropertyValue(propertyValue));
PropertyModificationOperation attributeModification = new PropertyModificationOperation(delta);
return attributeModification;
}
private PropertyModificationOperation createDeleteAttributeChange(String propertyName, String propertyValue) {
PrismProperty property = createProperty(propertyName, propertyValue);
ItemPath propertyPath = new ItemPath(ShadowType.F_ATTRIBUTES,
new QName(ResourceTypeUtil.getResourceNamespace(resourceType), propertyName));
PropertyDelta delta = new PropertyDelta(propertyPath, property.getDefinition(), prismContext);
delta.addValueToDelete(new PrismPropertyValue(propertyValue));
PropertyModificationOperation attributeModification = new PropertyModificationOperation(delta);
return attributeModification;
}
private PropertyModificationOperation createActivationChange(ActivationStatusType status) {
PrismObjectDefinition<ShadowType> shadowDefinition = getShadowDefinition(ShadowType.class);
PropertyDelta<ActivationStatusType> delta = PropertyDelta.createDelta(
new ItemPath(ShadowType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS),
shadowDefinition);
delta.setValueToReplace(new PrismPropertyValue<ActivationStatusType>(status));
return new PropertyModificationOperation(delta);
}
/**
* Simple call to connector test() method.
*
* @throws Exception
*/
@Test
public void test300TestConnection() throws Exception {
final String TEST_NAME = "test300TestConnection";
TestUtil.displayTestTile(this, TEST_NAME);
// GIVEN
OperationResult result = new OperationResult(TEST_NAME);
// WHEN
cc.test(result);
// THEN
result.computeStatus("test failed");
AssertJUnit.assertNotNull(result);
OperationResult connectorConnectionResult = result.getSubresults().get(0);
AssertJUnit.assertNotNull(connectorConnectionResult);
System.out.println("Test \"connector connection\" result: " + connectorConnectionResult);
AssertJUnit.assertTrue(connectorConnectionResult.isSuccess());
AssertJUnit.assertTrue(result.isSuccess());
}
/**
* Simple call to connector test() method.
*
* @throws Exception
*/
@Test
public void test310TestConnectionNegative() throws Exception {
final String TEST_NAME = "test310TestConnectionNegative";
TestUtil.displayTestTile(this, TEST_NAME);
// GIVEN
OperationResult result = new OperationResult(TEST_NAME);
ConnectorInstance badConnector = factory.createConnectorInstance(connectorType,
ResourceTypeUtil.getResourceNamespace(badResourceType), "test connector");
badConnector.configure(badResourceType.getConnectorConfiguration().asPrismContainerValue(), result);
// WHEN
badConnector.test(result);
// THEN
result.computeStatus("test failed");
display("Test result (FAILURE EXPECTED)", result);
AssertJUnit.assertNotNull(result);
OperationResult connectorConnectionResult = result.getSubresults().get(1);
AssertJUnit.assertNotNull(connectorConnectionResult);
System.out.println("Test \"connector connection\" result: " + connectorConnectionResult
+ " (FAILURE EXPECTED)");
AssertJUnit.assertTrue("Unexpected success of bad connector test",
!connectorConnectionResult.isSuccess());
AssertJUnit.assertTrue(!result.isSuccess());
}
/**
* Test fetching and translating resource schema.
*
* @throws Exception
*/
@Test
public void test400FetchResourceSchema() throws Exception {
final String TEST_NAME = "test400FetchResourceSchema";
TestUtil.displayTestTile(this, TEST_NAME);
// GIVEN
// WHEN
// The schema was fetched during test init. Now just check if it was OK.
// THEN
AssertJUnit.assertNotNull(resourceSchema);
System.out.println(resourceSchema.debugDump());
Document xsdSchema = resourceSchema.serializeToXsd();
System.out
.println("-------------------------------------------------------------------------------------");
System.out.println(DOMUtil.printDom(xsdSchema));
System.out
.println("-------------------------------------------------------------------------------------");
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema
.findObjectClassDefinition(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.OBJECT_CLASS_INETORGPERSON_NAME));
AssertJUnit.assertNotNull(accountDefinition);
AssertJUnit.assertFalse("No identifiers for account object class ", accountDefinition
.getPrimaryIdentifiers().isEmpty());
PrismPropertyDefinition uidDefinition = accountDefinition.findAttributeDefinition(
new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.RESOURCE_OPENDJ_PRIMARY_IDENTIFIER_LOCAL_NAME));
AssertJUnit.assertNotNull(uidDefinition);
for (Definition def : resourceSchema.getDefinitions()) {
if (def instanceof ResourceAttributeContainerDefinition) {
ResourceAttributeContainerDefinition rdef = (ResourceAttributeContainerDefinition) def;
assertNotEmpty("No type name in object class", rdef.getTypeName());
assertNotEmpty("No native object class for " + rdef.getTypeName(),
rdef.getNativeObjectClass());
// This is maybe not that important, but just for a sake of
// completeness
assertNotEmpty("No name for " + rdef.getTypeName(), rdef.getName());
}
}
}
@Test
public void test410Capabilities() throws Exception {
final String TEST_NAME = "test410Capabilities";
TestUtil.displayTestTile(this, TEST_NAME);
// GIVEN
OperationResult result = new OperationResult(TEST_NAME);
// WHEN
Collection<Object> capabilities = cc.fetchCapabilities(result);
// THEN
result.computeStatus("getCapabilities failed");
TestUtil.assertSuccess("getCapabilities failed (result)", result);
assertFalse("Empty capabilities returned", capabilities.isEmpty());
CredentialsCapabilityType capCred = CapabilityUtil.getCapability(capabilities,
CredentialsCapabilityType.class);
assertNotNull("password capability not present", capCred.getPassword());
PagedSearchCapabilityType capPage = CapabilityUtil.getCapability(capabilities, PagedSearchCapabilityType.class);
assertNotNull("paged search capability not present", capPage);
}
@Test
public void test500FetchObject() throws Exception {
final String TEST_NAME = "test500FetchObject";
TestUtil.displayTestTile(this, TEST_NAME);
// GIVEN
ResourceAttributeContainer resourceObject = createResourceObject(
"uid=Teell,ou=People,dc=example,dc=com", "Teell William", "Teell");
OperationResult addResult = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
PrismObject<ShadowType> shadow = wrapInShadow(ShadowType.class, resourceObject);
// Add a testing object
cc.addObject(shadow, null, null, addResult);
ObjectClassComplexTypeDefinition accountDefinition = resourceObject.getDefinition().getComplexTypeDefinition();
Collection<ResourceAttribute<?>> identifiers = resourceObject.getPrimaryIdentifiers();
// Determine object class from the schema
ResourceObjectIdentification identification = new ResourceObjectIdentification(accountDefinition, identifiers, null);
OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
// WHEN
PrismObject<ShadowType> ro = cc.fetchObject(ShadowType.class, identification, null, null, result);
// THEN
AssertJUnit.assertNotNull(ro);
System.out.println("Fetched object " + ro);
System.out.println("Result:");
System.out.println(result.debugDump());
}
@Test
public void test510Search() throws Exception {
final String TEST_NAME = "test510Search";
TestUtil.displayTestTile(this, TEST_NAME);
// GIVEN
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findObjectClassDefinition(OpenDJController.OBJECT_CLASS_INETORGPERSON_NAME);
// Determine object class from the schema
ResultHandler<ShadowType> handler = new ResultHandler<ShadowType>() {
@Override
public boolean handle(PrismObject<ShadowType> object) {
System.out.println("Search: found: " + object);
return true;
}
};
OperationResult result = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
// WHEN
cc.search(accountDefinition, new ObjectQuery(), handler, null, null, null, null, result);
// THEN
}
@Test
public void test600CreateAccountWithPassword() throws Exception {
final String TEST_NAME = "test600CreateAccountWithPassword";
TestUtil.displayTestTile(this, TEST_NAME);
// GIVEN
ResourceAttributeContainer resourceObject = createResourceObject(
"uid=lechuck,ou=people,dc=example,dc=com", "Ghost Pirate LeChuck", "LeChuck");
Set<Operation> additionalOperations = new HashSet<Operation>();
ProtectedStringType ps = protector.encryptString("t4k30v3rTh3W0rld");
// PasswordChangeOperation passOp = new PasswordChangeOperation(ps);
// additionalOperations.add(passOp);
OperationResult addResult = new OperationResult(this.getClass().getName()
+ "." + TEST_NAME);
PrismObject<ShadowType> shadow = wrapInShadow(ShadowType.class, resourceObject);
CredentialsType credentials = new CredentialsType();
PasswordType pass = new PasswordType();
pass.setValue(ps);
credentials.setPassword(pass);
shadow.asObjectable().setCredentials(credentials);
// WHEN
cc.addObject(shadow, additionalOperations, null, addResult);
// THEN
String entryUuid = (String) resourceObject.getPrimaryIdentifier().getValue().getValue();
Entry entry = openDJController.searchAndAssertByEntryUuid(entryUuid);
display("Entry before change", entry);
String passwordAfter = OpenDJController.getAttributeValue(entry, "userPassword");
assertNotNull(passwordAfter);
System.out.println("Changed password: " + passwordAfter);
// TODO
}
@Test
public void test610ChangePassword() throws Exception {
final String TEST_NAME = "test610ChangePassword";
TestUtil.displayTestTile(this, TEST_NAME);
// GIVEN
ResourceAttributeContainer resourceObject = createResourceObject(
"uid=drake,ou=People,dc=example,dc=com", "Sir Francis Drake", "Drake");
PrismObject<ShadowType> shadow = wrapInShadow(ShadowType.class, resourceObject);
OperationResult addResult = new OperationResult(this.getClass().getName() + "." + TEST_NAME);
// Add a testing object
cc.addObject(shadow, null, null, addResult);
String entryUuid = (String) resourceObject.getPrimaryIdentifier().getValue().getValue();
Entry entry = openDJController.searchAndAssertByEntryUuid(entryUuid);
display("Entry before change", entry);
String passwordBefore = OpenDJController.getAttributeValue(entry, "userPassword");
// We have set no password during create, therefore the password should
// be empty
assertNull(passwordBefore);
ObjectClassComplexTypeDefinition accountDefinition = resourceObject.getDefinition().getComplexTypeDefinition();
Collection<ResourceAttribute<?>> identifiers = resourceObject.getPrimaryIdentifiers();
// Determine object class from the schema
OperationResult result = new OperationResult(this.getClass().getName() + ".testFetchObject");
// WHEN
Set<Operation> changes = new HashSet<Operation>();
ProtectedStringType passPs = protector.encryptString("salalala");
ItemDeltaType propMod = new ItemDeltaType();
//create modification path
Document doc = DOMUtil.getDocument();
ItemPathType path = new ItemPathType("credentials/password/value");
// PropertyPath propPath = new PropertyPath(new PropertyPath(ResourceObjectShadowType.F_CREDENTIALS), CredentialsType.F_PASSWORD);
propMod.setPath(path);
//set the replace value
MapXNode passPsXnode = ((PrismContextImpl) prismContext).getBeanMarshaller().marshalProtectedDataType(passPs, null);
RawType value = new RawType(passPsXnode, prismContext);
propMod.getValue().add(value);
//set the modificaion type
propMod.setModificationType(ModificationTypeType.REPLACE);
PropertyDelta passDelta = (PropertyDelta)DeltaConvertor.createItemDelta(propMod, shadow.getDefinition());
PropertyModificationOperation passwordModification = new PropertyModificationOperation(passDelta);
changes.add(passwordModification);
// PasswordChangeOperation passwordChange = new PasswordChangeOperation(passPs);
// changes.add(passwordChange);
cc.modifyObject(accountDefinition, identifiers, changes, null, result);
// THEN
entry = openDJController.searchAndAssertByEntryUuid(entryUuid);
display("Entry after change", entry);
String passwordAfter = OpenDJController.getAttributeValue(entry, "userPassword");
assertNotNull(passwordAfter);
System.out.println("Account password: " + passwordAfter);
}
private ResourceAttributeContainer createResourceObject(String dn, String sn, String cn) throws SchemaException {
// Account type is hardcoded now
ObjectClassComplexTypeDefinition accountDefinition = resourceSchema
.findObjectClassDefinition(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.OBJECT_CLASS_INETORGPERSON_NAME));
// Determine identifier from the schema
ResourceAttributeContainer resourceObject = accountDefinition.instantiate(ShadowType.F_ATTRIBUTES);
ResourceAttributeDefinition road = accountDefinition.findAttributeDefinition(
new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "sn"));
ResourceAttribute roa = road.instantiate();
roa.setValue(new PrismPropertyValue(sn));
resourceObject.add(roa);
road = accountDefinition.findAttributeDefinition(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "cn"));
roa = road.instantiate();
roa.setValue(new PrismPropertyValue(cn));
resourceObject.add(roa);
road = accountDefinition.findAttributeDefinition(
new QName(ResourceTypeUtil.getResourceNamespace(resourceType), OpenDJController.RESOURCE_OPENDJ_SECONDARY_IDENTIFIER_LOCAL_NAME));
roa = road.instantiate();
roa.setValue(new PrismPropertyValue(dn));
resourceObject.add(roa);
return resourceObject;
}
private <T extends ShadowType> PrismObject<T> wrapInShadow(Class<T> type, ResourceAttributeContainer resourceObject) throws SchemaException {
PrismObjectDefinition<T> shadowDefinition = getShadowDefinition(type);
PrismObject<T> shadow = shadowDefinition.instantiate();
resourceObject.setElementName(ShadowType.F_ATTRIBUTES);
shadow.getValue().add(resourceObject);
return shadow;
}
private <T extends ShadowType> PrismObjectDefinition<T> getShadowDefinition(Class<T> type) {
return prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(type);
}
}