use of com.evolveum.midpoint.schema.processor.ResourceObjectDefinition in project midpoint by Evolveum.
the class ShadowIntegrityCheckItemProcessor method checkShadow.
private void checkShadow(ShadowCheckResult checkResult, PrismObject<ShadowType> shadow, Task workerTask, OperationResult result) throws SchemaException {
ShadowCheckConfiguration cfg = activityRun.getConfiguration();
ShadowType shadowType = shadow.asObjectable();
ObjectReferenceType resourceRef = shadowType.getResourceRef();
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Checking shadow {} (resource {})", ObjectTypeUtil.toShortString(shadowType), resourceRef != null ? resourceRef.getOid() : "(null)");
}
getStats().incrementShadows();
if (resourceRef == null) {
checkResult.recordError(ShadowStatistics.NO_RESOURCE_OID, new SchemaException("No resourceRef"));
fixNoResourceIfRequested(checkResult, ShadowStatistics.NO_RESOURCE_OID);
applyFixes(checkResult, shadow, workerTask, result);
return;
}
String resourceOid = resourceRef.getOid();
if (resourceOid == null) {
checkResult.recordError(ShadowStatistics.NO_RESOURCE_OID, new SchemaException("Null resource OID"));
fixNoResourceIfRequested(checkResult, ShadowStatistics.NO_RESOURCE_OID);
applyFixes(checkResult, shadow, workerTask, result);
return;
}
PrismObject<ResourceType> resource = getCachedResource(resourceOid);
if (resource == null) {
getStats().incrementResources();
try {
resource = getProvisioningService().getObject(ResourceType.class, resourceOid, null, workerTask, result);
} catch (ObjectNotFoundException e) {
checkResult.recordError(ShadowStatistics.NO_RESOURCE, new ObjectNotFoundException("Resource object does not exist: " + e.getMessage(), e));
fixNoResourceIfRequested(checkResult, ShadowStatistics.NO_RESOURCE);
applyFixes(checkResult, shadow, workerTask, result);
return;
} catch (SchemaException e) {
checkResult.recordError(ShadowStatistics.CANNOT_GET_RESOURCE, new SchemaException("Resource object has schema problems: " + e.getMessage(), e));
return;
} catch (CommonException | RuntimeException e) {
checkResult.recordError(ShadowStatistics.CANNOT_GET_RESOURCE, new SystemException("Resource object cannot be fetched for some reason: " + e.getMessage(), e));
return;
}
cacheResource(resource);
}
checkResult.setResource(resource);
ShadowKindType kind = shadowType.getKind();
if (kind == null) {
// TODO or simply assume account?
checkResult.recordError(ShadowStatistics.NO_KIND_SPECIFIED, new SchemaException("No kind specified"));
return;
}
if (cfg.checkExtraData) {
checkOrFixShadowActivationConsistency(checkResult, shadow);
}
PrismObject<ShadowType> fetchedShadow = null;
if (cfg.checkFetch) {
fetchedShadow = fetchShadow(checkResult, shadow, workerTask, result);
if (fetchedShadow != null) {
shadow.setUserData(KEY_EXISTS_ON_RESOURCE, "true");
}
}
if (cfg.checkOwners) {
List<PrismObject<FocusType>> owners = activityRun.searchOwners(shadow, result);
if (owners != null) {
shadow.setUserData(KEY_OWNERS, owners);
if (owners.size() > 1) {
checkResult.recordError(ShadowStatistics.MULTIPLE_OWNERS, new SchemaException("Multiple owners: " + owners));
}
}
if (shadowType.getSynchronizationSituation() == SynchronizationSituationType.LINKED && (owners == null || owners.isEmpty())) {
checkResult.recordError(ShadowStatistics.LINKED_WITH_NO_OWNER, new SchemaException("Linked shadow with no owner"));
}
if (shadowType.getSynchronizationSituation() != SynchronizationSituationType.LINKED && owners != null && !owners.isEmpty()) {
checkResult.recordError(ShadowStatistics.NOT_LINKED_WITH_OWNER, new SchemaException("Shadow with an owner but not marked as linked (marked as " + shadowType.getSynchronizationSituation() + ")"));
}
}
String intent = shadowType.getIntent();
if (cfg.checkIntents && (intent == null || intent.isEmpty())) {
checkResult.recordWarning(ShadowStatistics.NO_INTENT_SPECIFIED, "None or empty intent");
}
if (cfg.fixIntents && (intent == null || intent.isEmpty())) {
doFixIntent(checkResult, fetchedShadow, shadow, resource, workerTask, result);
}
QName objectClassName = shadowType.getObjectClass();
if (objectClassName == null) {
checkResult.recordError(ShadowStatistics.NO_OBJECT_CLASS_SPECIFIED, new SchemaException("No object class specified"));
return;
}
ContextMapKey key = new ContextMapKey(resourceOid, objectClassName);
ObjectTypeContext context = activityRun.getObjectTypeContext(key);
if (context == null) {
context = new ObjectTypeContext();
context.setResource(resource);
ResourceSchema refinedSchema;
try {
refinedSchema = ResourceSchemaFactory.getCompleteSchema(context.getResource(), LayerType.MODEL);
} catch (SchemaException e) {
checkResult.recordError(ShadowStatistics.CANNOT_GET_REFINED_SCHEMA, new SchemaException("Couldn't derive resource schema: " + e.getMessage(), e));
return;
}
if (refinedSchema == null) {
checkResult.recordError(ShadowStatistics.NO_RESOURCE_REFINED_SCHEMA, new SchemaException("No resource schema"));
return;
}
ResourceObjectDefinition objectDefinition = refinedSchema.findObjectDefinition(kind, ShadowUtil.getIntent(shadow));
if (objectDefinition instanceof ResourceObjectTypeDefinition) {
context.setObjectTypeDefinition((ResourceObjectTypeDefinition) objectDefinition);
} else {
// TODO or warning only?
checkResult.recordError(ShadowStatistics.NO_OBJECT_CLASS_REFINED_SCHEMA, new SchemaException("No refined object class definition for kind=" + kind + ", intent=" + intent));
return;
}
activityRun.putObjectTypeContext(key, context);
}
try {
getProvisioningService().applyDefinition(shadow, workerTask, result);
} catch (SchemaException | ObjectNotFoundException | CommunicationException | ConfigurationException | ExpressionEvaluationException e) {
checkResult.recordError(ShadowStatistics.OTHER_FAILURE, new SystemException("Couldn't apply definition to shadow from repo", e));
return;
}
Set<ResourceAttributeDefinition<?>> identifiers = new HashSet<>();
Collection<? extends ResourceAttributeDefinition<?>> primaryIdentifiers = context.getObjectTypeDefinition().getPrimaryIdentifiers();
identifiers.addAll(primaryIdentifiers);
identifiers.addAll(context.getObjectTypeDefinition().getSecondaryIdentifiers());
PrismContainer<ShadowAttributesType> attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES);
if (attributesContainer == null) {
// might happen on unfinished shadows?
checkResult.recordError(ShadowStatistics.OTHER_FAILURE, new SchemaException("No attributes container"));
return;
}
for (ResourceAttributeDefinition<?> identifier : identifiers) {
PrismProperty<String> property = attributesContainer.getValue().findProperty(identifier.getItemName());
if (property == null || property.size() == 0) {
checkResult.recordWarning(ShadowStatistics.OTHER_FAILURE, "No value for identifier " + identifier.getItemName());
continue;
}
if (property.size() > 1) {
// we don't expect multi-valued identifiers
checkResult.recordError(ShadowStatistics.OTHER_FAILURE, new SchemaException("Multi-valued identifier " + identifier.getItemName() + " with values " + property.getValues()));
continue;
}
// size == 1
String value = property.getValue().getValue();
if (value == null) {
checkResult.recordWarning(ShadowStatistics.OTHER_FAILURE, "Null value for identifier " + identifier.getItemName());
continue;
}
if (cfg.checkUniqueness) {
if (!cfg.checkDuplicatesOnPrimaryIdentifiersOnly || primaryIdentifiers.contains(identifier)) {
addIdentifierValue(context, identifier.getItemName(), value, shadow);
}
}
if (cfg.checkNormalization) {
doCheckNormalization(checkResult, identifier, value);
}
}
applyFixes(checkResult, shadow, workerTask, result);
}
use of com.evolveum.midpoint.schema.processor.ResourceObjectDefinition in project midpoint by Evolveum.
the class ProjectionCredentialsProcessor method processProjectionPasswordMapping.
private <F extends FocusType> void processProjectionPasswordMapping(LensContext<F> context, final LensProjectionContext projCtx, final SecurityPolicyType securityPolicy, XMLGregorianCalendar now, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException {
LensFocusContext<F> focusContext = context.getFocusContext();
PrismObject<F> focusNew = focusContext.getObjectNew();
if (focusNew == null) {
// This must be a focus delete or something similar. No point in proceeding
LOGGER.trace("focusNew is null, skipping credentials processing");
return;
}
PrismObjectDefinition<ShadowType> accountDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class);
PrismPropertyDefinition<ProtectedStringType> projPasswordPropertyDefinition = accountDefinition.findPropertyDefinition(SchemaConstants.PATH_PASSWORD_VALUE);
ResourceShadowDiscriminator rsd = projCtx.getResourceShadowDiscriminator();
ResourceObjectDefinition objectDefinition = projCtx.getStructuralObjectDefinition();
if (objectDefinition == null) {
LOGGER.trace("No ResourceObjectTypeDefinition, therefore also no password outbound definition," + " skipping credentials processing for projection {}", rsd);
return;
}
List<MappingType> outboundMappingBeans = objectDefinition.getPasswordOutbound();
if (outboundMappingBeans.isEmpty()) {
LOGGER.trace("No outbound password mapping for {}, skipping credentials processing", rsd);
return;
}
ObjectDeltaObject<F> objectDeltaObject = focusContext.getObjectDeltaObjectAbsolute();
// HACK
if (!projCtx.isDoReconciliation() && !projCtx.isAdd() && !isActivated(outboundMappingBeans, objectDeltaObject.getObjectDelta())) {
LOGGER.trace("Outbound password mappings not activated for type {}, skipping credentials processing", rsd);
return;
}
ObjectDelta<ShadowType> projDelta = projCtx.getCurrentDelta();
PropertyDelta<ProtectedStringType> projPasswordDelta;
if (projDelta != null && projDelta.getChangeType() == MODIFY) {
projPasswordDelta = projDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE);
} else {
projPasswordDelta = null;
}
checkExistingDeltaSanity(projCtx, projPasswordDelta);
boolean evaluateWeak = getEvaluateWeak(projCtx);
// TODO wave
ItemDeltaItem<PrismPropertyValue<ProtectedStringType>, PrismPropertyDefinition<ProtectedStringType>> focusPasswordIdi = objectDeltaObject.findIdi(SchemaConstants.PATH_PASSWORD_VALUE);
ConfigurableValuePolicySupplier valuePolicySupplier = (result1) -> SecurityUtil.getPasswordPolicy(securityPolicy);
MappingInitializer<PrismPropertyValue<ProtectedStringType>, PrismPropertyDefinition<ProtectedStringType>> initializer = (builder) -> {
builder.mappingKind(MappingKindType.OUTBOUND).implicitSourcePath(SchemaConstants.PATH_PASSWORD_VALUE).implicitTargetPath(SchemaConstants.PATH_PASSWORD_VALUE);
builder.defaultTargetDefinition(projPasswordPropertyDefinition);
builder.defaultSource(new Source<>(focusPasswordIdi, ExpressionConstants.VAR_INPUT_QNAME));
builder.valuePolicySupplier(valuePolicySupplier);
return builder;
};
MappingOutputProcessor<PrismPropertyValue<ProtectedStringType>> processor = (mappingOutputPath, outputStruct) -> {
PrismValueDeltaSetTriple<PrismPropertyValue<ProtectedStringType>> outputTriple = outputStruct.getOutputTriple();
if (outputTriple == null) {
LOGGER.trace("Credentials 'password' expression resulted in null output triple, skipping credentials processing for {}", rsd);
return false;
}
boolean projectionIsNew = projDelta != null && (projDelta.getChangeType() == ChangeType.ADD || projCtx.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD);
Collection<PrismPropertyValue<ProtectedStringType>> newValues;
if (projectionIsNew) {
newValues = outputTriple.getNonNegativeValues();
} else {
newValues = outputTriple.getPlusSet();
}
if (!canGetCleartext(newValues)) {
ObjectDelta<ShadowType> projectionPrimaryDelta = projCtx.getPrimaryDelta();
if (projectionPrimaryDelta != null) {
PropertyDelta<ProtectedStringType> passwordPrimaryDelta = projectionPrimaryDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE);
if (passwordPrimaryDelta != null) {
// We have only hashed value coming from the mapping. There are not very useful
// for provisioning. But we have primary projection delta - and that is very likely
// to be better.
// Skip all password mappings in this case. Primary delta trumps everything.
// No weak, normal or even strong mapping can change that.
// We need to disregard even strong mapping in this case. If we would heed the strong
// mapping then account initialization won't be possible.
LOGGER.trace("We have primary password delta in projection, skipping credentials processing");
return false;
}
}
}
Collection<PrismPropertyValue<ProtectedStringType>> minusSet = outputTriple.getMinusSet();
if (!minusSet.isEmpty()) {
if (!canGetCleartext(minusSet)) {
// We have hashed values in minus set. That is not great, we won't be able to get
// cleartext from that if we need it (e.g. for runAs in provisioning).
// Therefore try to get old value from focus password delta. If that matches with
// hashed value then we have the cleartext.
ProtectedStringType oldProjectionPassword = minusSet.iterator().next().getRealValue();
PropertyDelta<ProtectedStringType> focusPasswordDelta = (PropertyDelta<ProtectedStringType>) focusPasswordIdi.getDelta();
Collection<PrismPropertyValue<ProtectedStringType>> focusPasswordDeltaOldValues = focusPasswordDelta.getEstimatedOldValues();
if (focusPasswordDeltaOldValues != null && !focusPasswordDeltaOldValues.isEmpty()) {
ProtectedStringType oldFocusPassword = requireNonNull(focusPasswordDeltaOldValues.iterator().next().getRealValue());
try {
if (oldFocusPassword.canGetCleartext() && protector.compareCleartext(oldFocusPassword, oldProjectionPassword)) {
outputTriple.clearMinusSet();
outputTriple.addToMinusSet(prismContext.itemFactory().createPropertyValue(oldFocusPassword));
}
} catch (EncryptionException e) {
throw new SystemException(e.getMessage(), e);
}
}
}
}
return true;
};
String projCtxDesc = projCtx.toHumanReadableString();
PrismObject<ShadowType> shadowNew = projCtx.getObjectNew();
MappingInitializer<PrismPropertyValue<ProtectedStringType>, PrismPropertyDefinition<ProtectedStringType>> internalInitializer = builder -> {
builder.addVariableDefinitions(ModelImplUtils.getDefaultVariablesMap(context, projCtx, true));
builder.mappingKind(MappingKindType.OUTBOUND);
builder.originType(OriginType.OUTBOUND);
builder.implicitTargetPath(SchemaConstants.PATH_PASSWORD_VALUE);
builder.originObject(projCtx.getResource());
initializer.initialize(builder);
return builder;
};
MappingEvaluatorParams<PrismPropertyValue<ProtectedStringType>, PrismPropertyDefinition<ProtectedStringType>, ShadowType, F> params = new MappingEvaluatorParams<>();
params.setMappingTypes(outboundMappingBeans);
params.setMappingDesc("password mapping" + " in projection " + projCtxDesc);
params.setNow(now);
params.setInitializer(internalInitializer);
params.setProcessor(processor);
params.setTargetLoader(new ProjectionMappingLoader<>(projCtx, contextLoader));
params.setAPrioriTargetObject(shadowNew);
params.setAPrioriTargetDelta(LensUtil.findAPrioriDelta(context, projCtx));
params.setTargetContext(projCtx);
params.setDefaultTargetItemPath(SchemaConstants.PATH_PASSWORD_VALUE);
if (context.getFocusContext() != null) {
params.setSourceContext(context.getFocusContext().getObjectDeltaObjectAbsolute());
}
params.setEvaluateCurrent(MappingTimeEval.CURRENT);
params.setEvaluateWeak(evaluateWeak);
params.setContext(context);
params.setHasFullTargetObject(projCtx.hasFullShadow());
projectionMappingSetEvaluator.evaluateMappingsToTriples(params, task, result);
}
use of com.evolveum.midpoint.schema.processor.ResourceObjectDefinition in project midpoint by Evolveum.
the class ProjectionValuesProcessor method willResetIterationCounter.
private boolean willResetIterationCounter(LensProjectionContext projectionContext) throws SchemaException {
ObjectDelta<ShadowType> projectionDelta = projectionContext.getCurrentDelta();
if (projectionDelta == null) {
return false;
}
LOGGER.trace("willResetIterationCounter: projectionDelta is\n{}", projectionDelta.debugDumpLazily());
ResourceObjectDefinition oOcDef = projectionContext.getCompositeObjectDefinition();
for (ResourceAttributeDefinition<?> identifierDef : oOcDef.getPrimaryIdentifiers()) {
ItemPath identifierPath = ItemPath.create(ShadowType.F_ATTRIBUTES, identifierDef.getItemName());
if (projectionDelta.findPropertyDelta(identifierPath) != null) {
return true;
}
}
for (ResourceAttributeDefinition<?> identifierDef : oOcDef.getSecondaryIdentifiers()) {
ItemPath identifierPath = ItemPath.create(ShadowType.F_ATTRIBUTES, identifierDef.getItemName());
if (projectionDelta.findPropertyDelta(identifierPath) != null) {
return true;
}
}
return false;
}
use of com.evolveum.midpoint.schema.processor.ResourceObjectDefinition in project midpoint by Evolveum.
the class TestAssignmentErrors method test010RefinedSchemaWhite.
@Test
public void test010RefinedSchemaWhite() throws Exception {
// GIVEN
// WHEN
PrismObject<ResourceType> resourceWhite = getObject(ResourceType.class, RESOURCE_DUMMY_WHITE_OID);
ResourceSchema refinedSchema = ResourceSchemaFactory.getCompleteSchema(resourceWhite);
displayDumpable("Refined schema", refinedSchema);
ResourceObjectDefinition accountDef = refinedSchema.findObjectDefinition(ShadowKindType.ACCOUNT, null);
// This is an object class definition, as this resource has no schema handling defined
assertNotNull("Account definition is missing", accountDef);
assertNotNull("Null identifiers in account", accountDef.getPrimaryIdentifiers());
assertFalse("Empty identifiers in account", accountDef.getPrimaryIdentifiers().isEmpty());
assertNotNull("Null secondary identifiers in account", accountDef.getSecondaryIdentifiers());
assertFalse("Empty secondary identifiers in account", accountDef.getSecondaryIdentifiers().isEmpty());
assertNotNull("No naming attribute in account", accountDef.getNamingAttribute());
assertFalse("No nativeObjectClass in account", StringUtils.isEmpty(accountDef.getObjectClassDefinition().getNativeObjectClass()));
assertFalse("Account definition is deprecated", accountDef.isDeprecated());
assertFalse("Account definition in auxiliary", accountDef.getObjectClassDefinition().isAuxiliary());
ResourceAttributeDefinition<?> uidDef = accountDef.findAttributeDefinition(SchemaConstants.ICFS_UID);
assertEquals(1, uidDef.getMaxOccurs());
assertEquals(0, uidDef.getMinOccurs());
assertFalse("No UID display name", StringUtils.isBlank(uidDef.getDisplayName()));
assertFalse("UID has create", uidDef.canAdd());
assertFalse("UID has update", uidDef.canModify());
assertTrue("No UID read", uidDef.canRead());
assertTrue("UID definition not in identifiers", accountDef.getPrimaryIdentifiers().contains(uidDef));
ResourceAttributeDefinition<?> nameDef = accountDef.findAttributeDefinition(SchemaConstants.ICFS_NAME);
assertEquals(1, nameDef.getMaxOccurs());
assertEquals(1, nameDef.getMinOccurs());
assertFalse("No NAME displayName", StringUtils.isBlank(nameDef.getDisplayName()));
assertTrue("No NAME create", nameDef.canAdd());
assertTrue("No NAME update", nameDef.canModify());
assertTrue("No NAME read", nameDef.canRead());
assertTrue("NAME definition not in identifiers", accountDef.getSecondaryIdentifiers().contains(nameDef));
ResourceAttributeDefinition<?> fullnameDef = accountDef.findAttributeDefinition("fullname");
assertNotNull("No definition for fullname", fullnameDef);
assertEquals(1, fullnameDef.getMaxOccurs());
assertEquals(1, fullnameDef.getMinOccurs());
assertTrue("No fullname create", fullnameDef.canAdd());
assertTrue("No fullname update", fullnameDef.canModify());
assertTrue("No fullname read", fullnameDef.canRead());
assertNull("The _PASSSWORD_ attribute sneaked into schema", accountDef.findAttributeDefinition(new QName(SchemaConstants.NS_ICF_SCHEMA, "password")));
}
use of com.evolveum.midpoint.schema.processor.ResourceObjectDefinition in project midpoint by Evolveum.
the class TestSecurityBasic method test255AutzJackSelfAccountsReadWrite.
@Test
public void test255AutzJackSelfAccountsReadWrite() throws Exception {
given();
cleanupAutzTest(USER_JACK_OID);
assignRole(USER_JACK_OID, ROLE_SELF_ACCOUNTS_READ_WRITE_OID);
assignAccountToUser(USER_JACK_OID, RESOURCE_DUMMY_OID, null);
assumeAssignmentPolicy(AssignmentPolicyEnforcementType.NONE);
when();
login(USER_JACK_USERNAME);
then();
assertGetAllow(UserType.class, USER_JACK_OID);
assertGetDeny(UserType.class, USER_GUYBRUSH_OID);
assertAddDeny();
assertModifyAllow(UserType.class, USER_JACK_OID, UserType.F_HONORIFIC_PREFIX, PrismTestUtil.createPolyString("Captain"));
assertModifyDeny(UserType.class, USER_GUYBRUSH_OID, UserType.F_HONORIFIC_PREFIX, PrismTestUtil.createPolyString("Pirate"));
assertDeleteDeny();
assertDeleteDeny(UserType.class, USER_JACK_OID);
PrismObject<UserType> user = getUser(USER_JACK_OID);
String accountOid = getSingleLinkOid(user);
assertGetAllow(ShadowType.class, accountOid);
PrismObject<ShadowType> shadow = getObject(ShadowType.class, accountOid);
display("Jack's shadow", shadow);
Task task = getTestTask();
ResourceObjectDefinition rOcDef = modelInteractionService.getEditObjectClassDefinition(shadow, getDummyResourceObject(), null, task, task.getResult());
displayDumpable("Refined objectclass def", rOcDef);
assertAttributeFlags(rOcDef, SchemaConstants.ICFS_UID, true, false, false);
assertAttributeFlags(rOcDef, SchemaConstants.ICFS_NAME, true, true, true);
// Not linked to jack
assertGetDeny(ShadowType.class, ACCOUNT_SHADOW_ELAINE_DUMMY_OID);
// Not linked to jack
assertAddDeny(ACCOUNT_JACK_DUMMY_RED_FILE);
// Not even jack's account
assertAddDeny(ACCOUNT_GUYBRUSH_DUMMY_FILE);
// Linked to jack
assertAllow("add jack's account to jack", (t, result) -> modifyUserAddAccount(USER_JACK_OID, ACCOUNT_JACK_DUMMY_RED_FILE, t, result));
user = getUser(USER_JACK_OID);
display("Jack after red account link", user);
String accountRedOid = getLiveLinkRefOid(user, RESOURCE_DUMMY_RED_OID);
assertNotNull("Strange, red account not linked to jack", accountRedOid);
// Linked to other user
assertDeny("add gyubrush's account", (t, result) -> modifyUserAddAccount(USER_LARGO_OID, ACCOUNT_HERMAN_DUMMY_FILE, t, result));
assertDeleteAllow(ShadowType.class, accountRedOid);
assertDeleteDeny(ShadowType.class, ACCOUNT_SHADOW_ELAINE_DUMMY_OID);
assertGlobalStateUntouched();
}
Aggregations