/* * 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.test; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertTrue; import com.evolveum.icf.dummy.resource.DummyResource; import com.evolveum.midpoint.common.Clock; import com.evolveum.midpoint.common.crypto.CryptoUtil; import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.RefinedResourceSchema; import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl; import com.evolveum.midpoint.prism.ConsistencyCheckScope; import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.Objectable; import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.prism.PrismPropertyDefinition; import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.PrismReference; import com.evolveum.midpoint.prism.PrismReferenceValue; import com.evolveum.midpoint.prism.PrismValue; import com.evolveum.midpoint.prism.crypto.EncryptionException; import com.evolveum.midpoint.prism.crypto.Protector; import com.evolveum.midpoint.prism.delta.ItemDelta; 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.path.ItemPath; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.query.builder.QueryBuilder; import com.evolveum.midpoint.prism.util.PrismAsserts; import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.repo.api.RepoAddOptions; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.MidPointPrismContextFactory; import com.evolveum.midpoint.schema.ResultHandler; import com.evolveum.midpoint.schema.constants.ConnectorTestOperation; import com.evolveum.midpoint.schema.constants.MidPointConstants; import com.evolveum.midpoint.schema.constants.ObjectTypes; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.internals.CachingStatistics; import com.evolveum.midpoint.schema.internals.InternalMonitor; import com.evolveum.midpoint.schema.internals.InternalsConfig; import com.evolveum.midpoint.schema.processor.*; import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; import com.evolveum.midpoint.schema.processor.ResourceAttribute; import com.evolveum.midpoint.schema.processor.ResourceAttributeContainer; import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.schema.util.FocusTypeUtil; import com.evolveum.midpoint.schema.util.ResourceTypeUtil; import com.evolveum.midpoint.schema.util.ShadowUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.test.ldap.OpenDJController; import com.evolveum.midpoint.test.util.DerbyController; import com.evolveum.midpoint.test.util.MidPointTestConstants; import com.evolveum.midpoint.test.util.TestUtil; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.PrettyPrinter; 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.exception.SystemException; 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.prism.xml.ns._public.types_3.PolyStringType; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder; import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; import org.testng.Assert; import org.testng.AssertJUnit; import org.testng.annotations.BeforeMethod; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import javax.xml.bind.JAXBException; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; import java.io.File; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import static com.evolveum.midpoint.test.IntegrationTestTools.display; import static org.testng.AssertJUnit.assertNotNull; /** * @author Radovan Semancik * */ public abstract class AbstractIntegrationTest extends AbstractTestNGSpringContextTests { public static final String COMMON_DIR_NAME = "common"; @Deprecated public static final String COMMON_DIR_PATH = MidPointTestConstants.TEST_RESOURCES_PATH + "/" + COMMON_DIR_NAME; public static final File COMMON_DIR = new File(MidPointTestConstants.TEST_RESOURCES_DIR, COMMON_DIR_NAME); protected static final String DEFAULT_INTENT = "default"; protected static final String OPENDJ_PEOPLE_SUFFIX = "ou=people,dc=example,dc=com"; protected static final String OPENDJ_GROUPS_SUFFIX = "ou=groups,dc=example,dc=com"; private static final Trace LOGGER = TraceManager.getTrace(AbstractIntegrationTest.class); // Values used to check if something is unchanged or changed properly protected LdapShaPasswordEncoder ldapShaPasswordEncoder = new LdapShaPasswordEncoder(); private long lastResourceSchemaFetchCount = 0; private long lastConnectorSchemaParseCount = 0; private long lastConnectorCapabilitiesFetchCount = 0; private long lastConnectorInitializationCount = 0; private long lastResourceSchemaParseCount = 0; private CachingStatistics lastResourceCacheStats; private long lastShadowFetchOperationCount = 0; private long lastScriptCompileCount = 0; private long lastScriptExecutionCount = 0; private long lastConnectorOperationCount = 0; private long lastConnectorSimulatedPagingSearchCount = 0; private long lastDummyResourceGroupMembersReadCount = 0; private long lastPrismObjectCloneCount = 0; @Autowired(required = true) @Qualifier("cacheRepositoryService") protected RepositoryService repositoryService; protected static Set<Class> initializedClasses = new HashSet<Class>(); @Autowired(required = true) protected TaskManager taskManager; @Autowired(required = true) protected Protector protector; @Autowired(required = true) protected Clock clock; @Autowired(required = true) protected PrismContext prismContext; @Autowired(required = true) protected MatchingRuleRegistry matchingRuleRegistry; // Controllers for embedded OpenDJ and Derby. The abstract test will configure it, but // it will not start // only tests that need OpenDJ or derby should start it protected static OpenDJController openDJController = new OpenDJController(); protected static DerbyController derbyController = new DerbyController(); // We need this complicated init as we want to initialize repo only once. // JUnit will // create new class instance for every test, so @Before and @PostInit will // not work // directly. We also need to init the repo after spring autowire is done, so // @BeforeClass won't work either. @BeforeMethod public void initSystemConditional() throws Exception { // Check whether we are already initialized assertNotNull("Repository is not wired properly", repositoryService); assertNotNull("Task manager is not wired properly", taskManager); LOGGER.trace("initSystemConditional: {} systemInitialized={}", this.getClass(), isSystemInitialized()); if (!isSystemInitialized()) { PrettyPrinter.setDefaultNamespacePrefix(MidPointConstants.NS_MIDPOINT_PUBLIC_PREFIX); PrismTestUtil.resetPrismContext(MidPointPrismContextFactory.FACTORY); LOGGER.trace("initSystemConditional: invoking initSystem"); Task initTask = taskManager.createTaskInstance(this.getClass().getName() + ".initSystem"); initTask.setChannel(SchemaConstants.CHANNEL_GUI_INIT_URI); OperationResult result = initTask.getResult(); InternalMonitor.reset(); InternalsConfig.setPrismMonitoring(true); prismContext.setMonitor(new InternalMonitor()); initSystem(initTask, result); postInitSystem(initTask, result); result.computeStatus(); IntegrationTestTools.display("initSystem result", result); TestUtil.assertSuccessOrWarning("initSystem failed (result)", result, 1); setSystemInitialized(); } } protected boolean isSystemInitialized() { return initializedClasses.contains(this.getClass()); } private void setSystemInitialized() { initializedClasses.add(this.getClass()); } protected void unsetSystemInitialized() { initializedClasses.remove(this.getClass()); } abstract public void initSystem(Task initTask, OperationResult initResult) throws Exception; /** * May be used to clean up initialized objects as all of the initialized objects should be * available at this time. */ protected void postInitSystem(Task initTask, OperationResult initResult) throws Exception { // Nothing to do by default }; protected <T extends ObjectType> PrismObject<T> repoAddObjectFromFile(String filePath, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, EncryptionException, IOException { return repoAddObjectFromFile(new File(filePath), parentResult); } protected <T extends ObjectType> PrismObject<T> repoAddObjectFromFile(File file, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, EncryptionException, IOException { return repoAddObjectFromFile(file, false, parentResult); } protected <T extends ObjectType> PrismObject<T> repoAddObjectFromFile(File file, Class<T> type, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, EncryptionException, IOException { return repoAddObjectFromFile(file, false, parentResult); } protected <T extends ObjectType> PrismObject<T> repoAddObjectFromFile(File file, Class<T> type, boolean metadata, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, EncryptionException, IOException { return repoAddObjectFromFile(file, metadata, parentResult); } protected <T extends ObjectType> PrismObject<T> repoAddObjectFromFile(File file, boolean metadata, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, EncryptionException, IOException { OperationResult result = parentResult.createSubresult(AbstractIntegrationTest.class.getName() + ".repoAddObjectFromFile"); result.addParam("file", file); LOGGER.debug("addObjectFromFile: {}", file); PrismObject<T> object = prismContext.parseObject(file); if (metadata) { addBasicMetadata(object); } LOGGER.trace("Adding object:\n{}", object.debugDump()); repoAddObject(object, "from file "+file, result); result.recordSuccess(); return object; } protected PrismObject<ShadowType> repoAddShadowFromFile(File file, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, EncryptionException, IOException { OperationResult result = parentResult.createSubresult(AbstractIntegrationTest.class.getName() + ".repoAddShadowFromFile"); result.addParam("file", file); LOGGER.debug("addShadowFromFile: {}", file); PrismObject<ShadowType> object = prismContext.parseObject(file); PrismContainer<Containerable> attrCont = object.findContainer(ShadowType.F_ATTRIBUTES); for (PrismProperty<?> attr: attrCont.getValue().getProperties()) { if (attr.getDefinition() == null) { ResourceAttributeDefinition<String> attrDef = new ResourceAttributeDefinitionImpl<>(attr.getElementName(), DOMUtil.XSD_STRING, prismContext); attr.setDefinition((PrismPropertyDefinition) attrDef); } } addBasicMetadata(object); LOGGER.trace("Adding object:\n{}", object.debugDump()); repoAddObject(object, "from file "+file, result); result.recordSuccess(); return object; } protected <T extends ObjectType> void addBasicMetadata(PrismObject<T> object) { // Add at least the very basic meta-data MetadataType metaData = new MetadataType(); metaData.setCreateTimestamp(clock.currentTimeXMLGregorianCalendar()); object.asObjectable().setMetadata(metaData); } protected <T extends ObjectType> void repoAddObject(PrismObject<T> object, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, EncryptionException { repoAddObject(object, null, result); } protected <T extends ObjectType> void repoAddObject(PrismObject<T> object, String contextDesc, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, EncryptionException { if (object.canRepresent(TaskType.class)) { Assert.assertNotNull(taskManager, "Task manager is not initialized"); try { taskManager.addTask((PrismObject<TaskType>) object, result); } catch (ObjectAlreadyExistsException ex) { result.recordFatalError(ex.getMessage(), ex); throw ex; } catch (SchemaException ex) { result.recordFatalError(ex.getMessage(), ex); throw ex; } } else { Assert.assertNotNull(repositoryService, "Repository service is not initialized"); try{ CryptoUtil.encryptValues(protector, object); String oid = repositoryService.addObject(object, null, result); object.setOid(oid); } catch(ObjectAlreadyExistsException ex){ result.recordFatalError(ex.getMessage()+" while adding "+object+(contextDesc==null?"":" "+contextDesc), ex); throw ex; } catch(SchemaException ex){ result.recordFatalError(ex.getMessage()+" while adding "+object+(contextDesc==null?"":" "+contextDesc), ex); throw ex; } catch (EncryptionException ex) { result.recordFatalError(ex.getMessage()+" while adding "+object+(contextDesc==null?"":" "+contextDesc), ex); throw ex; } } } protected <T extends ObjectType> List<PrismObject<T>> repoAddObjectsFromFile(String filePath, Class<T> type, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, IOException { return repoAddObjectsFromFile(new File(filePath), type, parentResult); } protected <T extends ObjectType> List<PrismObject<T>> repoAddObjectsFromFile(File file, Class<T> type, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, IOException { OperationResult result = parentResult.createSubresult(AbstractIntegrationTest.class.getName() + ".addObjectsFromFile"); result.addParam("file", file); LOGGER.trace("addObjectsFromFile: {}", file); List<PrismObject<T>> objects = (List) PrismTestUtil.parseObjects(file); for (PrismObject<T> object: objects) { try { repoAddObject(object, result); } catch (ObjectAlreadyExistsException e) { throw new ObjectAlreadyExistsException(e.getMessage()+" while adding "+object+" from file "+file, e); } catch (SchemaException e) { new SchemaException(e.getMessage()+" while adding "+object+" from file "+file, e); } catch (EncryptionException e) { new EncryptionException(e.getMessage()+" while adding "+object+" from file "+file, e); } } result.recordSuccess(); return objects; } // these objects can be of various types protected List<PrismObject> repoAddObjectsFromFile(File file, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, IOException { OperationResult result = parentResult.createSubresult(AbstractIntegrationTest.class.getName() + ".addObjectsFromFile"); result.addParam("file", file); LOGGER.trace("addObjectsFromFile: {}", file); List<PrismObject> objects = (List) PrismTestUtil.parseObjects(file); for (PrismObject object: objects) { try { repoAddObject(object, result); } catch (ObjectAlreadyExistsException e) { throw new ObjectAlreadyExistsException(e.getMessage()+" while adding "+object+" from file "+file, e); } catch (SchemaException e) { new SchemaException(e.getMessage()+" while adding "+object+" from file "+file, e); } catch (EncryptionException e) { new EncryptionException(e.getMessage()+" while adding "+object+" from file "+file, e); } } result.recordSuccess(); return objects; } protected <T extends ObjectType> T parseObjectTypeFromFile(String fileName, Class<T> clazz) throws SchemaException, IOException { return parseObjectType(new File(fileName), clazz); } protected <T extends ObjectType> T parseObjectType(File file) throws SchemaException, IOException { PrismObject<T> prismObject = prismContext.parseObject(file); return prismObject.asObjectable(); } protected <T extends ObjectType> T parseObjectType(File file, Class<T> clazz) throws SchemaException, IOException { PrismObject<T> prismObject = prismContext.parseObject(file); return prismObject.asObjectable(); } protected static <T> T unmarshallValueFromFile(File file, Class<T> clazz) throws IOException, JAXBException, SchemaException { return PrismTestUtil.parseAnyValue(file); } protected static <T> T unmarshallValueFromFile(String filePath, Class<T> clazz) throws IOException, JAXBException, SchemaException { return PrismTestUtil.parseAnyValue(new File(filePath)); } protected static ObjectType unmarshallValueFromFile(String filePath) throws IOException, JAXBException, SchemaException { return unmarshallValueFromFile(filePath, ObjectType.class); } protected PrismObject<ResourceType> addResourceFromFile(File file, String connectorType, OperationResult result) throws JAXBException, SchemaException, ObjectAlreadyExistsException, EncryptionException, IOException { return addResourceFromFile(file, connectorType, false, result); } protected PrismObject<ResourceType> addResourceFromFile(File file, String connectorType, boolean overwrite, OperationResult result) throws JAXBException, SchemaException, ObjectAlreadyExistsException, EncryptionException, IOException { LOGGER.trace("addObjectFromFile: {}, connector type {}", file, connectorType); PrismObject<ResourceType> resource = prismContext.parseObject(file); fillInConnectorRef(resource, connectorType, result); CryptoUtil.encryptValues(protector, resource); display("Adding resource ", resource); RepoAddOptions options = null; if (overwrite){ options = RepoAddOptions.createOverwrite(); } String oid = repositoryService.addObject(resource, options, result); resource.setOid(oid); return resource; } protected PrismObject<ConnectorType> findConnectorByType(String connectorType, OperationResult result) throws SchemaException { ObjectQuery query = QueryBuilder.queryFor(ConnectorType.class, prismContext) .item(ConnectorType.F_CONNECTOR_TYPE).eq(connectorType) .build(); List<PrismObject<ConnectorType>> connectors = repositoryService.searchObjects(ConnectorType.class, query, null, result); if (connectors.size() != 1) { throw new IllegalStateException("Cannot find connector type " + connectorType + ", got " + connectors); } return connectors.get(0); } protected PrismObject<ConnectorType> findConnectorByTypeAndVersion(String connectorType, String connectorVersion, OperationResult result) throws SchemaException { ObjectQuery query = QueryBuilder.queryFor(ConnectorType.class, prismContext) .item(ConnectorType.F_CONNECTOR_TYPE).eq(connectorType) .and().item(ConnectorType.F_CONNECTOR_VERSION).eq(connectorVersion) .build(); List<PrismObject<ConnectorType>> connectors = repositoryService.searchObjects(ConnectorType.class, query, null, result); if (connectors.size() != 1) { throw new IllegalStateException("Cannot find connector type " + connectorType + ", version "+connectorVersion+", got " + connectors); } return connectors.get(0); } protected void fillInConnectorRef(PrismObject<ResourceType> resource, String connectorType, OperationResult result) throws SchemaException { ResourceType resourceType = resource.asObjectable(); PrismObject<ConnectorType> connector = findConnectorByType(connectorType, result); if (resourceType.getConnectorRef() == null) { resourceType.setConnectorRef(new ObjectReferenceType()); } resourceType.getConnectorRef().setOid(connector.getOid()); resourceType.getConnectorRef().setType(ObjectTypes.CONNECTOR.getTypeQName()); } protected void fillInAdditionalConnectorRef(PrismObject<ResourceType> resource, String connectorName, String connectorType, OperationResult result) throws SchemaException { ResourceType resourceType = resource.asObjectable(); PrismObject<ConnectorType> connectorPrism = findConnectorByType(connectorType, result); for (ConnectorInstanceSpecificationType additionalConnector: resourceType.getAdditionalConnector()) { if (connectorName.equals(additionalConnector.getName())) { ObjectReferenceType ref = new ObjectReferenceType().oid(connectorPrism.getOid()); additionalConnector.setConnectorRef(ref); } } } protected SystemConfigurationType getSystemConfiguration() throws ObjectNotFoundException, SchemaException { OperationResult result = new OperationResult(AbstractIntegrationTest.class.getName()+".getSystemConfiguration"); try { PrismObject<SystemConfigurationType> sysConf = repositoryService.getObject(SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), null, result); result.computeStatus(); TestUtil.assertSuccess("getObject(systemConfig) not success", result); return sysConf.asObjectable(); } catch (ObjectNotFoundException e) { // No big deal return null; } } protected void assumeAssignmentPolicy(AssignmentPolicyEnforcementType policy) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { SystemConfigurationType systemConfiguration = getSystemConfiguration(); AssignmentPolicyEnforcementType currentPolicy = getAssignmentPolicyEnforcementType(systemConfiguration); if (currentPolicy == policy) { return; } ProjectionPolicyType syncSettings = new ProjectionPolicyType(); syncSettings.setAssignmentPolicyEnforcement(policy); applySyncSettings(SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), SchemaConstants.C_SYSTEM_CONFIGURATION_GLOBAL_ACCOUNT_SYNCHRONIZATION_SETTINGS, syncSettings); } protected void assumeResourceAssigmentPolicy(String oid, AssignmentPolicyEnforcementType policy, boolean legalize) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException{ ProjectionPolicyType syncSettings = new ProjectionPolicyType(); syncSettings.setAssignmentPolicyEnforcement(policy); syncSettings.setLegalize(Boolean.valueOf(legalize)); applySyncSettings(ResourceType.class, oid, ResourceType.F_PROJECTION, syncSettings); } protected void deleteResourceAssigmentPolicy(String oid, AssignmentPolicyEnforcementType policy, boolean legalize) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException{ PrismObjectDefinition<ResourceType> objectDefinition = prismContext.getSchemaRegistry() .findObjectDefinitionByCompileTimeClass(ResourceType.class); ProjectionPolicyType syncSettings = new ProjectionPolicyType(); syncSettings.setAssignmentPolicyEnforcement(policy); syncSettings.setLegalize(Boolean.valueOf(legalize)); ItemDelta deleteAssigmentEnforcement = PropertyDelta .createModificationDeleteProperty(new ItemPath(ResourceType.F_PROJECTION), objectDefinition.findPropertyDefinition(ResourceType.F_PROJECTION), syncSettings); Collection<ItemDelta> modifications = new ArrayList<ItemDelta>(); modifications.add(deleteAssigmentEnforcement); OperationResult result = new OperationResult("Aplying sync settings"); repositoryService.modifyObject(ResourceType.class, oid, modifications, result); display("Aplying sync settings result", result); result.computeStatus(); TestUtil.assertSuccess("Aplying sync settings failed (result)", result); } protected AssignmentPolicyEnforcementType getAssignmentPolicyEnforcementType(SystemConfigurationType systemConfiguration) { ProjectionPolicyType globalAccountSynchronizationSettings = systemConfiguration.getGlobalAccountSynchronizationSettings(); if (globalAccountSynchronizationSettings == null) { return null; } return globalAccountSynchronizationSettings.getAssignmentPolicyEnforcement(); } protected void applySyncSettings(Class clazz, String oid, QName path, ProjectionPolicyType syncSettings) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { PrismObjectDefinition<?> objectDefinition = prismContext.getSchemaRegistry() .findObjectDefinitionByCompileTimeClass(clazz); Collection<? extends ItemDelta> modifications = PropertyDelta .createModificationReplacePropertyCollection( path, objectDefinition, syncSettings); OperationResult result = new OperationResult("Aplying sync settings"); repositoryService.modifyObject(clazz, oid, modifications, result); invalidateSystemObjectsCache(); display("Aplying sync settings result", result); result.computeStatus(); TestUtil.assertSuccess("Aplying sync settings failed (result)", result); } protected void invalidateSystemObjectsCache() { // Nothing to do here. For subclasses in model-common and higher components. } protected void assertNoChanges(ObjectDelta<?> delta) { assertNull("Unexpected changes: "+ delta, delta); } protected void assertNoChanges(String desc, ObjectDelta<?> delta) { assertNull("Unexpected changes in "+desc+": "+ delta, delta); } protected <F extends FocusType> void assertEffectiveActivation(PrismObject<F> focus, ActivationStatusType expected) { ActivationType activationType = focus.asObjectable().getActivation(); assertNotNull("No activation in "+focus, activationType); assertEquals("Wrong effectiveStatus in activation in "+focus, expected, activationType.getEffectiveStatus()); } protected <F extends FocusType> void assertEffectiveActivation(AssignmentType assignmentType, ActivationStatusType expected) { ActivationType activationType = assignmentType.getActivation(); assertNotNull("No activation in "+assignmentType, activationType); assertEquals("Wrong effectiveStatus in activation in "+assignmentType, expected, activationType.getEffectiveStatus()); } protected <F extends FocusType> void assertValidityStatus(PrismObject<F> focus, TimeIntervalStatusType expected) { ActivationType activationType = focus.asObjectable().getActivation(); assertNotNull("No activation in "+focus, activationType); assertEquals("Wrong validityStatus in activation in "+focus, expected, activationType.getValidityStatus()); } protected void assertShadow(PrismObject<? extends ShadowType> shadow) { assertObject(shadow); } protected void assertObject(PrismObject<? extends ObjectType> object) { object.checkConsistence(true, true, ConsistencyCheckScope.THOROUGH); assertTrue("Incomplete definition in "+object, object.hasCompleteDefinition()); assertFalse("No OID", StringUtils.isEmpty(object.getOid())); assertNotNull("Null name in "+object, object.asObjectable().getName()); } protected void assertUser(PrismObject<UserType> user, String oid, String name, String fullName, String givenName, String familyName) { assertUser(user, oid, name, fullName, givenName, familyName, null); } protected void assertUser(PrismObject<UserType> user, String oid, String name, String fullName, String givenName, String familyName, String location) { assertObject(user); UserType userType = user.asObjectable(); if (oid != null) { assertEquals("Wrong " + user + " OID (prism)", oid, user.getOid()); assertEquals("Wrong " + user + " OID (jaxb)", oid, userType.getOid()); } PrismAsserts.assertEqualsPolyString("Wrong "+user+" name", name, userType.getName()); PrismAsserts.assertEqualsPolyString("Wrong "+user+" fullName", fullName, userType.getFullName()); PrismAsserts.assertEqualsPolyString("Wrong "+user+" givenName", givenName, userType.getGivenName()); PrismAsserts.assertEqualsPolyString("Wrong "+user+" familyName", familyName, userType.getFamilyName()); if (location != null) { PrismAsserts.assertEqualsPolyString("Wrong " + user + " location", location, userType.getLocality()); } } protected <O extends ObjectType> void assertSubtype(PrismObject<O> object, String subtype) { assertTrue("Object "+object+" does not have subtype "+subtype, FocusTypeUtil.hasSubtype(object, subtype)); } protected void assertShadowCommon(PrismObject<ShadowType> accountShadow, String oid, String username, ResourceType resourceType, QName objectClass) throws SchemaException { assertShadowCommon(accountShadow, oid, username, resourceType, objectClass, null, false); } protected void assertAccountShadowCommon(PrismObject<ShadowType> accountShadow, String oid, String username, ResourceType resourceType) throws SchemaException { assertShadowCommon(accountShadow, oid, username, resourceType, getAccountObjectClass(resourceType), null, false); } protected void assertAccountShadowCommon(PrismObject<ShadowType> accountShadow, String oid, String username, ResourceType resourceType, MatchingRule<String> nameMatchingRule, boolean requireNormalizedIdentfiers) throws SchemaException { assertShadowCommon(accountShadow,oid,username,resourceType,getAccountObjectClass(resourceType),nameMatchingRule, requireNormalizedIdentfiers); } protected QName getAccountObjectClass(ResourceType resourceType) { return new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "AccountObjectClass"); } protected QName getGroupObjectClass(ResourceType resourceType) { return new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "GroupObjectClass"); } protected void assertShadowCommon(PrismObject<ShadowType> shadow, String oid, String username, ResourceType resourceType, QName objectClass, MatchingRule<String> nameMatchingRule, boolean requireNormalizedIdentfiers) throws SchemaException { assertShadowCommon(shadow, oid, username, resourceType, objectClass, nameMatchingRule, requireNormalizedIdentfiers, false); } protected void assertShadowCommon(PrismObject<ShadowType> shadow, String oid, String username, ResourceType resourceType, QName objectClass, final MatchingRule<String> nameMatchingRule, boolean requireNormalizedIdentfiers, boolean useMatchingRuleForShadowName) throws SchemaException { assertShadow(shadow); if (oid != null) { assertEquals("Shadow OID mismatch (prism)", oid, shadow.getOid()); } ShadowType resourceObjectShadowType = shadow.asObjectable(); if (oid != null) { assertEquals("Shadow OID mismatch (jaxb)", oid, resourceObjectShadowType.getOid()); } assertEquals("Shadow objectclass", objectClass, resourceObjectShadowType.getObjectClass()); assertEquals("Shadow resourceRef OID", resourceType.getOid(), shadow.asObjectable().getResourceRef().getOid()); PrismContainer<Containerable> attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); assertNotNull("Null attributes in shadow for "+username, attributesContainer); assertFalse("Empty attributes in shadow for "+username, attributesContainer.isEmpty()); if (useMatchingRuleForShadowName) { MatchingRule<PolyString> polyMatchingRule = new MatchingRule<PolyString>() { @Override public QName getName() { return nameMatchingRule.getName(); } @Override public boolean isSupported(QName xsdType) { return nameMatchingRule.isSupported(xsdType); } @Override public boolean match(PolyString a, PolyString b) throws SchemaException { return nameMatchingRule.match(a.getOrig(), b.getOrig()); } @Override public boolean matchRegex(PolyString a, String regex) throws SchemaException { return nameMatchingRule.matchRegex(a.getOrig(), regex); } @Override public PolyString normalize(PolyString original) throws SchemaException { return new PolyString(nameMatchingRule.normalize(original.getOrig())); } }; PrismAsserts.assertPropertyValueMatch(shadow, ShadowType.F_NAME, polyMatchingRule, PrismTestUtil.createPolyString(username)); } else { PrismAsserts.assertPropertyValue(shadow, ShadowType.F_NAME, PrismTestUtil.createPolyString(username)); } RefinedResourceSchema rSchema = RefinedResourceSchemaImpl.getRefinedSchema(resourceType); ObjectClassComplexTypeDefinition ocDef = rSchema.findObjectClassDefinition(objectClass); if (ocDef.getSecondaryIdentifiers().isEmpty()) { ResourceAttributeDefinition idDef = ocDef.getPrimaryIdentifiers().iterator().next(); PrismProperty<String> idProp = attributesContainer.findProperty(idDef.getName()); assertNotNull("No primary identifier ("+idDef.getName()+") attribute in shadow for "+username, idProp); if (nameMatchingRule == null) { assertEquals("Unexpected primary identifier in shadow for "+username, username, idProp.getRealValue()); } else { if (requireNormalizedIdentfiers) { assertEquals("Unexpected primary identifier in shadow for "+username, nameMatchingRule.normalize(username), idProp.getRealValue()); } else { PrismAsserts.assertEquals("Unexpected primary identifier in shadow for "+username, nameMatchingRule, username, idProp.getRealValue()); } } } else { ResourceAttributeDefinition idSecDef = ocDef.getSecondaryIdentifiers().iterator().next(); PrismProperty<String> idProp = attributesContainer.findProperty(idSecDef.getName()); assertNotNull("No secondary identifier ("+idSecDef.getName()+") attribute in shadow for "+username, idProp); if (nameMatchingRule == null) { assertEquals("Unexpected secondary identifier in shadow for "+username, username, idProp.getRealValue()); } else { if (requireNormalizedIdentfiers) { assertEquals("Unexpected secondary identifier in shadow for "+username, nameMatchingRule.normalize(username), idProp.getRealValue()); } else { PrismAsserts.assertEquals("Unexpected secondary identifier in shadow for "+username, nameMatchingRule, username, idProp.getRealValue()); } } } } protected void assertShadowSecondaryIdentifier(PrismObject<ShadowType> shadow, String expectedIdentifier, ResourceType resourceType, MatchingRule<String> nameMatchingRule) throws SchemaException { RefinedResourceSchema rSchema = RefinedResourceSchemaImpl.getRefinedSchema(resourceType); ObjectClassComplexTypeDefinition ocDef = rSchema.findObjectClassDefinition(shadow.asObjectable().getObjectClass()); ResourceAttributeDefinition idSecDef = ocDef.getSecondaryIdentifiers().iterator().next(); PrismContainer<Containerable> attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); PrismProperty<String> idProp = attributesContainer.findProperty(idSecDef.getName()); assertNotNull("No secondary identifier ("+idSecDef.getName()+") attribute in shadow for "+expectedIdentifier, idProp); if (nameMatchingRule == null) { assertEquals("Unexpected secondary identifier in shadow for "+expectedIdentifier, expectedIdentifier, idProp.getRealValue()); } else { PrismAsserts.assertEquals("Unexpected secondary identifier in shadow for "+expectedIdentifier, nameMatchingRule, expectedIdentifier, idProp.getRealValue()); } } protected void assertShadowName(PrismObject<ShadowType> shadow, String expectedName) { PrismAsserts.assertEqualsPolyString("Shadow name is wrong in "+shadow, expectedName, shadow.asObjectable().getName()); } protected void assertShadowName(ShadowType shadowType, String expectedName) { assertShadowName(shadowType.asPrismObject(), expectedName); } protected void assertShadowRepo(String oid, String username, ResourceType resourceType, QName objectClass) throws ObjectNotFoundException, SchemaException { OperationResult result = new OperationResult(AbstractIntegrationTest.class.getName()+".assertShadowRepo"); PrismObject<ShadowType> shadow = repositoryService.getObject(ShadowType.class, oid, null, result); result.computeStatus(); TestUtil.assertSuccess(result); assertShadowRepo(shadow, oid, username, resourceType, objectClass); } protected void assertAccountShadowRepo(String oid, String username, ResourceType resourceType) throws ObjectNotFoundException, SchemaException { assertShadowRepo(oid,username,resourceType,getAccountObjectClass(resourceType)); } protected void assertShadowRepo(PrismObject<ShadowType> accountShadow, String oid, String username, ResourceType resourceType, QName objectClass) throws SchemaException { assertShadowRepo(accountShadow, oid, username, resourceType, objectClass, null); } protected void assertAccountShadowRepo(PrismObject<ShadowType> accountShadow, String oid, String username, ResourceType resourceType) throws SchemaException { assertShadowRepo(accountShadow, oid, username, resourceType, getAccountObjectClass(resourceType), null); } protected void assertAccountShadowRepo(PrismObject<ShadowType> accountShadow, String oid, String username, ResourceType resourceType, MatchingRule<String> matchingRule) throws SchemaException { assertShadowRepo(accountShadow, oid, username, resourceType, getAccountObjectClass(resourceType), matchingRule); } protected void assertShadowRepo(PrismObject<ShadowType> accountShadow, String oid, String username, ResourceType resourceType, QName objectClass, MatchingRule<String> nameMatchingRule) throws SchemaException { assertShadowCommon(accountShadow, oid, username, resourceType, objectClass, nameMatchingRule, true); PrismContainer<Containerable> attributesContainer = accountShadow.findContainer(ShadowType.F_ATTRIBUTES); List<Item<?,?>> attributes = attributesContainer.getValue().getItems(); // Collection secIdentifiers = ShadowUtil.getSecondaryIdentifiers(accountShadow); if (attributes == null){ AssertJUnit.fail("No attributes in repo shadow"); } RefinedResourceSchema refinedSchema = null; try { refinedSchema = RefinedResourceSchemaImpl.getRefinedSchema(resourceType); } catch (SchemaException e) { AssertJUnit.fail(e.getMessage()); } ObjectClassComplexTypeDefinition objClassDef = refinedSchema.getRefinedDefinition(objectClass); Collection secIdentifiers = objClassDef.getSecondaryIdentifiers(); if (secIdentifiers == null){ AssertJUnit.fail("No secondary identifiers in repo shadow"); } // repo shadow should contains all secondary identifiers + ICF_UID assertRepoShadowAttributes(attributes, secIdentifiers.size()+1); } protected void assertRepoShadowAttributes(List<Item<?,?>> attributes, int expectedNumberOfIdentifiers) { assertEquals("Unexpected number of attributes in repo shadow", expectedNumberOfIdentifiers, attributes.size()); } protected String getIcfUid(PrismObject<ShadowType> shadow) { PrismContainer<Containerable> attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); assertNotNull("Null attributes in "+shadow, attributesContainer); assertFalse("Empty attributes in "+shadow, attributesContainer.isEmpty()); PrismProperty<String> icfUidProp = attributesContainer.findProperty(new QName(SchemaConstants.NS_ICF_SCHEMA,"uid")); assertNotNull("No ICF name attribute in "+shadow, icfUidProp); return icfUidProp.getRealValue(); } protected void rememberResourceSchemaFetchCount() { lastResourceSchemaFetchCount = InternalMonitor.getResourceSchemaFetchCount(); } protected void assertResourceSchemaFetchIncrement(int expectedIncrement) { long currentConnectorSchemaFetchCount = InternalMonitor.getResourceSchemaFetchCount(); long actualIncrement = currentConnectorSchemaFetchCount - lastResourceSchemaFetchCount; assertEquals("Unexpected increment in resource schema fetch count", (long)expectedIncrement, actualIncrement); lastResourceSchemaFetchCount = currentConnectorSchemaFetchCount; } protected void rememberConnectorSchemaParseCount() { lastConnectorSchemaParseCount = InternalMonitor.getConnectorSchemaParseCount(); } protected void assertConnectorSchemaParseIncrement(int expectedIncrement) { long currentCount = InternalMonitor.getConnectorSchemaParseCount(); long actualIncrement = currentCount - lastConnectorSchemaParseCount; assertEquals("Unexpected increment in connector schema parse count", (long)expectedIncrement, actualIncrement); lastConnectorSchemaParseCount = currentCount; } protected void rememberConnectorCapabilitiesFetchCount() { lastConnectorCapabilitiesFetchCount = InternalMonitor.getConnectorCapabilitiesFetchCount(); } protected void assertConnectorCapabilitiesFetchIncrement(int expectedIncrement) { long currentConnectorCapabilitiesFetchCount = InternalMonitor.getConnectorCapabilitiesFetchCount(); long actualIncrement = currentConnectorCapabilitiesFetchCount - lastConnectorCapabilitiesFetchCount; assertEquals("Unexpected increment in connector capabilities fetch count", (long)expectedIncrement, actualIncrement); lastConnectorCapabilitiesFetchCount = currentConnectorCapabilitiesFetchCount; } protected void rememberConnectorInitializationCount() { lastConnectorInitializationCount = InternalMonitor.getConnectorInstanceInitializationCount(); } protected void assertConnectorInitializationCountIncrement(int expectedIncrement) { long currentConnectorInitializationCount = InternalMonitor.getConnectorInstanceInitializationCount(); long actualIncrement = currentConnectorInitializationCount - lastConnectorInitializationCount; assertEquals("Unexpected increment in connector initialization count", (long)expectedIncrement, actualIncrement); lastConnectorInitializationCount = currentConnectorInitializationCount; } protected void rememberResourceSchemaParseCount() { lastResourceSchemaParseCount = InternalMonitor.getResourceSchemaParseCount(); } protected void assertResourceSchemaParseCountIncrement(int expectedIncrement) { long currentResourceSchemaParseCount = InternalMonitor.getResourceSchemaParseCount(); long actualIncrement = currentResourceSchemaParseCount - lastResourceSchemaParseCount; assertEquals("Unexpected increment in resource schema parse count", (long)expectedIncrement, actualIncrement); lastResourceSchemaParseCount = currentResourceSchemaParseCount; } protected void rememberScriptCompileCount() { lastScriptCompileCount = InternalMonitor.getScriptCompileCount(); } protected void assertScriptCompileIncrement(int expectedIncrement) { long currentCount = InternalMonitor.getScriptCompileCount(); long actualIncrement = currentCount - lastScriptCompileCount; assertEquals("Unexpected increment in script compile count", (long)expectedIncrement, actualIncrement); lastScriptCompileCount = currentCount; } protected void rememberScriptExecutionCount() { lastScriptExecutionCount = InternalMonitor.getScriptExecutionCount(); } protected void assertScriptExecutionIncrement(int expectedIncrement) { long currentCount = InternalMonitor.getScriptExecutionCount(); long actualIncrement = currentCount - lastScriptExecutionCount; assertEquals("Unexpected increment in script execution count", (long)expectedIncrement, actualIncrement); lastScriptExecutionCount = currentCount; } protected void rememberConnectorOperationCount() { lastConnectorOperationCount = InternalMonitor.getConnectorOperationCount(); } protected void assertConnectorOperationIncrement(int expectedIncrement) { long currentCount = InternalMonitor.getConnectorOperationCount(); long actualIncrement = currentCount - lastConnectorOperationCount; assertEquals("Unexpected increment in connector operationCount count", (long)expectedIncrement, actualIncrement); lastConnectorOperationCount = currentCount; } protected void rememberConnectorSimulatedPagingSearchCount() { lastConnectorSimulatedPagingSearchCount = InternalMonitor.getConnectorSimulatedPagingSearchCount(); } protected void assertConnectorSimulatedPagingSearchIncrement(int expectedIncrement) { long currentCount = InternalMonitor.getConnectorSimulatedPagingSearchCount(); long actualIncrement = currentCount - lastConnectorSimulatedPagingSearchCount; assertEquals("Unexpected increment in connector simulated paged search count", (long)expectedIncrement, actualIncrement); lastConnectorSimulatedPagingSearchCount = currentCount; } protected void rememberResourceCacheStats() { lastResourceCacheStats = InternalMonitor.getResourceCacheStats().clone(); } protected void assertResourceCacheHitsIncrement(int expectedIncrement) { assertCacheHits(lastResourceCacheStats, InternalMonitor.getResourceCacheStats(), "resouce cache", expectedIncrement); } protected void assertResourceCacheMissesIncrement(int expectedIncrement) { assertCacheMisses(lastResourceCacheStats, InternalMonitor.getResourceCacheStats(), "resouce cache", expectedIncrement); } protected void assertCacheHits(CachingStatistics lastStats, CachingStatistics currentStats, String desc, int expectedIncrement) { long actualIncrement = currentStats.getHits() - lastStats.getHits(); assertEquals("Unexpected increment in "+desc+" hit count", (long)expectedIncrement, actualIncrement); lastStats.setHits(currentStats.getHits()); } protected void assertCacheMisses(CachingStatistics lastStats, CachingStatistics currentStats, String desc, int expectedIncrement) { long actualIncrement = currentStats.getMisses() - lastStats.getMisses(); assertEquals("Unexpected increment in "+desc+" miss count", (long)expectedIncrement, actualIncrement); lastStats.setMisses(currentStats.getMisses()); } protected void rememberPrismObjectCloneCount() { lastPrismObjectCloneCount = InternalMonitor.getPrismObjectCloneCount(); } protected void assertPrismObjectCloneIncrement(int expectedIncrement) { long currentCount = InternalMonitor.getPrismObjectCloneCount(); long actualIncrement = currentCount - lastPrismObjectCloneCount; assertEquals("Unexpected increment in prism object clone count", (long)expectedIncrement, actualIncrement); lastPrismObjectCloneCount = currentCount; } protected void assertPrismObjectCloneIncrement(int expectedIncrementMin, int expectedIncrementMax) { long currentCount = InternalMonitor.getPrismObjectCloneCount(); long actualIncrement = currentCount - lastPrismObjectCloneCount; assertTrue("Unexpected increment in prism object clone count. Expected " +expectedIncrementMin+"-"+expectedIncrementMax+" but was "+actualIncrement, actualIncrement >= expectedIncrementMin && actualIncrement <= expectedIncrementMax); lastPrismObjectCloneCount = currentCount; } protected void assertSteadyResources() { assertResourceSchemaFetchIncrement(0); assertResourceSchemaParseCountIncrement(0); assertConnectorCapabilitiesFetchIncrement(0); assertConnectorInitializationCountIncrement(0); assertConnectorSchemaParseIncrement(0); } protected void rememberSteadyResources() { rememberResourceSchemaFetchCount(); rememberResourceSchemaParseCount(); rememberConnectorCapabilitiesFetchCount(); rememberConnectorInitializationCount(); rememberConnectorSchemaParseCount(); } protected void rememberShadowFetchOperationCount() { lastShadowFetchOperationCount = InternalMonitor.getShadowFetchOperationCount(); } protected void assertShadowFetchOperationCountIncrement(int expectedIncrement) { long currentCount = InternalMonitor.getShadowFetchOperationCount(); long actualIncrement = currentCount - lastShadowFetchOperationCount; assertEquals("Unexpected increment in shadow fetch count", (long)expectedIncrement, actualIncrement); lastShadowFetchOperationCount = currentCount; } protected void rememberDummyResourceGroupMembersReadCount(String instanceName) { lastDummyResourceGroupMembersReadCount = DummyResource.getInstance(instanceName).getGroupMembersReadCount(); } protected void assertDummyResourceGroupMembersReadCountIncrement(String instanceName, int expectedIncrement) { long currentDummyResourceGroupMembersReadCount = DummyResource.getInstance(instanceName).getGroupMembersReadCount(); long actualIncrement = currentDummyResourceGroupMembersReadCount - lastDummyResourceGroupMembersReadCount; assertEquals("Unexpected increment in group members read count count in dummy resource '"+instanceName+"'", (long)expectedIncrement, actualIncrement); lastDummyResourceGroupMembersReadCount = currentDummyResourceGroupMembersReadCount; } protected PrismObject<ShadowType> createShadow(PrismObject<ResourceType> resource, String id) throws SchemaException { return createShadow(resource, id, id); } protected PrismObject<ShadowType> createShadowNameOnly(PrismObject<ResourceType> resource, String name) throws SchemaException { return createShadow(resource, null, name); } protected PrismObject<ShadowType> createShadow(PrismObject<ResourceType> resource, String uid, String name) throws SchemaException { PrismObject<ShadowType> shadow = getShadowDefinition().instantiate(); ShadowType shadowType = shadow.asObjectable(); if (name != null) { shadowType.setName(PrismTestUtil.createPolyStringType(name)); } ObjectReferenceType resourceRef = new ObjectReferenceType(); resourceRef.setOid(resource.getOid()); shadowType.setResourceRef(resourceRef); shadowType.setKind(ShadowKindType.ACCOUNT); RefinedResourceSchema refinedSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource); RefinedObjectClassDefinition objectClassDefinition = refinedSchema.getDefaultRefinedDefinition(ShadowKindType.ACCOUNT); shadowType.setObjectClass(objectClassDefinition.getTypeName()); ResourceAttributeContainer attrContainer = ShadowUtil.getOrCreateAttributesContainer(shadow, objectClassDefinition); if (uid != null) { RefinedAttributeDefinition uidAttrDef = objectClassDefinition.findAttributeDefinition(new QName(SchemaConstants.NS_ICF_SCHEMA,"uid")); ResourceAttribute<String> uidAttr = uidAttrDef.instantiate(); uidAttr.setRealValue(uid); attrContainer.add(uidAttr); } if (name != null) { RefinedAttributeDefinition nameAttrDef = objectClassDefinition.findAttributeDefinition(new QName(SchemaConstants.NS_ICF_SCHEMA,"name")); ResourceAttribute<String> nameAttr = nameAttrDef.instantiate(); nameAttr.setRealValue(name); attrContainer.add(nameAttr); } return shadow; } protected PrismObject<ShadowType> findAccountShadowByUsername(String username, PrismObject<ResourceType> resource, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException { ObjectQuery query = createAccountShadowQuerySecondaryIdentifier(username, resource); List<PrismObject<ShadowType>> accounts = repositoryService.searchObjects(ShadowType.class, query, null, result); if (accounts.isEmpty()) { return null; } assert accounts.size() == 1 : "Too many accounts found for username "+username+" on "+resource+": "+accounts; return accounts.iterator().next(); } protected PrismObject<ShadowType> findShadowByName(ShadowKindType kind, String intent, String name, PrismObject<ResourceType> resource, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException { RefinedResourceSchema rSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource); RefinedObjectClassDefinition rOcDef = rSchema.getRefinedDefinition(kind,intent); ObjectQuery query = createShadowQuerySecondaryIdentifier(rOcDef, name, resource); List<PrismObject<ShadowType>> shadows = repositoryService.searchObjects(ShadowType.class, query, null, result); if (shadows.isEmpty()) { return null; } assert shadows.size() == 1 : "Too many shadows found for name "+name+" on "+resource+": "+shadows; return shadows.iterator().next(); } protected PrismObject<ShadowType> findShadowByName(QName objectClass, String name, PrismObject<ResourceType> resource, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException { RefinedResourceSchema rSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource); RefinedObjectClassDefinition rOcDef = rSchema.getRefinedDefinition(objectClass); ObjectQuery query = createShadowQuerySecondaryIdentifier(rOcDef, name, resource); List<PrismObject<ShadowType>> shadows = repositoryService.searchObjects(ShadowType.class, query, null, result); if (shadows.isEmpty()) { return null; } assert shadows.size() == 1 : "Too many shadows found for name "+name+" on "+resource+": "+shadows; return shadows.iterator().next(); } protected ObjectQuery createAccountShadowQuery(String identifier, PrismObject<ResourceType> resource) throws SchemaException { RefinedResourceSchema rSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource); RefinedObjectClassDefinition rAccount = rSchema.getDefaultRefinedDefinition(ShadowKindType.ACCOUNT); Collection<? extends ResourceAttributeDefinition> identifierDefs = rAccount.getPrimaryIdentifiers(); assert identifierDefs.size() == 1 : "Unexpected identifier set in "+resource+" refined schema: "+identifierDefs; ResourceAttributeDefinition identifierDef = identifierDefs.iterator().next(); //TODO: set matching rule instead of null return QueryBuilder.queryFor(ShadowType.class, prismContext) .itemWithDef(identifierDef, ShadowType.F_ATTRIBUTES, identifierDef.getName()).eq(identifier) .and().item(ShadowType.F_OBJECT_CLASS).eq(rAccount.getObjectClassDefinition().getTypeName()) .and().item(ShadowType.F_RESOURCE_REF).ref(resource.getOid()) .build(); } protected ObjectQuery createAccountShadowQuerySecondaryIdentifier(String identifier, PrismObject<ResourceType> resource) throws SchemaException { RefinedResourceSchema rSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource); RefinedObjectClassDefinition rAccount = rSchema.getDefaultRefinedDefinition(ShadowKindType.ACCOUNT); return createShadowQuerySecondaryIdentifier(rAccount, identifier, resource); } protected ObjectQuery createShadowQuerySecondaryIdentifier(ObjectClassComplexTypeDefinition rAccount, String identifier, PrismObject<ResourceType> resource) throws SchemaException { Collection<? extends ResourceAttributeDefinition> identifierDefs = rAccount.getSecondaryIdentifiers(); assert identifierDefs.size() == 1 : "Unexpected identifier set in "+resource+" refined schema: "+identifierDefs; ResourceAttributeDefinition identifierDef = identifierDefs.iterator().next(); //TODO: set matching rule instead of null return QueryBuilder.queryFor(ShadowType.class, prismContext) .itemWithDef(identifierDef, ShadowType.F_ATTRIBUTES, identifierDef.getName()).eq(identifier) .and().item(ShadowType.F_OBJECT_CLASS).eq(rAccount.getTypeName()) .and().item(ShadowType.F_RESOURCE_REF).ref(resource.getOid()) .build(); } protected ObjectQuery createAccountShadowQueryByAttribute(String attributeName, String attributeValue, PrismObject<ResourceType> resource) throws SchemaException { RefinedResourceSchema rSchema = RefinedResourceSchemaImpl.getRefinedSchema(resource); RefinedObjectClassDefinition rAccount = rSchema.getDefaultRefinedDefinition(ShadowKindType.ACCOUNT); return createShadowQueryByAttribute(rAccount, attributeName, attributeValue, resource); } protected ObjectQuery createShadowQueryByAttribute(ObjectClassComplexTypeDefinition rAccount, String attributeName, String attributeValue, PrismObject<ResourceType> resource) throws SchemaException { ResourceAttributeDefinition<Object> attrDef = rAccount.findAttributeDefinition(attributeName); return QueryBuilder.queryFor(ShadowType.class, prismContext) .itemWithDef(attrDef, ShadowType.F_ATTRIBUTES, attrDef.getName()).eq(attributeValue) .and().item(ShadowType.F_OBJECT_CLASS).eq(rAccount.getTypeName()) .and().item(ShadowType.F_RESOURCE_REF).ref(resource.getOid()) .build(); } protected PrismObjectDefinition<UserType> getUserDefinition() { return prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(UserType.class); } protected PrismObjectDefinition<ShadowType> getShadowDefinition() { return prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class); } // objectClassName may be null protected RefinedAttributeDefinition getAttributeDefinition(ResourceType resourceType, ShadowKindType kind, QName objectClassName, String attributeLocalName) throws SchemaException { RefinedResourceSchema refinedResourceSchema = RefinedResourceSchemaImpl.getRefinedSchema(resourceType); RefinedObjectClassDefinition refinedObjectClassDefinition = refinedResourceSchema.findRefinedDefinitionByObjectClassQName(kind, objectClassName); return refinedObjectClassDefinition.findAttributeDefinition(attributeLocalName); } protected void assertPassword(ShadowType shadow, String expectedPassword) throws SchemaException, EncryptionException { CredentialsType credentials = shadow.getCredentials(); assertNotNull("No credentials in "+shadow, credentials); PasswordType password = credentials.getPassword(); assertNotNull("No password in "+shadow, password); ProtectedStringType passwordValue = password.getValue(); assertNotNull("No password value in "+shadow, passwordValue); protector.decrypt(passwordValue); assertEquals("Wrong password in "+shadow, expectedPassword, passwordValue.getClearValue()); } protected void assertPasswordDelta(ObjectDelta<ShadowType> shadowDelta) { ItemDelta<PrismValue, ItemDefinition> passwordDelta = shadowDelta.findItemDelta(SchemaConstants.PATH_PASSWORD_VALUE); assertNotNull("No password delta in "+shadowDelta, passwordDelta); } protected void assertFilter(ObjectFilter filter, Class<? extends ObjectFilter> expectedClass) { if (expectedClass == null) { assertNull("Expected that filter is null, but it was "+filter, filter); } else { assertNotNull("Expected that filter is of class "+expectedClass.getName()+", but it was null", filter); if (!(expectedClass.isAssignableFrom(filter.getClass()))) { AssertJUnit.fail("Expected that filter is of class "+expectedClass.getName()+", but it was "+filter); } } } protected void assertSyncToken(String syncTaskOid, Object expectedValue) throws ObjectNotFoundException, SchemaException { OperationResult result = new OperationResult(AbstractIntegrationTest.class.getName()+".assertSyncToken"); Task task = taskManager.getTask(syncTaskOid, result); assertSyncToken(task, expectedValue, result); result.computeStatus(); TestUtil.assertSuccess(result); } protected void assertSyncToken(String syncTaskOid, Object expectedValue, OperationResult result) throws ObjectNotFoundException, SchemaException { Task task = taskManager.getTask(syncTaskOid, result); assertSyncToken(task, expectedValue, result); } protected void assertSyncToken(Task task, Object expectedValue, OperationResult result) throws ObjectNotFoundException, SchemaException { PrismProperty<Object> syncTokenProperty = task.getExtensionProperty(SchemaConstants.SYNC_TOKEN); if (expectedValue == null && syncTokenProperty == null) { return; } Object syncTokenPropertyValue = syncTokenProperty.getAnyRealValue(); if (!MiscUtil.equals(expectedValue, syncTokenPropertyValue)) { AssertJUnit.fail("Wrong sync token, expected: " + expectedValue + (expectedValue==null?"":(", "+expectedValue.getClass().getName())) + ", was: "+ syncTokenPropertyValue + (syncTokenPropertyValue==null?"":(", "+syncTokenPropertyValue.getClass().getName()))); } } protected void assertShadows(int expected) throws SchemaException { OperationResult result = new OperationResult("assertShadows"); assertShadows(expected, result); result.computeStatus(); TestUtil.assertSuccess(result); } protected void assertShadows(int expected, OperationResult result) throws SchemaException { int actual = repositoryService.countObjects(ShadowType.class, null, result); if (expected != actual) { if (actual > 20) { AssertJUnit.fail("Unexpected number of (repository) shadows. Expected " + expected + " but was " + actual + " (too many to display)"); } ResultHandler<ShadowType> handler = new ResultHandler<ShadowType>() { @Override public boolean handle(PrismObject<ShadowType> object, OperationResult parentResult) { display("found shadow", object); return true; } }; repositoryService.searchObjectsIterative(ShadowType.class, null, handler, null, false, result); AssertJUnit.fail("Unexpected number of (repository) shadows. Expected " + expected + " but was " + actual); } } protected void assertShadowDead(PrismObject<ShadowType> shadow) { assertEquals("Shadow not dead: "+shadow, Boolean.TRUE, shadow.asObjectable().isDead()); } protected void assertShadowExists(PrismObject<ShadowType> shadow, Boolean expectedValue) { assertEquals("Wrong shadow 'exists': "+shadow, expectedValue, shadow.asObjectable().isExists()); } protected void assertActivationAdministrativeStatus(PrismObject<ShadowType> 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 assertShadowLockout(PrismObject<ShadowType> 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()); } } protected void assertUserLockout(PrismObject<UserType> user, LockoutStatusType expectedStatus) { ActivationType activationType = user.asObjectable().getActivation(); if (activationType == null) { if (expectedStatus == null) { return; } else { AssertJUnit.fail("Expected lockout status of "+user+" to be "+expectedStatus+", but there was no lockout status"); } } else { assertEquals("Wrong lockout status of "+user, expectedStatus, activationType.getLockoutStatus()); } } protected PolyString createPolyString(String string) { return PrismTestUtil.createPolyString(string); } protected PolyStringType createPolyStringType(String string) { return PrismTestUtil.createPolyStringType(string); } protected ItemPath getExtensionPath(QName propName) { return new ItemPath(ObjectType.F_EXTENSION, propName); } protected void assertNumberOfAttributes(PrismObject<ShadowType> shadow, Integer expectedNumberOfAttributes) { PrismContainer<Containerable> attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); assertNotNull("No attributes in repo shadow "+shadow, attributesContainer); List<Item<?,?>> attributes = attributesContainer.getValue().getItems(); assertFalse("Empty attributes in repo shadow "+shadow, attributes.isEmpty()); if (expectedNumberOfAttributes != null) { assertEquals("Unexpected number of attributes in repo shadow "+shadow, (int)expectedNumberOfAttributes, attributes.size()); } } protected ObjectReferenceType createRoleReference(String oid) { return createObjectReference(oid, RoleType.COMPLEX_TYPE, null); } protected ObjectReferenceType createOrgReference(String oid) { return createObjectReference(oid, OrgType.COMPLEX_TYPE, null); } protected ObjectReferenceType createOrgReference(String oid, QName relation) { return createObjectReference(oid, OrgType.COMPLEX_TYPE, relation); } protected ObjectReferenceType createObjectReference(String oid, QName type, QName relation) { ObjectReferenceType ref = new ObjectReferenceType(); ref.setOid(oid); ref.setType(type); ref.setRelation(relation); return ref; } protected void assertNotReached() { AssertJUnit.fail("Unexpected success"); } protected CredentialsStorageTypeType getPasswordStorageType() { return CredentialsStorageTypeType.ENCRYPTION; } protected CredentialsStorageTypeType getPasswordHistoryStorageType() { return CredentialsStorageTypeType.HASHING; } protected void assertEncryptedUserPassword(String userOid, String expectedClearPassword) throws EncryptionException, ObjectNotFoundException, SchemaException { OperationResult result = new OperationResult(AbstractIntegrationTest.class.getName()+".assertEncryptedUserPassword"); PrismObject<UserType> user = repositoryService.getObject(UserType.class, userOid, null, result); result.computeStatus(); TestUtil.assertSuccess(result); assertEncryptedUserPassword(user, expectedClearPassword); } protected void assertEncryptedUserPassword(PrismObject<UserType> user, String expectedClearPassword) throws EncryptionException, SchemaException { assertUserPassword(user, expectedClearPassword, CredentialsStorageTypeType.ENCRYPTION); } protected void assertUserPassword(PrismObject<UserType> user, String expectedClearPassword) throws EncryptionException, SchemaException { assertUserPassword(user, expectedClearPassword, getPasswordStorageType()); } protected void assertUserPassword(PrismObject<UserType> user, String expectedClearPassword, CredentialsStorageTypeType storageType) throws EncryptionException, SchemaException { UserType userType = user.asObjectable(); CredentialsType creds = userType.getCredentials(); assertNotNull("No credentials in "+user, creds); PasswordType password = creds.getPassword(); assertNotNull("No password in "+user, password); ProtectedStringType protectedActualPassword = password.getValue(); assertProtectedString("Password for "+user, expectedClearPassword, protectedActualPassword, storageType); } protected void assertProtectedString(String message, String expectedClearValue, ProtectedStringType actualValue, CredentialsStorageTypeType storageType) throws EncryptionException, SchemaException { switch (storageType) { case NONE: assertNull(message+": unexpected value: "+actualValue, actualValue); break; case ENCRYPTION: assertNotNull(message+": no value", actualValue); assertTrue(message+": unenctypted value: "+actualValue, actualValue.isEncrypted()); String actualClearPassword = protector.decryptString(actualValue); assertEquals(message+": wrong value", expectedClearValue, actualClearPassword); break; case HASHING: assertNotNull(message+": no value", actualValue); assertTrue(message+": value not hashed: "+actualValue, actualValue.isHashed()); ProtectedStringType expectedPs = new ProtectedStringType(); expectedPs.setClearValue(expectedClearValue); assertTrue(message+": hash does not match, expected "+expectedClearValue+", but was "+actualValue, protector.compare(actualValue, expectedPs)); break; default: throw new IllegalArgumentException("Unknown storage "+storageType); } } protected boolean compareProtectedString(String expectedClearValue, ProtectedStringType actualValue, CredentialsStorageTypeType storageType) throws EncryptionException, SchemaException { switch (storageType) { case NONE: return actualValue == null; case ENCRYPTION: if (actualValue == null) { return false; } if (!actualValue.isEncrypted()) { return false; } String actualClearPassword = protector.decryptString(actualValue); return expectedClearValue.equals(actualClearPassword); case HASHING: if (actualValue == null) { return false; } if (!actualValue.isHashed()) { return false; } ProtectedStringType expectedPs = new ProtectedStringType(); expectedPs.setClearValue(expectedClearValue); return protector.compare(actualValue, expectedPs); default: throw new IllegalArgumentException("Unknown storage "+storageType); } } protected void assertPasswordHistoryEntries(PrismObject<UserType> user, String... changedPasswords) { CredentialsType credentials = user.asObjectable().getCredentials(); assertNotNull("Null credentials in "+user, credentials); PasswordType passwordType = credentials.getPassword(); assertNotNull("Null passwordType in "+user, passwordType); assertPasswordHistoryEntries(user.toString(), passwordType.getHistoryEntry(), getPasswordHistoryStorageType(), changedPasswords); } protected void assertPasswordHistoryEntries(PasswordType passwordType, String... changedPasswords) { assertPasswordHistoryEntries(passwordType.getHistoryEntry(), changedPasswords); } protected void assertPasswordHistoryEntries(List<PasswordHistoryEntryType> historyEntriesType, String... changedPasswords) { assertPasswordHistoryEntries(null, historyEntriesType, getPasswordHistoryStorageType(), changedPasswords); } protected void assertPasswordHistoryEntries(String message, List<PasswordHistoryEntryType> historyEntriesType, CredentialsStorageTypeType storageType, String... changedPasswords) { if (message == null) { message = ""; } else { message = message + ": "; } if (changedPasswords.length != historyEntriesType.size()) { AssertJUnit.fail(message + "Unexpected number of history entries, expected " + Arrays.toString(changedPasswords)+"("+changedPasswords.length+"), was " + getPasswordHistoryHumanReadable(historyEntriesType) + "("+historyEntriesType.size()+")"); } assertEquals(message + "Unexpected number of history entries", changedPasswords.length, historyEntriesType.size()); for (PasswordHistoryEntryType historyEntry : historyEntriesType) { boolean found = false; try { for (String changedPassword : changedPasswords) { if (compareProtectedString(changedPassword, historyEntry.getValue(), storageType)) { found = true; break; } } if (!found) { AssertJUnit.fail(message + "Unexpected value saved in between password hisotry entries: " + getHumanReadablePassword(historyEntry.getValue()) + ". Expected "+ Arrays.toString(changedPasswords)+"("+changedPasswords.length+"), was " + getPasswordHistoryHumanReadable(historyEntriesType) + "("+historyEntriesType.size()+"); expected storage type: "+storageType); } } catch (EncryptionException | SchemaException e) { AssertJUnit.fail(message + "Could not encrypt password: "+e.getMessage()); } } } protected String getPasswordHistoryHumanReadable(List<PasswordHistoryEntryType> historyEntriesType) { return historyEntriesType.stream() .map(historyEntry -> { try { return getHumanReadablePassword(historyEntry.getValue()); } catch (EncryptionException e) { throw new SystemException(e.getMessage(), e); } }) .collect(Collectors.joining(", ")); } protected String getHumanReadablePassword(ProtectedStringType ps) throws EncryptionException { if (ps == null) { return null; } if (ps.isEncrypted()) { return "[E:"+protector.decryptString(ps)+"]"; } if (ps.isHashed()) { return "[H:"+ps.getHashedDataType().getDigestValue().length*8+"bit]"; } return ps.getClearValue(); } protected void logTrustManagers() throws NoSuchAlgorithmException, KeyStoreException { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init((KeyStore)null); for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) { if (trustManager instanceof X509TrustManager) { X509TrustManager x509TrustManager = (X509TrustManager)trustManager; LOGGER.debug("TrustManager(X509): {}", x509TrustManager); X509Certificate[] acceptedIssuers = x509TrustManager.getAcceptedIssuers(); if (acceptedIssuers != null) { for (X509Certificate acceptedIssuer: acceptedIssuers) { LOGGER.debug(" acceptedIssuer: {}", acceptedIssuer); } } } else { LOGGER.debug("TrustManager: {}", trustManager); } } } protected void setPassword(PrismObject<UserType> user, String password) { UserType userType = user.asObjectable(); CredentialsType creds = userType.getCredentials(); if (creds == null) { creds = new CredentialsType(); userType.setCredentials(creds); } PasswordType passwordType = creds.getPassword(); if (passwordType == null) { passwordType = new PasswordType(); creds.setPassword(passwordType); } ProtectedStringType ps = new ProtectedStringType(); ps.setClearValue(password); passwordType.setValue(ps); } protected void assertIncompleteShadowPassword(PrismObject<ShadowType> shadow) { PrismProperty<PolyStringType> passValProp = shadow.findProperty(SchemaConstants.PATH_PASSWORD_VALUE); assertNotNull("No password value property in "+shadow, passValProp); assertTrue("Password value property does not have 'incomplete' flag in "+shadow, passValProp.isIncomplete()); } protected void assertNoShadowPassword(PrismObject<ShadowType> shadow) { PrismProperty<PolyStringType> passValProp = shadow.findProperty(SchemaConstants.PATH_PASSWORD_VALUE); assertNull("Unexpected password value property in "+shadow+": "+passValProp, passValProp); } protected <O extends ObjectType> PrismObject<O> instantiateObject(Class<O> type) throws SchemaException { return prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(type).instantiate(); } protected void assertMetadata(String message, MetadataType metadataType, boolean create, boolean assertRequest, XMLGregorianCalendar start, XMLGregorianCalendar end, String actorOid, String channel) { assertNotNull("No metadata in " + message, metadataType); if (create) { TestUtil.assertBetween("Wrong create timestamp in " + message, start, end, metadataType.getCreateTimestamp()); if (actorOid != null) { ObjectReferenceType creatorRef = metadataType.getCreatorRef(); assertNotNull("No creatorRef in " + message, creatorRef); assertEquals("Wrong creatorRef OID in " + message, actorOid, creatorRef.getOid()); if (assertRequest) { TestUtil.assertBetween("Wrong request timestamp in " + message, start, end, metadataType.getRequestTimestamp()); ObjectReferenceType requestorRef = metadataType.getRequestorRef(); assertNotNull("No requestorRef in " + message, requestorRef); assertEquals("Wrong requestorRef OID in " + message, actorOid, requestorRef.getOid()); } } assertEquals("Wrong create channel in " + message, channel, metadataType.getCreateChannel()); } else { if (actorOid != null) { ObjectReferenceType modifierRef = metadataType.getModifierRef(); assertNotNull("No modifierRef in " + message, modifierRef); assertEquals("Wrong modifierRef OID in " + message, actorOid, modifierRef.getOid()); } TestUtil.assertBetween("Wrong password modify timestamp in " + message, start, end, metadataType.getModifyTimestamp()); assertEquals("Wrong modification channel in " + message, channel, metadataType.getModifyChannel()); } } protected void assertShadowPasswordMetadata(PrismObject<ShadowType> shadow, boolean passwordCreated, XMLGregorianCalendar startCal, XMLGregorianCalendar endCal, String actorOid, String channel) { CredentialsType creds = shadow.asObjectable().getCredentials(); assertNotNull("No credentials in shadow "+shadow, creds); PasswordType password = creds.getPassword(); assertNotNull("No password in shadow "+shadow, password); MetadataType metadata = password.getMetadata(); assertNotNull("No metadata in shadow "+shadow, metadata); assertMetadata("Password metadata in "+shadow, metadata, passwordCreated, false, startCal, endCal, actorOid, channel); } // Convenience protected <O extends ObjectType> PrismObject<O> parseObject(File file) throws SchemaException, IOException { return prismContext.parseObject(file); } protected void displayTestTile(String testName) { TestUtil.displayTestTile(this, testName); } protected void displayWhen(String testName) { TestUtil.displayWhen(testName); } protected void displayThen(String testName) { TestUtil.displayThen(testName); } protected Task createTask(String operationName) { if (!operationName.contains(".")) { operationName = this.getClass().getName() + "." + operationName; } Task task = taskManager.createTaskInstance(operationName); return task; } protected void assertSuccess(OperationResult result) { if (result.isUnknown()) { result.computeStatus(); } TestUtil.assertSuccess(result); } protected void assertSuccess(String message, OperationResult result) { if (result.isUnknown()) { result.computeStatus(); } TestUtil.assertSuccess(message, result); } protected String assertInProgress(OperationResult result) { if (result.isUnknown()) { result.computeStatus(); } TestUtil.assertStatus(result, OperationResultStatus.IN_PROGRESS); return result.getAsynchronousOperationReference(); } protected void assertFailure(OperationResult result) { if (result.isUnknown()) { result.computeStatus(); } TestUtil.assertFailure(result); } protected void fail(String message) { AssertJUnit.fail(message); } protected OperationResult assertSingleConnectorTestResult(OperationResult testResult) { return IntegrationTestTools.assertSingleConnectorTestResult(testResult); } protected void assertTestResourceSuccess(OperationResult testResult, ConnectorTestOperation operation) { IntegrationTestTools.assertTestResourceSuccess(testResult, operation); } protected void assertTestResourceFailure(OperationResult testResult, ConnectorTestOperation operation) { IntegrationTestTools.assertTestResourceFailure(testResult, operation); } protected void assertTestResourceNotApplicable(OperationResult testResult, ConnectorTestOperation operation) { IntegrationTestTools.assertTestResourceNotApplicable(testResult, operation); } protected <T> void assertAttribute(PrismObject<ResourceType> resource, ShadowType shadow, QName attrQname, T... expectedValues) { List<T> actualValues = ShadowUtil.getAttributeValues(shadow, attrQname); PrismAsserts.assertSets("attribute "+attrQname+" in " + shadow, actualValues, expectedValues); } protected <T> void assertAttribute(ResourceType resourceType, ShadowType shadowType, String attrName, T... expectedValues) { assertAttribute(resourceType.asPrismObject(), shadowType, attrName, expectedValues); } protected <T> void assertAttribute(ResourceType resourceType, ShadowType shadowType, QName attrName, T... expectedValues) { assertAttribute(resourceType.asPrismObject(), shadowType, attrName, expectedValues); } protected <T> void assertAttribute(PrismObject<ResourceType> resource, ShadowType shadow, String attrName, T... expectedValues) { QName attrQname = new QName(ResourceTypeUtil.getResourceNamespace(resource), attrName); assertAttribute(resource, shadow, attrQname, expectedValues); } protected <T> void assertAttribute(PrismObject<ResourceType> resource, ShadowType shadow, MatchingRule<T> matchingRule, QName attrQname, T... expectedValues) throws SchemaException { List<T> actualValues = ShadowUtil.getAttributeValues(shadow, attrQname); PrismAsserts.assertSets("attribute "+attrQname+" in " + shadow, matchingRule, actualValues, expectedValues); } protected void assertNoAttribute(PrismObject<ResourceType> resource, ShadowType shadow, QName attrQname) { PrismContainer<?> attributesContainer = shadow.asPrismObject().findContainer(ShadowType.F_ATTRIBUTES); if (attributesContainer == null || attributesContainer.isEmpty()) { return; } PrismProperty attribute = attributesContainer.findProperty(attrQname); assertNull("Unexpected attribute "+attrQname+" in "+shadow+": "+attribute, attribute); } protected void assertNoAttribute(PrismObject<ResourceType> resource, ShadowType shadow, String attrName) { QName attrQname = new QName(ResourceTypeUtil.getResourceNamespace(resource), attrName); assertNoAttribute(resource, shadow, attrQname); } protected void assertNoPendingOperation(PrismObject<ShadowType> shadow) { List<PendingOperationType> pendingOperations = shadow.asObjectable().getPendingOperation(); assertEquals("Wroung number of pending operations in "+shadow, 0, pendingOperations.size()); } protected void assertCase(String oid, String expectedState) throws ObjectNotFoundException, SchemaException { OperationResult result = new OperationResult("assertCase"); PrismObject<CaseType> acase = repositoryService.getObject(CaseType.class, oid, null, result); display("Case", acase); CaseType caseType = acase.asObjectable(); assertEquals("Wrong state of "+acase, expectedState ,caseType.getState()); } protected void closeCase(String caseOid) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { OperationResult result = new OperationResult("closeCase"); Collection modifications = new ArrayList<>(1); PrismPropertyDefinition<String> statePropertyDef = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(CaseType.class).findPropertyDefinition(CaseType.F_STATE); PropertyDelta<String> statusDelta = statePropertyDef.createEmptyDelta(new ItemPath(CaseType.F_STATE)); statusDelta.addValueToReplace(new PrismPropertyValue<>(SchemaConstants.CASE_STATE_CLOSED)); modifications.add(statusDelta); PrismPropertyDefinition<String> outcomePropertyDef = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(CaseType.class).findPropertyDefinition(CaseType.F_OUTCOME); PropertyDelta<String> outcomeDelta = outcomePropertyDef.createEmptyDelta(new ItemPath(CaseType.F_OUTCOME)); outcomeDelta.addValueToReplace(new PrismPropertyValue<>(OperationResultStatusType.SUCCESS.value())); modifications.add(outcomeDelta); repositoryService.modifyObject(CaseType.class, caseOid, modifications, null, result); PrismObject<CaseType> caseClosed = repositoryService.getObject(CaseType.class, caseOid, null, result); display("Case closed", caseClosed); } protected <F extends FocusType> void assertLinks(PrismObject<F> focus, int expectedNumLinks) throws ObjectNotFoundException, SchemaException { PrismReference linkRef = focus.findReference(FocusType.F_LINK_REF); if (linkRef == null) { assert expectedNumLinks == 0 : "Expected "+expectedNumLinks+" but "+focus+" has no linkRef"; return; } assertEquals("Wrong number of links in " + focus, expectedNumLinks, linkRef.size()); } protected void assertLinked(String userOid, String accountOid) throws ObjectNotFoundException, SchemaException { assertLinked(UserType.class, userOid, accountOid); } protected <F extends FocusType> void assertLinked(Class<F> type, String focusOid, String projectionOid) throws ObjectNotFoundException, SchemaException { OperationResult result = new OperationResult("assertLinked"); PrismObject<F> user = repositoryService.getObject(type, focusOid, null, result); assertLinked(user, projectionOid); } protected <F extends FocusType> void assertLinked(PrismObject<F> focus, PrismObject<ShadowType> projection) throws ObjectNotFoundException, SchemaException { assertLinked(focus, projection.getOid()); } protected <F extends FocusType> void assertLinked(PrismObject<F> focus, String projectionOid) throws ObjectNotFoundException, SchemaException { PrismReference linkRef = focus.findReference(FocusType.F_LINK_REF); assertNotNull("No linkRefs in "+focus, linkRef); boolean found = false; for (PrismReferenceValue val: linkRef.getValues()) { if (val.getOid().equals(projectionOid)) { found = true; } } assertTrue("Focus " + focus + " is not linked to shadow " + projectionOid, found); } protected void assertNotLinked(String userOid, String accountOid) throws ObjectNotFoundException, SchemaException { OperationResult result = new OperationResult("assertLinked"); PrismObject<UserType> user = repositoryService.getObject(UserType.class, userOid, null, result); assertNotLinked(user, accountOid); } protected void assertNotLinked(PrismObject<UserType> user, PrismObject<ShadowType> account) throws ObjectNotFoundException, SchemaException { assertNotLinked(user, account.getOid()); } protected void assertNotLinked(PrismObject<UserType> user, String accountOid) throws ObjectNotFoundException, SchemaException { PrismReference linkRef = user.findReference(UserType.F_LINK_REF); if (linkRef == null) { return; } boolean found = false; for (PrismReferenceValue val: linkRef.getValues()) { if (val.getOid().equals(accountOid)) { found = true; } } assertFalse("User " + user + " IS linked to account " + accountOid + " but not expecting it", found); } protected void assertNoLinkedAccount(PrismObject<UserType> user) { PrismReference accountRef = user.findReference(UserType.F_LINK_REF); if (accountRef == null) { return; } assert accountRef.isEmpty() : "Expected that "+user+" has no linked account but it has "+accountRef.size()+" linked accounts: " + accountRef.getValues(); } protected <F extends FocusType> void assertPersonaLinks(PrismObject<F> focus, int expectedNumLinks) throws ObjectNotFoundException, SchemaException { PrismReference linkRef = focus.findReference(FocusType.F_PERSONA_REF); if (linkRef == null) { assert expectedNumLinks == 0 : "Expected "+expectedNumLinks+" but "+focus+" has no personaRef"; return; } assertEquals("Wrong number of persona links in " + focus, expectedNumLinks, linkRef.size()); } protected <O extends ObjectType> void assertObjectOids(String message, Collection<PrismObject<O>> objects, String... oids) { List<String> objectOids = objects.stream().map( o -> o.getOid()).collect(Collectors.toList()); PrismAsserts.assertEqualsCollectionUnordered(message, objectOids, oids); } }