From f323091f96bb76d2abb2ad80f1850bf2c40dcbec Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Thu, 12 Mar 2020 20:28:05 +0100 Subject: [PATCH 1/5] RObjectDeltaOperation#fromRepo methods marked with @NotNull --- .../sql/data/audit/RObjectDeltaOperation.java | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/audit/RObjectDeltaOperation.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/audit/RObjectDeltaOperation.java index 12aec8e13b7..17192aa3255 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/audit/RObjectDeltaOperation.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/audit/RObjectDeltaOperation.java @@ -7,6 +7,14 @@ package com.evolveum.midpoint.repo.sql.data.audit; +import static com.evolveum.midpoint.repo.sql.data.audit.RObjectDeltaOperation.COLUMN_RECORD_ID; + +import java.sql.ResultSet; +import javax.persistence.*; + +import org.hibernate.annotations.ForeignKey; +import org.jetbrains.annotations.NotNull; + import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.polystring.PolyString; @@ -28,17 +36,6 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; -import org.hibernate.annotations.ForeignKey; - -import javax.persistence.*; - -import static com.evolveum.midpoint.repo.sql.data.audit.RObjectDeltaOperation.COLUMN_RECORD_ID; - -import java.sql.ResultSet; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - /** * @author lazyman */ @@ -46,7 +43,7 @@ @Entity @IdClass(RObjectDeltaOperationId.class) @Table(name = RObjectDeltaOperation.TABLE_NAME, indexes = { - @Index(name = "iAuditDeltaRecordId", columnList = COLUMN_RECORD_ID)}) + @Index(name = "iAuditDeltaRecordId", columnList = COLUMN_RECORD_ID) }) public class RObjectDeltaOperation implements OperationResultFull, EntityState { private static final long serialVersionUID = -1065600513263271161L; @@ -86,7 +83,6 @@ public class RObjectDeltaOperation implements OperationResultFull, EntityState { private String resourceOid; private RPolyString resourceName; - @ForeignKey(name = "none") @MapsId("record") @ManyToOne(fetch = FetchType.LAZY) @@ -265,7 +261,7 @@ public int hashCode() { } public static RObjectDeltaOperation toRepo(RAuditEventRecord record, ObjectDeltaOperation operation, - PrismContext prismContext) throws DtoTranslationException { + PrismContext prismContext) throws DtoTranslationException { RObjectDeltaOperation auditDelta = new RObjectDeltaOperation(); auditDelta.setRecord(record); @@ -294,7 +290,6 @@ public static RObjectDeltaOperation toRepo(RAuditEventRecord record, ObjectDelta throw new DtoTranslationException(ex.getMessage(), ex); } - return auditDelta; } @@ -339,7 +334,7 @@ public static SingleSqlQuery toRepo(Long recordId, ObjectDeltaOperation operatio queryBuilder.addNullParameter(STATUS_COLUMN_NAME); queryBuilder.addNullParameter(FULL_RESULT_COLUMN_NAME); } - if(operation.getObjectName() != null) { + if (operation.getObjectName() != null) { queryBuilder.addParameter(OBJECT_NAME_ORIG_COLUMN_NAME, operation.getObjectName().getOrig()); queryBuilder.addParameter(OBJECT_NAME_NORM_COLUMN_NAME, operation.getObjectName().getNorm()); } else { @@ -347,7 +342,7 @@ public static SingleSqlQuery toRepo(Long recordId, ObjectDeltaOperation operatio queryBuilder.addNullParameter(OBJECT_NAME_NORM_COLUMN_NAME); } queryBuilder.addParameter(RESOURCE_OID_COLUMN_NAME, operation.getResourceOid()); - if(operation.getResourceName() != null) { + if (operation.getResourceName() != null) { queryBuilder.addParameter(RESOURCE_NAME_ORIG_COLUMN_NAME, operation.getResourceName().getOrig()); queryBuilder.addParameter(RESOURCE_NAME_NORM_COLUMN_NAME, operation.getResourceName().getNorm()); } else { @@ -359,10 +354,10 @@ public static SingleSqlQuery toRepo(Long recordId, ObjectDeltaOperation operatio throw new DtoTranslationException(ex.getMessage(), ex); } - return queryBuilder.build(); } + @NotNull public static ObjectDeltaOperation fromRepo(RObjectDeltaOperation operation, PrismContext prismContext, boolean useUtf16) throws DtoTranslationException { @@ -392,6 +387,7 @@ public static ObjectDeltaOperation fromRepo(RObjectDeltaOperation operation, Pri return odo; } + @NotNull public static ObjectDeltaOperation fromRepo(ResultSet resultSet, PrismContext prismContext, boolean useUtf16) throws DtoTranslationException { @@ -411,11 +407,11 @@ public static ObjectDeltaOperation fromRepo(ResultSet resultSet, PrismContext pr OperationResultType resultType = prismContext.parserFor(xmlResult).parseRealValue(OperationResultType.class); odo.setExecutionResult(OperationResult.createOperationResult(resultType)); } - if(resultSet.getString(OBJECT_NAME_ORIG_COLUMN_NAME) != null || resultSet.getString(OBJECT_NAME_NORM_COLUMN_NAME) != null) { + if (resultSet.getString(OBJECT_NAME_ORIG_COLUMN_NAME) != null || resultSet.getString(OBJECT_NAME_NORM_COLUMN_NAME) != null) { odo.setObjectName(new PolyString(resultSet.getString(OBJECT_NAME_ORIG_COLUMN_NAME), resultSet.getString(OBJECT_NAME_NORM_COLUMN_NAME))); } odo.setResourceOid(resultSet.getString(RESOURCE_OID_COLUMN_NAME)); - if(resultSet.getString(RESOURCE_NAME_ORIG_COLUMN_NAME) != null || resultSet.getString(RESOURCE_NAME_NORM_COLUMN_NAME) != null) { + if (resultSet.getString(RESOURCE_NAME_ORIG_COLUMN_NAME) != null || resultSet.getString(RESOURCE_NAME_NORM_COLUMN_NAME) != null) { odo.setResourceName(new PolyString(resultSet.getString(RESOURCE_NAME_ORIG_COLUMN_NAME), resultSet.getString(RESOURCE_NAME_NORM_COLUMN_NAME))); } } catch (Exception ex) { @@ -424,5 +420,4 @@ public static ObjectDeltaOperation fromRepo(ResultSet resultSet, PrismContext pr return odo; } - } From cff4d1450ec6124f4447a564fa230705f2fcf7e3 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Thu, 12 Mar 2020 20:29:06 +0100 Subject: [PATCH 2/5] MID-5893: DashboardServiceImpl: fixed select count(*) with bad space Also: renamed combinate->combine + more more diamonds --- .../impl/controller/DashboardServiceImpl.java | 112 +++++++----------- 1 file changed, 45 insertions(+), 67 deletions(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/DashboardServiceImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/DashboardServiceImpl.java index 85e8aff8d71..1cbe91c0989 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/DashboardServiceImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/DashboardServiceImpl.java @@ -8,11 +8,7 @@ import static com.evolveum.midpoint.model.api.util.DashboardUtils.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; @@ -41,27 +37,10 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.task.api.TaskManager; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -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.*; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AuditSearchType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.DashboardWidgetDataFieldTypeType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.DashboardWidgetPresentationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.DashboardWidgetSourceTypeType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.DashboardWidgetType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.DashboardWidgetVariationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.DisplayType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.IconType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.IntegerStatType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectCollectionType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType; /** @@ -99,77 +78,77 @@ public DashboardWidget createWidgetData(DashboardWidgetType widget, Task task, O return data; } - private DisplayType combinateDisplay(DisplayType display, DisplayType variationDisplay) { - DisplayType combinatedDisplay = new DisplayType(); + private DisplayType combineDisplay(DisplayType display, DisplayType variationDisplay) { + DisplayType combinedDisplay = new DisplayType(); if (variationDisplay == null) { return display; } - if(display == null) { + if (display == null) { return variationDisplay; } - if(StringUtils.isBlank(variationDisplay.getColor())) { - combinatedDisplay.setColor(display.getColor()); + if (StringUtils.isBlank(variationDisplay.getColor())) { + combinedDisplay.setColor(display.getColor()); } else { - combinatedDisplay.setColor(variationDisplay.getColor()); + combinedDisplay.setColor(variationDisplay.getColor()); } - if(StringUtils.isBlank(variationDisplay.getCssClass())) { - combinatedDisplay.setCssClass(display.getCssClass()); + if (StringUtils.isBlank(variationDisplay.getCssClass())) { + combinedDisplay.setCssClass(display.getCssClass()); } else { - combinatedDisplay.setCssClass(variationDisplay.getCssClass()); + combinedDisplay.setCssClass(variationDisplay.getCssClass()); } - if(StringUtils.isBlank(variationDisplay.getCssStyle())) { - combinatedDisplay.setCssStyle(display.getCssStyle()); + if (StringUtils.isBlank(variationDisplay.getCssStyle())) { + combinedDisplay.setCssStyle(display.getCssStyle()); } else { - combinatedDisplay.setCssStyle(variationDisplay.getCssStyle()); + combinedDisplay.setCssStyle(variationDisplay.getCssStyle()); } - if(variationDisplay.getHelp() == null) { - combinatedDisplay.setHelp(display.getHelp()); + if (variationDisplay.getHelp() == null) { + combinedDisplay.setHelp(display.getHelp()); } else { - combinatedDisplay.setHelp(variationDisplay.getHelp()); + combinedDisplay.setHelp(variationDisplay.getHelp()); } - if(variationDisplay.getLabel() == null) { - combinatedDisplay.setLabel(display.getLabel()); + if (variationDisplay.getLabel() == null) { + combinedDisplay.setLabel(display.getLabel()); } else { - combinatedDisplay.setLabel(variationDisplay.getLabel()); + combinedDisplay.setLabel(variationDisplay.getLabel()); } - if(variationDisplay.getSingularLabel() == null) { - combinatedDisplay.setSingularLabel(display.getSingularLabel()); + if (variationDisplay.getSingularLabel() == null) { + combinedDisplay.setSingularLabel(display.getSingularLabel()); } else { - combinatedDisplay.setSingularLabel(variationDisplay.getSingularLabel()); + combinedDisplay.setSingularLabel(variationDisplay.getSingularLabel()); } - if(variationDisplay.getPluralLabel() == null) { - combinatedDisplay.setPluralLabel(display.getPluralLabel()); + if (variationDisplay.getPluralLabel() == null) { + combinedDisplay.setPluralLabel(display.getPluralLabel()); } else { - combinatedDisplay.setPluralLabel(variationDisplay.getPluralLabel()); + combinedDisplay.setPluralLabel(variationDisplay.getPluralLabel()); } - if(variationDisplay.getTooltip() == null) { - combinatedDisplay.setTooltip(display.getTooltip()); + if (variationDisplay.getTooltip() == null) { + combinedDisplay.setTooltip(display.getTooltip()); } else { - combinatedDisplay.setTooltip(variationDisplay.getTooltip()); + combinedDisplay.setTooltip(variationDisplay.getTooltip()); } - if(variationDisplay.getIcon() == null) { - combinatedDisplay.setIcon(display.getIcon()); - } else if(display.getIcon() != null){ + if (variationDisplay.getIcon() == null) { + combinedDisplay.setIcon(display.getIcon()); + } else if (display.getIcon() != null) { IconType icon = new IconType(); - if(StringUtils.isBlank(variationDisplay.getIcon().getCssClass())) { + if (StringUtils.isBlank(variationDisplay.getIcon().getCssClass())) { icon.setCssClass(display.getIcon().getCssClass()); } else { icon.setCssClass(variationDisplay.getIcon().getCssClass()); } - if(StringUtils.isBlank(variationDisplay.getIcon().getColor())) { + if (StringUtils.isBlank(variationDisplay.getIcon().getColor())) { icon.setColor(display.getIcon().getColor()); } else { icon.setColor(variationDisplay.getIcon().getColor()); } - if(StringUtils.isBlank(variationDisplay.getIcon().getImageUrl())) { + if (StringUtils.isBlank(variationDisplay.getIcon().getImageUrl())) { icon.setImageUrl(display.getIcon().getImageUrl()); } else { icon.setImageUrl(variationDisplay.getIcon().getImageUrl()); } - combinatedDisplay.setIcon(icon); + combinedDisplay.setIcon(icon); } - return combinatedDisplay; + return combinedDisplay; } public DashboardWidgetSourceTypeType getSourceType(DashboardWidgetType widget) { @@ -227,7 +206,7 @@ private String generateNumberMessageForAuditSearch(DashboardWidgetType widget, D return null; } - Map parameters = new HashMap(); + Map parameters = new HashMap<>(); String query = getQueryForCount(createQuery(collection, parameters, false, clock)); LOGGER.debug("Parameters for select: " + parameters); @@ -237,7 +216,7 @@ private String generateNumberMessageForAuditSearch(DashboardWidgetType widget, D if(auditSearch.getDomainQuery() == null) { LOGGER.error("DomainQuery of auditSearch is not defined"); } else { - parameters = new HashMap(); + parameters = new HashMap<>(); query = getQueryForCount(createQuery(collection, parameters, true, clock)); LOGGER.debug("Parameters for select: " + parameters); @@ -251,7 +230,7 @@ private String generateNumberMessageForAuditSearch(DashboardWidgetType widget, D private String getQueryForCount(String query) { int index = query.toLowerCase().indexOf("from"); - query = "select count (*) " + query.substring(index); + query = "select count(*) " + query.substring(index); query = query.split("order")[0]; LOGGER.debug("Query for select: " + query); return query; @@ -273,7 +252,7 @@ private String generateNumberMessageForCollection(DashboardWidgetType widget, Da Collection evalPolicyRules = modelInteractionService.evaluateCollectionPolicyRules( valueCollection.asPrismObject(), compiledCollection, null, task, task.getResult()); - Collection policySituations = new ArrayList(); + Collection policySituations = new ArrayList<>(); for(EvaluatedPolicyRule evalPolicyRule : evalPolicyRules) { if(!evalPolicyRule.getAllTriggers().isEmpty()) { policySituations.add(evalPolicyRule.getPolicySituation()); @@ -317,7 +296,7 @@ private static IntegerStatType generateIntegerStat(Integer value, Integer domain } private String generateNumberMessage(DashboardWidgetType widget, ExpressionVariables variables, DashboardWidget data) { - Map numberMessagesParts = new HashMap(); + Map numberMessagesParts = new HashMap<>(); widget.getPresentation().getDataField().forEach(dataField -> { switch(dataField.getFieldType()) { @@ -375,7 +354,7 @@ private void evaluateVariation(DashboardWidgetType widget, ExpressionVariables v if(usingVariation != null && usingVariation.getRealValue() != null && usingVariation.getRealValue().equals(Boolean.TRUE)) { - data.setDisplay(combinateDisplay(widget.getDisplay(), variation.getDisplay())); + data.setDisplay(combineDisplay(widget.getDisplay(), variation.getDisplay())); } else { data.setDisplay(widget.getDisplay()); } @@ -416,8 +395,7 @@ public ObjectCollectionType getObjectCollectionType(DashboardWidgetType widget, return null; } ObjectReferenceType ref = widget.getData().getCollection().getCollectionRef(); - ObjectCollectionType collection = objectResolver.resolve(ref, ObjectCollectionType.class, null, "resolving collection from "+widget, task, result); - return collection; + return objectResolver.resolve(ref, ObjectCollectionType.class, null, "resolving collection from "+widget, task, result); } private ObjectType getObjectFromObjectRef(DashboardWidgetType widget, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { From 281baa7519e671fb5f838ae3f724522577de9c43 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Thu, 12 Mar 2020 21:27:21 +0100 Subject: [PATCH 3/5] MID-5893: SqlAuditServiceImpl: fixed select count(*) with bad space - session creation put just before try {, no localSession needed, as it's effectively final now - new Work()#execute replaced with lambda (long one, but still better) - and more code cleanup --- .../repo/sql/SqlAuditServiceImpl.java | 667 +++++++----------- 1 file changed, 267 insertions(+), 400 deletions(-) diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlAuditServiceImpl.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlAuditServiceImpl.java index 088e774f166..ce8736a8a57 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlAuditServiceImpl.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlAuditServiceImpl.java @@ -6,8 +6,32 @@ */ package com.evolveum.midpoint.repo.sql; -import com.evolveum.midpoint.audit.api.*; -import com.evolveum.midpoint.prism.PrismContext; +import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; + +import java.sql.*; +import java.util.Date; +import java.util.*; +import java.util.Map.Entry; +import java.util.function.BiFunction; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.xml.datatype.Duration; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import org.hibernate.FlushMode; +import org.hibernate.Session; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.engine.spi.RowSelection; +import org.hibernate.query.NativeQuery; +import org.hibernate.query.Query; +import org.springframework.beans.factory.annotation.Autowired; + +import com.evolveum.midpoint.audit.api.AuditEventRecord; +import com.evolveum.midpoint.audit.api.AuditReferenceValue; +import com.evolveum.midpoint.audit.api.AuditResultHandler; +import com.evolveum.midpoint.audit.api.AuditService; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; @@ -18,7 +42,6 @@ import com.evolveum.midpoint.repo.sql.data.SelectQueryBuilder; import com.evolveum.midpoint.repo.sql.data.SingleSqlQuery; import com.evolveum.midpoint.repo.sql.data.audit.*; -import com.evolveum.midpoint.repo.sql.data.common.enums.ROperationResultStatus; import com.evolveum.midpoint.repo.sql.data.common.other.RObjectType; import com.evolveum.midpoint.repo.sql.helpers.BaseHelper; import com.evolveum.midpoint.repo.sql.perf.SqlPerformanceMonitorImpl; @@ -28,48 +51,16 @@ import com.evolveum.midpoint.repo.sql.util.TemporaryTableDialect; import com.evolveum.midpoint.schema.ObjectDeltaOperation; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.Holder; -import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.exception.SchemaException; 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.CleanupPolicyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.EventStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultStatusType; import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; -import org.hibernate.FlushMode; -import org.hibernate.ScrollableResults; -import org.hibernate.Session; -import org.hibernate.dialect.Dialect; -import org.hibernate.dialect.pagination.LimitHandler; -import org.hibernate.engine.spi.RowSelection; -import org.hibernate.jdbc.Work; -import org.hibernate.query.NativeQuery; -import org.hibernate.query.Query; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.propertyeditors.CustomCollectionEditor; - -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.xml.datatype.Duration; -import javax.xml.datatype.XMLGregorianCalendar; - -import java.lang.reflect.InvocationTargetException; -import java.math.BigDecimal; -import java.sql.*; -import java.util.*; -import java.util.Date; -import java.util.Map.Entry; -import java.util.function.BiFunction; - -import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; /** * @author lazyman @@ -91,7 +82,7 @@ public class SqlAuditServiceImpl extends SqlBaseService implements AuditService private static final String QUERY_MAX_RESULT = "setMaxResults"; private static final String QUERY_FIRST_RESULT = "setFirstResult"; - private Map customColumn = new HashMap(); + private Map customColumn = new HashMap<>(); public SqlAuditServiceImpl(SqlRepositoryFactory repositoryFactory) { super(repositoryFactory); @@ -184,7 +175,6 @@ public void listRecordsIterative(String query, Map params, Audit } } - } @Override @@ -208,23 +198,17 @@ public void reindexEntry(AuditEventRecord record) { } private void reindexEntryAttempt(AuditEventRecord record) { - Session session = null; + Session session = baseHelper.beginTransaction(); try { - session = baseHelper.beginTransaction(); RAuditEventRecord reindexed = RAuditEventRecord.toRepo(record, getPrismContext(), null); //TODO FIXME temporary hack, merge will eventyually load the object to the session if there isn't one, // but in this case we force loading object because of "objectDeltaOperation". There is some problem probably // during serializing/deserializing which causes constraint violation on priamry key.. - Object o = session.load(RAuditEventRecord.class, record.getRepoId()); - - if (o instanceof RAuditEventRecord) { - RAuditEventRecord rRecord = (RAuditEventRecord) o; - rRecord.getChangedItems().clear(); - rRecord.getChangedItems().addAll(reindexed.getChangedItems()); - - session.merge(rRecord); - } + RAuditEventRecord rRecord = session.load(RAuditEventRecord.class, record.getRepoId()); + rRecord.getChangedItems().clear(); + rRecord.getChangedItems().addAll(reindexed.getChangedItems()); + session.merge(rRecord); session.getTransaction().commit(); @@ -239,164 +223,150 @@ private void reindexEntryAttempt(AuditEventRecord record) { } private void listRecordsIterativeAttempt(String query, Map params, - AuditResultHandler handler, OperationResult result) { - Session session = null; + AuditResultHandler handler, OperationResult result) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("List records attempt\n query: {}\n params:\n{}", query, DebugUtil.debugDump(params, 2)); } - session = baseHelper.beginReadOnlyTransaction(); - + Session session = baseHelper.beginReadOnlyTransaction(); try { - Session localSession = session; - session.doWork(new Work() { - - @Override - public void execute(Connection con) throws SQLException { - - Database database = baseHelper.getConfiguration().getDatabase(); - int count = 0; - String basicQuery = query; - if (StringUtils.isBlank(query)) { - basicQuery = "select * from m_audit_event " - + (database.equals(Database.ORACLE) ? "" : "as ") - + "aer where 1=1 order by aer.timestampValue desc"; - } - String deltaQuery = "select * from m_audit_delta " - + (database.equals(Database.ORACLE) ? "" : "as ") - + "delta where delta.record_id=?"; - String propertyQuery = "select * from m_audit_prop_value " - + (database.equals(Database.ORACLE) ? "" : "as ") - + "prop where prop.record_id=?"; - String refQuery = "select * from m_audit_ref_value " - + (database.equals(Database.ORACLE) ? "" : "as ") - + "ref where ref.record_id=?"; - String resourceQuery = "select * from m_audit_resource " - + (database.equals(Database.ORACLE) ? "" : "as ") - + "res where res.record_id=?"; - SelectQueryBuilder queryBuilder = new SelectQueryBuilder(database, basicQuery); - setParametersToQuery(queryBuilder, params); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("List records attempt\n processed query: {}", queryBuilder); - } - - PreparedStatement stmt = queryBuilder.build().createPreparedStatement(con); + session.doWork(con -> { + Database database = baseHelper.getConfiguration().getDatabase(); + int count = 0; + String basicQuery = query; + if (StringUtils.isBlank(query)) { + basicQuery = "select * from m_audit_event " + + (database.equals(Database.ORACLE) ? "" : "as ") + + "aer where 1=1 order by aer.timestampValue desc"; + } + String deltaQuery = "select * from m_audit_delta " + + (database.equals(Database.ORACLE) ? "" : "as ") + + "delta where delta.record_id=?"; + String propertyQuery = "select * from m_audit_prop_value " + + (database.equals(Database.ORACLE) ? "" : "as ") + + "prop where prop.record_id=?"; + String refQuery = "select * from m_audit_ref_value " + + (database.equals(Database.ORACLE) ? "" : "as ") + + "ref where ref.record_id=?"; + String resourceQuery = "select * from m_audit_resource " + + (database.equals(Database.ORACLE) ? "" : "as ") + + "res where res.record_id=?"; + SelectQueryBuilder queryBuilder = new SelectQueryBuilder(database, basicQuery); + setParametersToQuery(queryBuilder, params); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("List records attempt\n processed query: {}", queryBuilder); + } - ResultSet resultList = stmt.executeQuery(); - try { - while (resultList.next()) { + try (PreparedStatement stmt = queryBuilder.build().createPreparedStatement(con)) { + ResultSet resultList = stmt.executeQuery(); + while (resultList.next()) { - AuditEventRecord audit = RAuditEventRecord.fromRepo(resultList); - if(!customColumn.isEmpty()) { - for(Entry property : customColumn.entrySet()) { - audit.getCustomColumnProperty().put(property.getKey(), resultList.getString(property.getValue())); - } - } + AuditEventRecord audit = RAuditEventRecord.fromRepo(resultList); + if (!customColumn.isEmpty()) { + for (Entry property : customColumn.entrySet()) { + audit.getCustomColumnProperty().put(property.getKey(), resultList.getString(property.getValue())); + } + } - //query for deltas - PreparedStatement subStmt = con.prepareStatement(deltaQuery); - subStmt.setLong(1, resultList.getLong(RAuditEventRecord.ID_COLUMN_NAME)); - ResultSet subResultList = subStmt.executeQuery(); + //query for deltas + PreparedStatement subStmt = con.prepareStatement(deltaQuery); + subStmt.setLong(1, resultList.getLong(RAuditEventRecord.ID_COLUMN_NAME)); + ResultSet subResultList = subStmt.executeQuery(); - OperationResult deltaResult = result.createMinorSubresult(OP_LOAD_AUDIT_DELTA); + OperationResult deltaResult = result.createMinorSubresult(OP_LOAD_AUDIT_DELTA); + try { + while (subResultList.next()) { try { - while (subResultList.next()) { - try { - ObjectDeltaOperation odo = RObjectDeltaOperation.fromRepo(subResultList, getPrismContext(), getConfiguration().isUsingSQLServer()); - if (odo != null) { - audit.addDelta(odo); - } - } catch (DtoTranslationException ex) { - LOGGER.error("Cannot convert stored audit delta. Reason: {}", ex.getMessage(), ex); - deltaResult.recordPartialError("Cannot convert stored audit delta. Reason: " + ex.getMessage(), ex); - //do not throw an error. rather audit record without delta than fatal error. - continue; - } - - } - } finally { - subResultList.close(); - subStmt.close(); - deltaResult.computeStatus(); + ObjectDeltaOperation odo = RObjectDeltaOperation.fromRepo( + subResultList, getPrismContext(), getConfiguration().isUsingSQLServer()); + audit.addDelta(odo); + } catch (DtoTranslationException ex) { + LOGGER.error("Cannot convert stored audit delta. Reason: {}", ex.getMessage(), ex); + deltaResult.recordPartialError("Cannot convert stored audit delta. Reason: " + ex.getMessage(), ex); + //do not throw an error. rather audit record without delta than fatal error. } + } + } finally { + subResultList.close(); + subStmt.close(); + deltaResult.computeStatus(); + } - //query for properties - subStmt = con.prepareStatement(propertyQuery); - subStmt.setLong(1, resultList.getLong(RAuditEventRecord.ID_COLUMN_NAME)); - subResultList = subStmt.executeQuery(); - - try { - while (subResultList.next()) { - audit.addPropertyValue(subResultList.getString(RAuditPropertyValue.NAME_COLUMN_NAME), - subResultList.getString(RAuditPropertyValue.VALUE_COLUMN_NAME)); - } - } finally { - subResultList.close(); - subStmt.close(); - } + //query for properties + subStmt = con.prepareStatement(propertyQuery); + subStmt.setLong(1, resultList.getLong(RAuditEventRecord.ID_COLUMN_NAME)); + subResultList = subStmt.executeQuery(); - //query for references - subStmt = con.prepareStatement(refQuery); - subStmt.setLong(1, resultList.getLong(RAuditEventRecord.ID_COLUMN_NAME)); - subResultList = subStmt.executeQuery(); + try { + while (subResultList.next()) { + audit.addPropertyValue(subResultList.getString(RAuditPropertyValue.NAME_COLUMN_NAME), + subResultList.getString(RAuditPropertyValue.VALUE_COLUMN_NAME)); + } + } finally { + subResultList.close(); + subStmt.close(); + } - try { - while (subResultList.next()) { - audit.addReferenceValue(subResultList.getString(RAuditReferenceValue.NAME_COLUMN_NAME), - RAuditReferenceValue.fromRepo(subResultList)); - } - } finally { - subResultList.close(); - subStmt.close(); - } + //query for references + subStmt = con.prepareStatement(refQuery); + subStmt.setLong(1, resultList.getLong(RAuditEventRecord.ID_COLUMN_NAME)); + subResultList = subStmt.executeQuery(); - //query for target resource oids - subStmt = con.prepareStatement(resourceQuery); - subStmt.setLong(1, resultList.getLong(RAuditEventRecord.ID_COLUMN_NAME)); - subResultList = subStmt.executeQuery(); + try { + while (subResultList.next()) { + audit.addReferenceValue(subResultList.getString(RAuditReferenceValue.NAME_COLUMN_NAME), + RAuditReferenceValue.fromRepo(subResultList)); + } + } finally { + subResultList.close(); + subStmt.close(); + } - try { - while (subResultList.next()) { - audit.addResourceOid(subResultList.getString(RTargetResourceOid.RESOURCE_OID_COLUMN_NAME)); - } - } finally { - subResultList.close(); - subStmt.close(); - } + //query for target resource oids + subStmt = con.prepareStatement(resourceQuery); + subStmt.setLong(1, resultList.getLong(RAuditEventRecord.ID_COLUMN_NAME)); + subResultList = subStmt.executeQuery(); - try { - // TODO what if original name (in audit log) differs from the current one (in repo) ? - audit.setInitiator(resolve(localSession, resultList.getString(RAuditEventRecord.INITIATOR_OID_COLUMN_NAME), - resultList.getString(RAuditEventRecord.INITIATOR_NAME_COLUMN_NAME), - defaultIfNull(RObjectType.values()[resultList.getInt(RAuditEventRecord.INITIATOR_TYPE_COLUMN_NAME)], RObjectType.FOCUS))); - audit.setAttorney(resolve(localSession, resultList.getString(RAuditEventRecord.ATTORNEY_OID_COLUMN_NAME), - resultList.getString(RAuditEventRecord.ATTORNEY_NAME_COLUMN_NAME), RObjectType.FOCUS)); - audit.setTarget(resolve(localSession, resultList.getString(RAuditEventRecord.TARGET_OID_COLUMN_NAME), - resultList.getString(RAuditEventRecord.TARGET_NAME_COLUMN_NAME), - RObjectType.values()[resultList.getInt(RAuditEventRecord.TARGET_TYPE_COLUMN_NAME)]), getPrismContext()); - audit.setTargetOwner(resolve(localSession, resultList.getString(RAuditEventRecord.TARGET_OWNER_OID_COLUMN_NAME), - resultList.getString(RAuditEventRecord.TARGET_OWNER_NAME_COLUMN_NAME), - RObjectType.values()[resultList.getInt(RAuditEventRecord.TARGET_OWNER_TYPE_COLUMN_NAME)])); - } catch (SchemaException ex) { - baseHelper.handleGeneralCheckedException(ex, localSession, null); - } - count++; - if (!handler.handle(audit)) { - LOGGER.trace("Skipping handling of objects after {} was handled. ", audit); - break; - } + try { + while (subResultList.next()) { + audit.addResourceOid(subResultList.getString(RTargetResourceOid.RESOURCE_OID_COLUMN_NAME)); } - }finally { - stmt.close(); - result.computeStatus(); + } finally { + subResultList.close(); + subStmt.close(); } -// - LOGGER.trace("List records iterative attempt processed {} records", count); + try { + // TODO what if original name (in audit log) differs from the current one (in repo) ? + audit.setInitiator(resolve(session, resultList.getString(RAuditEventRecord.INITIATOR_OID_COLUMN_NAME), + resultList.getString(RAuditEventRecord.INITIATOR_NAME_COLUMN_NAME), + defaultIfNull(RObjectType.values()[resultList.getInt(RAuditEventRecord.INITIATOR_TYPE_COLUMN_NAME)], RObjectType.FOCUS))); + audit.setAttorney(resolve(session, resultList.getString(RAuditEventRecord.ATTORNEY_OID_COLUMN_NAME), + resultList.getString(RAuditEventRecord.ATTORNEY_NAME_COLUMN_NAME), RObjectType.FOCUS)); + audit.setTarget(resolve(session, resultList.getString(RAuditEventRecord.TARGET_OID_COLUMN_NAME), + resultList.getString(RAuditEventRecord.TARGET_NAME_COLUMN_NAME), + RObjectType.values()[resultList.getInt(RAuditEventRecord.TARGET_TYPE_COLUMN_NAME)]), getPrismContext()); + audit.setTargetOwner(resolve(session, resultList.getString(RAuditEventRecord.TARGET_OWNER_OID_COLUMN_NAME), + resultList.getString(RAuditEventRecord.TARGET_OWNER_NAME_COLUMN_NAME), + RObjectType.values()[resultList.getInt(RAuditEventRecord.TARGET_OWNER_TYPE_COLUMN_NAME)])); + } catch (SchemaException ex) { + baseHelper.handleGeneralCheckedException(ex, session, null); + } + count++; + if (!handler.handle(audit)) { + LOGGER.trace("Skipping handling of objects after {} was handled. ", audit); + break; + } + } + } finally { + result.computeStatus(); } + +// + LOGGER.trace("List records iterative attempt processed {} records", count); }); session.getTransaction().commit(); @@ -408,87 +378,28 @@ public void execute(Connection con) throws SQLException { } - private void setParametersToQuery(Query q, Map params) { - if (params == null) { - return; - } - - if (params.containsKey("setFirstResult")) { - q.setFirstResult((int) params.get("setFirstResult")); - params.remove("setFirstResult"); - } - if (params.containsKey("setMaxResults")) { - q.setMaxResults((int) params.get("setMaxResults")); - params.remove("setMaxResults"); - } - Set> paramSet = params.entrySet(); - for (Entry p : paramSet) { - if (p.getValue() == null) { - q.setParameter(p.getKey(), null); - continue; - } - - if (List.class.isAssignableFrom(p.getValue().getClass())) { - q.setParameterList(p.getKey(), convertValues((List) p.getValue())); - } else { - q.setParameter(p.getKey(), toRepoType(p.getValue())); - } -// if (XMLGregorianCalendar.class.isAssignableFrom(p.getValue().getClass())) { -// q.setParameter(p.getKey(), MiscUtil.asDate((XMLGregorianCalendar) p.getValue())); -// } else if (p.getValue() instanceof AuditEventType) { -// q.setParameter(p.getKey(), RAuditEventType.toRepo((AuditEventType) p.getValue())); -// } else if (p.getValue() instanceof AuditEventStage) { -// q.setParameter(p.getKey(), RAuditEventStage.toRepo((AuditEventStage) p.getValue())); -// } else { -// q.setParameter(p.getKey(), p.getValue()); -// } - } - } - private void setParametersToQuery(SelectQueryBuilder queryBuilder, Map params) { if (params == null) { return; } if (params.containsKey(QUERY_FIRST_RESULT)) { - queryBuilder.setFirstResult((int)params.get(QUERY_FIRST_RESULT)); + queryBuilder.setFirstResult((int) params.get(QUERY_FIRST_RESULT)); params.remove(QUERY_FIRST_RESULT); } if (params.containsKey(QUERY_MAX_RESULT)) { - queryBuilder.setMaxResult((int)params.get(QUERY_MAX_RESULT)); + queryBuilder.setMaxResult((int) params.get(QUERY_MAX_RESULT)); params.remove(QUERY_MAX_RESULT); } queryBuilder.addParameters(params); } - private List convertValues(List originValues) { - List repoValues = new ArrayList<>(); - for (Object value : originValues) { - repoValues.add(toRepoType(value)); - } - return repoValues; - } - - private Object toRepoType(Object value) { - if (XMLGregorianCalendar.class.isAssignableFrom(value.getClass())) { - return MiscUtil.asDate((XMLGregorianCalendar) value); - } else if (value instanceof AuditEventType) { - return RAuditEventType.toRepo((AuditEventType) value); - } else if (value instanceof AuditEventStage) { - return RAuditEventStage.toRepo((AuditEventStage) value); - } else if (value instanceof OperationResultStatusType) { - return ROperationResultStatus.toRepo((OperationResultStatusType) value); - } - - return value; - } - // using generic parameter to avoid typing warnings private PrismObject resolve(Session session, String oid, String defaultName, RObjectType defaultType) throws SchemaException { if (oid == null) { return null; } - Query query = session.getNamedQuery("get.object"); + Query query = session.getNamedQuery("get.object"); query.setParameter("oid", oid); query.setResultTransformer(GetObjectResult.RESULT_STYLE.getResultTransformer()); GetObjectResult object = (GetObjectResult) query.uniqueResult(); @@ -509,108 +420,95 @@ private PrismObject resolve(Session session, String oi } private void auditAttempt(AuditEventRecord record) { - Session session = null; + Session session = baseHelper.beginTransaction(); try { - session = baseHelper.beginTransaction(); -// RAuditEventRecord newRecord = RAuditEventRecord.toRepo(record, getPrismContext(), true); -// session.save(newRecord); SingleSqlQuery query = RAuditEventRecord.toRepo(record, customColumn); - Session localSession = session; - session.doWork(new Work() { - - @Override - public void execute(Connection connection) throws SQLException { - Database database = getConfiguration().getDatabase(); - String[] keyColumn = {RAuditEventRecord.ID_COLUMN_NAME}; - PreparedStatement smtp = query.createPreparedStatement(connection, keyColumn); - Long id = null; - try { - smtp.executeUpdate(); - ResultSet resultSet = smtp.getGeneratedKeys(); + session.doWork(connection -> { + Database database = getConfiguration().getDatabase(); + String[] keyColumn = { RAuditEventRecord.ID_COLUMN_NAME }; + PreparedStatement smtp = query.createPreparedStatement(connection, keyColumn); + Long id = null; + try { + smtp.executeUpdate(); + ResultSet resultSet = smtp.getGeneratedKeys(); - if (resultSet.next()) { - id = resultSet.getLong(1); + if (resultSet.next()) { + id = resultSet.getLong(1); - } - } finally { - smtp.close(); } - if(id == null) { - throw new IllegalArgumentException("Returned id of new record is null"); - } - - - BatchSqlQuery deltaBatchQuery = new BatchSqlQuery(database); - BatchSqlQuery itemBatchQuery = new BatchSqlQuery(database); + } finally { + smtp.close(); + } + if (id == null) { + throw new IllegalArgumentException("Returned id of new record is null"); + } - for (ObjectDeltaOperation delta : record.getDeltas()) { - if (delta == null) { - continue; - } + BatchSqlQuery deltaBatchQuery = new BatchSqlQuery(database); + BatchSqlQuery itemBatchQuery = new BatchSqlQuery(database); - ObjectDelta objectDelta = delta.getObjectDelta(); - for (ItemDelta itemDelta : objectDelta.getModifications()) { - ItemPath path = itemDelta.getPath(); - if (path != null) { // TODO what if empty? - CanonicalItemPath canonical = getPrismContext().createCanonicalItemPath(path, objectDelta.getObjectTypeClass()); - for (int i = 0; i < canonical.size(); i++) { + for (ObjectDeltaOperation delta : record.getDeltas()) { + if (delta == null) { + continue; + } - SingleSqlQuery itemQuery = RAuditItem.toRepo(id, canonical.allUpToIncluding(i).asString()); -// changedItem.setTransient(true); - itemBatchQuery.addQueryForBatch(itemQuery); - } - } - } + ObjectDelta objectDelta = delta.getObjectDelta(); + for (ItemDelta itemDelta : objectDelta.getModifications()) { + ItemPath path = itemDelta.getPath(); + CanonicalItemPath canonical = getPrismContext().createCanonicalItemPath(path, objectDelta.getObjectTypeClass()); + for (int i = 0; i < canonical.size(); i++) { - SingleSqlQuery deltaQuery; - try { - deltaQuery = RObjectDeltaOperation.toRepo(id, delta, getPrismContext()); - deltaBatchQuery.addQueryForBatch(deltaQuery); - } catch (DtoTranslationException e) { - baseHelper.handleGeneralCheckedException(e, localSession, null); + SingleSqlQuery itemQuery = RAuditItem.toRepo(id, canonical.allUpToIncluding(i).asString()); + itemBatchQuery.addQueryForBatch(itemQuery); } -// rDelta.setTransient(true); - } - if(!deltaBatchQuery.isEmpty()) { - deltaBatchQuery.execute(connection); } - if(!itemBatchQuery.isEmpty()) { - itemBatchQuery.execute(connection); + + SingleSqlQuery deltaQuery; + try { + deltaQuery = RObjectDeltaOperation.toRepo(id, delta, getPrismContext()); + deltaBatchQuery.addQueryForBatch(deltaQuery); + } catch (DtoTranslationException e) { + baseHelper.handleGeneralCheckedException(e, session, null); } + } + if (!deltaBatchQuery.isEmpty()) { + deltaBatchQuery.execute(connection); + } + if (!itemBatchQuery.isEmpty()) { + itemBatchQuery.execute(connection); + } - BatchSqlQuery propertyBatchQuery = new BatchSqlQuery(database); - for (Map.Entry> propertyEntry : record.getProperties().entrySet()) { - for (String propertyValue : propertyEntry.getValue()) { - SingleSqlQuery propertyQuery = RAuditPropertyValue.toRepo( - id, propertyEntry.getKey(), RUtil.trimString(propertyValue, AuditService.MAX_PROPERTY_SIZE)); + BatchSqlQuery propertyBatchQuery = new BatchSqlQuery(database); + for (Entry> propertyEntry : record.getProperties().entrySet()) { + for (String propertyValue : propertyEntry.getValue()) { + SingleSqlQuery propertyQuery = RAuditPropertyValue.toRepo( + id, propertyEntry.getKey(), RUtil.trimString(propertyValue, AuditService.MAX_PROPERTY_SIZE)); // val.setTransient(isTransient); - propertyBatchQuery.addQueryForBatch(propertyQuery); - } - } - if(!propertyBatchQuery.isEmpty()) { - propertyBatchQuery.execute(connection); + propertyBatchQuery.addQueryForBatch(propertyQuery); } + } + if (!propertyBatchQuery.isEmpty()) { + propertyBatchQuery.execute(connection); + } - BatchSqlQuery referenceBatchQuery = new BatchSqlQuery(database); - for (Map.Entry> referenceEntry : record.getReferences().entrySet()) { - for (AuditReferenceValue referenceValue : referenceEntry.getValue()) { - SingleSqlQuery referenceQuery = RAuditReferenceValue.toRepo(id, referenceEntry.getKey(), referenceValue); + BatchSqlQuery referenceBatchQuery = new BatchSqlQuery(database); + for (Entry> referenceEntry : record.getReferences().entrySet()) { + for (AuditReferenceValue referenceValue : referenceEntry.getValue()) { + SingleSqlQuery referenceQuery = RAuditReferenceValue.toRepo(id, referenceEntry.getKey(), referenceValue); // val.setTransient(isTransient); - referenceBatchQuery.addQueryForBatch(referenceQuery); - } - } - if(!referenceBatchQuery.isEmpty()) { - referenceBatchQuery.execute(connection); + referenceBatchQuery.addQueryForBatch(referenceQuery); } + } + if (!referenceBatchQuery.isEmpty()) { + referenceBatchQuery.execute(connection); + } - BatchSqlQuery resourceOidBatchQuery = new BatchSqlQuery(database); - for (String resourceOid : record.getResourceOids()) { - SingleSqlQuery resourceOidQuery = RTargetResourceOid.toRepo(id, resourceOid); - resourceOidBatchQuery.addQueryForBatch(resourceOidQuery); - } - if(!resourceOidBatchQuery.isEmpty()) { - resourceOidBatchQuery.execute(connection); - } + BatchSqlQuery resourceOidBatchQuery = new BatchSqlQuery(database); + for (String resourceOid : record.getResourceOids()) { + SingleSqlQuery resourceOidQuery = RTargetResourceOid.toRepo(id, resourceOid); + resourceOidBatchQuery.addQueryForBatch(resourceOidQuery); + } + if (!resourceOidBatchQuery.isEmpty()) { + resourceOidBatchQuery.execute(connection); } }); @@ -757,12 +655,10 @@ private void checkTemporaryTablesSupport(Dialect dialect) { // deletes one batch of records (using recordsSelector to select records according to particular cleanup policy) private int batchDeletionAttempt(BiFunction recordsSelector, Holder totalCountHolder, - long batchStart, Dialect dialect, OperationResult subResult) { + long batchStart, Dialect dialect, OperationResult subResult) { - Session session = null; + Session session = baseHelper.beginTransaction(); try { - session = baseHelper.beginTransaction(); - TemporaryTableDialect ttDialect = TemporaryTableDialect.getTempTableDialect(dialect); // create temporary table @@ -790,11 +686,10 @@ private int batchDeletionAttempt(BiFunction recordsSel // drop temporary table if (ttDialect.dropTemporaryTableAfterUse()) { LOGGER.debug("Dropping temporary table."); - StringBuilder sb = new StringBuilder(); - sb.append(ttDialect.getDropTemporaryTableString()); - sb.append(' ').append(tempTable); - session.createNativeQuery(sb.toString()).executeUpdate(); + String sb = ttDialect.getDropTemporaryTableString() + + ' ' + tempTable; + session.createNativeQuery(sb).executeUpdate(); } session.getTransaction().commit(); @@ -817,10 +712,8 @@ private int selectRecordsByMaxAge(Session session, String tempTable, Date minVal // fill temporary table, we don't need to join task on object on // container, oid and id is already in task table - StringBuilder selectSB = new StringBuilder(); - selectSB.append("select a.id as id from ").append(RAuditEventRecord.TABLE_NAME).append(" a"); - selectSB.append(" where a.").append(RAuditEventRecord.COLUMN_TIMESTAMP).append(" < ###TIME###"); - String selectString = selectSB.toString(); + String selectString = "select a.id as id from " + RAuditEventRecord.TABLE_NAME + " a" + + " where a." + RAuditEventRecord.COLUMN_TIMESTAMP + " < ###TIME###"; // batch size RowSelection rowSelection = new RowSelection(); @@ -861,10 +754,8 @@ private int selectRecordsByNumberToKeep(Session session, String tempTable, Integ return 0; } - StringBuilder selectSB = new StringBuilder(); - selectSB.append("select a.id as id from ").append(RAuditEventRecord.TABLE_NAME).append(" a"); - selectSB.append(" order by a.").append(RAuditEventRecord.COLUMN_TIMESTAMP).append(" asc"); - String selectString = selectSB.toString(); + String selectString = "select a.id as id from " + RAuditEventRecord.TABLE_NAME + " a" + + " order by a." + RAuditEventRecord.COLUMN_TIMESTAMP + " asc"; // batch size RowSelection rowSelection = new RowSelection(); @@ -881,10 +772,6 @@ private int selectRecordsByNumberToKeep(Session session, String tempTable, Integ /** * This method creates temporary table for cleanup audit method. - * - * @param session - * @param dialect - * @param tempTable */ private void createTemporaryTable(Session session, final Dialect dialect, final String tempTable) { session.doWork(connection -> { @@ -904,15 +791,12 @@ private void createTemporaryTable(Session session, final Dialect dialect, final TemporaryTableDialect ttDialect = TemporaryTableDialect.getTempTableDialect(dialect); - StringBuilder sb = new StringBuilder(); - sb.append(ttDialect.getCreateTemporaryTableString()); - sb.append(' ').append(tempTable).append(" (id "); - sb.append(dialect.getTypeName(Types.BIGINT)); - sb.append(" not null)"); - sb.append(ttDialect.getCreateTemporaryTablePostfix()); - Statement s = connection.createStatement(); - s.execute(sb.toString()); + s.execute(ttDialect.getCreateTemporaryTableString() + + ' ' + tempTable + " (id " + + dialect.getTypeName(Types.BIGINT) + + " not null)" + + ttDialect.getCreateTemporaryTablePostfix()); s.close(); }); } @@ -938,60 +822,43 @@ private String createDeleteQueryAsJoinPostgreSQL(String objectTable, String temp } private String createDeleteQueryAsSubquery(String objectTable, String tempTable, String idColumnName) { - StringBuilder sb = new StringBuilder(); - sb.append("delete from ").append(objectTable); - sb.append(" where ").append(idColumnName).append(" in (select id from ").append(tempTable) - .append(')'); - - return sb.toString(); + return "delete from " + objectTable + + " where " + idColumnName + " in (select id from " + tempTable + + ')'; } public long countObjects(String query, Map params) { - Session session = null; - long[] count = {0}; + long[] count = { 0 }; + Session session = baseHelper.beginTransaction(); try { - session = baseHelper.beginTransaction(); session.setFlushMode(FlushMode.MANUAL); -// Query q = session.createQuery(query); - session.doWork(new Work() { - - @Override - public void execute(Connection connection) throws SQLException { - Database database = getConfiguration().getDatabase(); - - String basicQuery = query; - if (StringUtils.isBlank(query)) { - basicQuery = "select count (*) from m_audit_event " - + (database.equals(Database.ORACLE) ? "" : "as ") - + "aer where 1 = 1"; - } - SelectQueryBuilder queryBuilder = new SelectQueryBuilder(database, basicQuery); - setParametersToQuery(queryBuilder, params); + session.doWork(connection -> { + Database database = getConfiguration().getDatabase(); + + String basicQuery = query; + if (StringUtils.isBlank(query)) { + basicQuery = "select count(*) from m_audit_event " + + (database.equals(Database.ORACLE) ? "" : "as ") + + "aer where 1 = 1"; + } + SelectQueryBuilder queryBuilder = new SelectQueryBuilder(database, basicQuery); + setParametersToQuery(queryBuilder, params); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("List records attempt\n processed query: {}", queryBuilder); - } + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("List records attempt\n processed query: {}", queryBuilder); + } - PreparedStatement stmt = queryBuilder.build().createPreparedStatement(connection); - try { - ResultSet resultList = stmt.executeQuery(); - if(!resultList.next()) { - throw new IllegalArgumentException("Result set don't have value for select: " + query); - } - if(resultList.getMetaData().getColumnCount() > 1) { - throw new IllegalArgumentException("Result have more as one value for select: " + query); - } - count[0] = resultList.getLong(1); - } finally { - stmt.close(); + try (PreparedStatement stmt = queryBuilder.build().createPreparedStatement(connection)) { + ResultSet resultList = stmt.executeQuery(); + if (!resultList.next()) { + throw new IllegalArgumentException("Result set don't have value for select: " + query); } - + if (resultList.getMetaData().getColumnCount() > 1) { + throw new IllegalArgumentException("Result have more as one value for select: " + query); + } + count[0] = resultList.getLong(1); } }); - -// setParametersToQuery(q, params); -// Number numberCount = (Number) q.uniqueResult(); -// count = numberCount != null ? numberCount.intValue() : 0; } catch (RuntimeException ex) { baseHelper.handleGeneralRuntimeException(ex, session, null); } finally { From 22f663f5db94e1d1bdf9de3c43f31f91f1c5208f Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Thu, 12 Mar 2020 23:17:03 +0100 Subject: [PATCH 4/5] fix for MID-5960 SelfService Credentials - Automatic password propagation Now, mapping strength and passwordCapabilityType.readable are taking into account when computing password propagation options for accounts. --- .../self/PageAbstractSelfCredentials.java | 899 ++++++++-------- .../midpoint/schema/CapabilityUtil.java | 697 +++++++------ .../ProjectionCredentialsProcessor.java | 975 +++++++++--------- 3 files changed, 1293 insertions(+), 1278 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAbstractSelfCredentials.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAbstractSelfCredentials.java index 8210398ea7d..187111c711b 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAbstractSelfCredentials.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAbstractSelfCredentials.java @@ -1,448 +1,451 @@ -/* - * Copyright (c) 2010-2019 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.web.page.self; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; -import com.evolveum.midpoint.prism.*; -import com.evolveum.prism.xml.ns._public.types_3.EncryptedDataType; - -import org.apache.commons.collections4.CollectionUtils; -import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.extensions.markup.html.tabs.AbstractTab; -import org.apache.wicket.extensions.markup.html.tabs.ITab; -import org.apache.wicket.markup.html.WebMarkupContainer; -import org.apache.wicket.markup.html.form.Form; -import org.apache.wicket.model.Model; - -import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; -import com.evolveum.midpoint.gui.api.model.LoadableModel; -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.delta.PropertyDelta; -import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.prism.schema.SchemaRegistry; -import com.evolveum.midpoint.schema.GetOperationOptions; -import com.evolveum.midpoint.schema.SchemaConstantsGenerated; -import com.evolveum.midpoint.schema.SelectorOptions; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.util.ResourceTypeUtil; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SecurityViolationException; -import com.evolveum.midpoint.util.logging.LoggingUtils; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.web.component.AjaxSubmitButton; -import com.evolveum.midpoint.web.component.TabbedPanel; -import com.evolveum.midpoint.web.component.breadcrumbs.Breadcrumb; -import com.evolveum.midpoint.web.page.admin.home.dto.MyPasswordsDto; -import com.evolveum.midpoint.web.page.admin.home.dto.PasswordAccountDto; -import com.evolveum.midpoint.web.page.self.component.ChangePasswordPanel; -import com.evolveum.midpoint.web.security.util.SecurityUtils; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; - -/** - * @author Viliam Repan (lazyman) - */ - -public abstract class PageAbstractSelfCredentials extends PageSelf { - private static final long serialVersionUID = 1L; - - protected static final String ID_MAIN_FORM = "mainForm"; - private static final String ID_TAB_PANEL = "tabPanel"; - private static final String ID_SAVE_BUTTON = "save"; - private static final String ID_CANCEL_BUTTON = "cancel"; - - private static final Trace LOGGER = TraceManager.getTrace(PageAbstractSelfCredentials.class); - private static final String DOT_CLASS = PageSelfCredentials.class.getName() + "."; - private static final String OPERATION_LOAD_USER_WITH_ACCOUNTS = DOT_CLASS + "loadUserWithAccounts"; - private static final String OPERATION_LOAD_USER = DOT_CLASS + "loadUser"; - private static final String OPERATION_LOAD_ACCOUNT = DOT_CLASS + "loadAccount"; - private static final String OPERATION_SAVE_PASSWORD = DOT_CLASS + "savePassword"; - private static final String OPERATION_CHECK_PASSWORD = DOT_CLASS + "checkPassword"; - private static final String OPERATION_GET_CREDENTIALS_POLICY = DOT_CLASS + "getCredentialsPolicy"; - - - private LoadableModel model; - private PrismObject focus; - - public PageAbstractSelfCredentials() { - model = new LoadableModel(false) { - private static final long serialVersionUID = 1L; - - @Override - protected MyPasswordsDto load() { - return loadPageModel(); - } - }; - - initLayout(); - } - - @Override - protected void createBreadcrumb() { - super.createBreadcrumb(); - - Breadcrumb bc = getLastBreadcrumb(); - bc.setIcon(new Model<>("fa fa-shield")); - } - - public PageAbstractSelfCredentials(final MyPasswordsDto myPasswordsDto) { - model = new LoadableModel(myPasswordsDto, false) { - private static final long serialVersionUID = 1L; - - @Override - protected MyPasswordsDto load() { - return myPasswordsDto; - } - }; - - initLayout(); - } - - private MyPasswordsDto loadPageModel() { - LOGGER.debug("Loading user and accounts."); - MyPasswordsDto dto = new MyPasswordsDto(); - OperationResult result = new OperationResult(OPERATION_LOAD_USER_WITH_ACCOUNTS); - try { - String focusOid = SecurityUtils.getPrincipalUser().getOid(); - Task task = createSimpleTask(OPERATION_LOAD_USER); - OperationResult subResult = result.createSubresult(OPERATION_LOAD_USER); - focus = getModelService().getObject(FocusType.class, focusOid, null, task, subResult); - subResult.recordSuccessIfUnknown(); - - dto.getAccounts().add(createDefaultPasswordAccountDto(focus)); - - CredentialsPolicyType credentialsPolicyType = getPasswordCredentialsPolicy(); - if (credentialsPolicyType != null) { - PasswordCredentialsPolicyType passwordCredentialsPolicy = credentialsPolicyType.getPassword(); - if (passwordCredentialsPolicy != null) { - CredentialsPropagationUserControlType propagationUserControl = passwordCredentialsPolicy.getPropagationUserControl(); - if (propagationUserControl != null) { - dto.setPropagation(propagationUserControl); - } - PasswordChangeSecurityType passwordChangeSecurity = passwordCredentialsPolicy.getPasswordChangeSecurity(); - if (passwordChangeSecurity != null) { - dto.setPasswordChangeSecurity(passwordChangeSecurity); - } - - } - - } - - if (dto.getPropagation() == null || dto.getPropagation().equals(CredentialsPropagationUserControlType.USER_CHOICE)) { - PrismReference reference = focus.findReference(FocusType.F_LINK_REF); - if (reference == null || reference.getValues() == null) { - LOGGER.debug("No accounts found for user {}.", new Object[]{focusOid}); - return dto; - } - - final Collection> options = getOperationOptionsBuilder() - .item(ShadowType.F_RESOURCE_REF).resolve() - .build(); - List values = reference.getValues(); - for (PrismReferenceValue value : values) { - subResult = result.createSubresult(OPERATION_LOAD_ACCOUNT); - try { - String accountOid = value.getOid(); - task = createSimpleTask(OPERATION_LOAD_ACCOUNT); - - PrismObject account = getModelService().getObject(ShadowType.class, - accountOid, options, task, subResult); - - - dto.getAccounts().add(createPasswordAccountDto(account, task, subResult)); - subResult.recordSuccessIfUnknown(); - } catch (Exception ex) { - LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load account", ex); - subResult.recordFatalError(getString("PageAbstractSelfCredentials.message.couldntLoadAccount.fatalError"), ex); - } - } - } - result.recordSuccessIfUnknown(); - } catch (Exception ex) { - LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load accounts", ex); - result.recordFatalError(getString("PageAbstractSelfCredentials.message.couldntLoadAccounts.fatalError"), ex); - } finally { - result.recomputeStatus(); - } - - Collections.sort(dto.getAccounts()); - - if (!result.isSuccess() && !result.isHandledError()) { - showResult(result); - } - - return dto; - } - - - private void initLayout() { - Form mainForm = new com.evolveum.midpoint.web.component.form.Form<>(ID_MAIN_FORM); - - List tabs = new ArrayList<>(); - tabs.add(new AbstractTab(createStringResource("PageSelfCredentials.tabs.password")) { - private static final long serialVersionUID = 1L; - - @Override - public WebMarkupContainer getPanel(String panelId) { - return new ChangePasswordPanel(panelId, isCheckOldPassword(), model, model.getObject()); - } - }); - - TabbedPanel credentialsTabPanel = WebComponentUtil.createTabPanel(ID_TAB_PANEL, this, tabs, null); - credentialsTabPanel.setOutputMarkupId(true); - - mainForm.add(credentialsTabPanel); - initButtons(mainForm); - - add(mainForm); - - } - - private void initButtons(Form mainForm) { - AjaxSubmitButton save = new AjaxSubmitButton(ID_SAVE_BUTTON, createStringResource("PageBase.button.save")) { - - private static final long serialVersionUID = 1L; - - @Override - protected void onError(AjaxRequestTarget target) { - target.add(getFeedbackPanel()); - } - - @Override - protected void onSubmit(AjaxRequestTarget target) { - onSavePerformed(target); - } - }; - mainForm.setDefaultButton(save); - mainForm.add(save); - - AjaxSubmitButton cancel = new AjaxSubmitButton(ID_CANCEL_BUTTON, createStringResource("PageBase.button.back")) { - - private static final long serialVersionUID = 1L; - - @Override - protected void onError(AjaxRequestTarget target) { - onCancelPerformed(target); - } - - @Override - protected void onSubmit(AjaxRequestTarget target) { - onCancelPerformed(target); - } - }; - mainForm.add(cancel); - } - - private PasswordAccountDto createDefaultPasswordAccountDto(PrismObject focus) { - String customSystemName = WebComponentUtil.getMidpointCustomSystemName(PageAbstractSelfCredentials.this, "midpoint.default.system.name"); - return new PasswordAccountDto(focus.getOid(), focus.getName().getOrig(), - getString("PageSelfCredentials.resourceMidpoint", customSystemName), - WebComponentUtil.isActivationEnabled(focus), true); - } - - private PasswordAccountDto createPasswordAccountDto(PrismObject account, Task task, OperationResult result) throws ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { - PrismReference resourceRef = account.findReference(ShadowType.F_RESOURCE_REF); - String resourceName; - if (resourceRef == null || resourceRef.getValue() == null || resourceRef.getValue().getObject() == null) { - resourceName = getString("PageSelfCredentials.couldntResolve"); - } else { - resourceName = WebComponentUtil.getName(resourceRef.getValue().getObject()); - } - - PasswordAccountDto passwordAccountDto = new PasswordAccountDto(account.getOid(), WebComponentUtil.getName(account), - resourceName, WebComponentUtil.isActivationEnabled(account)); - - passwordAccountDto.setPasswordOutbound(getPasswordOutbound(account, task, result)); - passwordAccountDto.setPasswordCapabilityEnabled(hasPasswordCapability(account)); - return passwordAccountDto; - } - - protected void onSavePerformed(AjaxRequestTarget target) { - List selectedAccounts = getSelectedAccountsList(); - - ProtectedStringType oldPassword = null; - if (isCheckOldPassword()) { - LOGGER.debug("Check old password"); - if (model.getObject().getOldPassword() == null - || model.getObject().getOldPassword().trim().equals("")){ - warn(getString("PageSelfCredentials.specifyOldPasswordMessage")); - target.add(getFeedbackPanel()); - return; - } else { - OperationResult checkPasswordResult = new OperationResult(OPERATION_CHECK_PASSWORD); - Task checkPasswordTask = createSimpleTask(OPERATION_CHECK_PASSWORD); - try { - oldPassword = new ProtectedStringType(); - oldPassword.setClearValue(model.getObject().getOldPassword()); - boolean isCorrectPassword = getModelInteractionService().checkPassword(focus.getOid(), oldPassword, - checkPasswordTask, checkPasswordResult); - if (!isCorrectPassword) { - error(getString("PageSelfCredentials.incorrectOldPassword")); - target.add(getFeedbackPanel()); - return; - } - } catch (Exception ex) { - LoggingUtils.logUnexpectedException(LOGGER, "Couldn't check password", ex); - checkPasswordResult.recordFatalError( - getString("PageAbstractSelfCredentials.message.onSavePerformed.fatalError", ex.getMessage()), ex); - target.add(getFeedbackPanel()); - return; - } finally { - checkPasswordResult.computeStatus(); - } - } - } - if (selectedAccounts.isEmpty()) { - warn(getString("PageSelfCredentials.noAccountSelected")); - target.add(getFeedbackPanel()); - return; - } - if (getModelObject().getPassword() == null ) { - warn(getString("PageSelfCredentials.emptyPasswordFiled")); - target.add(getFeedbackPanel()); - return; - } - - OperationResult result = new OperationResult(OPERATION_SAVE_PASSWORD); - try { - MyPasswordsDto dto = model.getObject(); - ProtectedStringType password = dto.getPassword(); - if (!password.isEncrypted()) { - WebComponentUtil.encryptProtectedString(password, true, getMidpointApplication()); - } - final ItemPath valuePath = ItemPath.create(SchemaConstantsGenerated.C_CREDENTIALS, - CredentialsType.F_PASSWORD, PasswordType.F_VALUE); - SchemaRegistry registry = getPrismContext().getSchemaRegistry(); - Collection> deltas = new ArrayList<>(); - - - for (PasswordAccountDto accDto : selectedAccounts) { - PrismObjectDefinition objDef = accDto.isMidpoint() ? - registry.findObjectDefinitionByCompileTimeClass(UserType.class) : - registry.findObjectDefinitionByCompileTimeClass(ShadowType.class); - - PropertyDelta delta = getPrismContext().deltaFactory().property() - .createModificationReplaceProperty(valuePath, objDef, password); - if (oldPassword != null) { - delta.addEstimatedOldValue(getPrismContext().itemFactory().createPropertyValue(oldPassword)); - } - - Class type = accDto.isMidpoint() ? UserType.class : ShadowType.class; - - deltas.add(getPrismContext().deltaFactory().object().createModifyDelta(accDto.getOid(), delta, type - )); - } - getModelService().executeChanges(deltas, null, createSimpleTask(OPERATION_SAVE_PASSWORD, SchemaConstants.CHANNEL_GUI_SELF_SERVICE_URI), result); - - result.computeStatus(); - } catch (Exception ex) { - setEncryptedPasswordData(null); - LoggingUtils.logUnexpectedException(LOGGER, "Couldn't save password changes", ex); - result.recordFatalError(getString("PageAbstractSelfCredentials.save.password.failed", ex.getMessage()), ex); - } finally { - result.computeStatusIfUnknown(); - } - - finishChangePassword(result, target); - } - - protected void setEncryptedPasswordData(EncryptedDataType data) { - MyPasswordsDto dto = model.getObject(); - ProtectedStringType password = dto.getPassword(); - if (password != null){ - password.setEncryptedData(data); - } - } - - protected abstract boolean isCheckOldPassword(); - - protected abstract void finishChangePassword(OperationResult result, AjaxRequestTarget target); - - private List getSelectedAccountsList(){ - List passwordAccountDtos = model.getObject().getAccounts(); - List selectedAccountList = new ArrayList<>(); - if (model.getObject().getPropagation() != null - && model.getObject().getPropagation().equals(CredentialsPropagationUserControlType.MAPPING)){ - selectedAccountList.addAll(passwordAccountDtos); - } else { - for (PasswordAccountDto passwordAccountDto : passwordAccountDtos) { - if (passwordAccountDto.getCssClass().equals(ChangePasswordPanel.SELECTED_ACCOUNT_ICON_CSS)) { - selectedAccountList.add(passwordAccountDto); - } - } - } - return selectedAccountList; - } - private void onCancelPerformed(AjaxRequestTarget target) { - redirectBack(); - } - - private boolean getPasswordOutbound(PrismObject shadow, Task task, OperationResult result) throws ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { - try { - RefinedObjectClassDefinition rOCDef = getModelInteractionService().getEditObjectClassDefinition(shadow, - shadow.asObjectable().getResourceRef().asReferenceValue().getObject(), - AuthorizationPhaseType.REQUEST, task, result); - - if (rOCDef != null && !CollectionUtils.isEmpty(rOCDef.getPasswordOutbound())){ - return true; - } - } catch (SchemaException ex) { - - } - return false; - } - - - private boolean hasPasswordCapability(PrismObject shadow) { - - ShadowType shadowType = shadow.asObjectable(); - ResourceType resource = (ResourceType) shadowType.getResourceRef().asReferenceValue().getObject().asObjectable(); - ResourceObjectTypeDefinitionType resourceObjectTypeDefinitionType = ResourceTypeUtil.findObjectTypeDefinition(resource.asPrismObject(), shadowType.getKind(), shadowType.getIntent()); - - return ResourceTypeUtil.isPasswordCapabilityEnabled(resource, resourceObjectTypeDefinitionType); - - } - - public PrismObject getFocus() { - return focus; - } - - private CredentialsPolicyType getPasswordCredentialsPolicy (){ - LOGGER.debug("Getting credentials policy"); - Task task = createSimpleTask(OPERATION_GET_CREDENTIALS_POLICY); - OperationResult result = new OperationResult(OPERATION_GET_CREDENTIALS_POLICY); - CredentialsPolicyType credentialsPolicyType = null; - try { - credentialsPolicyType = getModelInteractionService().getCredentialsPolicy(focus, task, result); - result.recordSuccessIfUnknown(); - } catch (Exception ex) { - LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load credentials policy", ex); - result.recordFatalError( - getString("PageAbstractSelfCredentials.message.getPasswordCredentialsPolicy.fatalError", ex.getMessage()), ex); - } finally { - result.computeStatus(); - } - return credentialsPolicyType; - } - - protected MyPasswordsDto getModelObject() { - return model.getObject(); - } -} +/* + * Copyright (c) 2010-2019 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.web.page.self; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.extensions.markup.html.tabs.AbstractTab; +import org.apache.wicket.extensions.markup.html.tabs.ITab; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.Model; + +import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; +import com.evolveum.midpoint.gui.api.model.LoadableModel; +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.PrismReference; +import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.delta.PropertyDelta; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.schema.SchemaRegistry; +import com.evolveum.midpoint.schema.CapabilityUtil; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SchemaConstantsGenerated; +import com.evolveum.midpoint.schema.SelectorOptions; +import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ResourceTypeUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.util.logging.LoggingUtils; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.component.AjaxSubmitButton; +import com.evolveum.midpoint.web.component.TabbedPanel; +import com.evolveum.midpoint.web.component.breadcrumbs.Breadcrumb; +import com.evolveum.midpoint.web.page.admin.home.dto.MyPasswordsDto; +import com.evolveum.midpoint.web.page.admin.home.dto.PasswordAccountDto; +import com.evolveum.midpoint.web.page.self.component.ChangePasswordPanel; +import com.evolveum.midpoint.web.security.util.SecurityUtils; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType; +import com.evolveum.prism.xml.ns._public.types_3.EncryptedDataType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; + +/** + * @author Viliam Repan (lazyman) + */ + +public abstract class PageAbstractSelfCredentials extends PageSelf { + private static final long serialVersionUID = 1L; + + private static final Trace LOGGER = TraceManager.getTrace(PageAbstractSelfCredentials.class); + + protected static final String ID_MAIN_FORM = "mainForm"; + private static final String ID_TAB_PANEL = "tabPanel"; + private static final String ID_SAVE_BUTTON = "save"; + private static final String ID_CANCEL_BUTTON = "cancel"; + + private static final String DOT_CLASS = PageSelfCredentials.class.getName() + "."; + private static final String OPERATION_LOAD_USER_WITH_ACCOUNTS = DOT_CLASS + "loadUserWithAccounts"; + private static final String OPERATION_LOAD_USER = DOT_CLASS + "loadUser"; + private static final String OPERATION_LOAD_ACCOUNT = DOT_CLASS + "loadAccount"; + private static final String OPERATION_SAVE_PASSWORD = DOT_CLASS + "savePassword"; + private static final String OPERATION_CHECK_PASSWORD = DOT_CLASS + "checkPassword"; + private static final String OPERATION_GET_CREDENTIALS_POLICY = DOT_CLASS + "getCredentialsPolicy"; + + + private LoadableModel model; + private PrismObject focus; + + public PageAbstractSelfCredentials() { + model = new LoadableModel(false) { + private static final long serialVersionUID = 1L; + + @Override + protected MyPasswordsDto load() { + return loadPageModel(); + } + }; + + initLayout(); + } + + @Override + protected void createBreadcrumb() { + super.createBreadcrumb(); + + Breadcrumb bc = getLastBreadcrumb(); + bc.setIcon(new Model<>("fa fa-shield")); + } + + private MyPasswordsDto loadPageModel() { + LOGGER.debug("Loading user and accounts."); + MyPasswordsDto dto = new MyPasswordsDto(); + OperationResult result = new OperationResult(OPERATION_LOAD_USER_WITH_ACCOUNTS); + try { + String focusOid = SecurityUtils.getPrincipalUser().getOid(); + Task task = createSimpleTask(OPERATION_LOAD_USER); + OperationResult subResult = result.createSubresult(OPERATION_LOAD_USER); + focus = getModelService().getObject(FocusType.class, focusOid, null, task, subResult); + subResult.recordSuccessIfUnknown(); + + dto.getAccounts().add(createDefaultPasswordAccountDto(focus)); + + CredentialsPolicyType credentialsPolicyType = getPasswordCredentialsPolicy(); + if (credentialsPolicyType != null) { + PasswordCredentialsPolicyType passwordCredentialsPolicy = credentialsPolicyType.getPassword(); + if (passwordCredentialsPolicy != null) { + CredentialsPropagationUserControlType propagationUserControl = passwordCredentialsPolicy.getPropagationUserControl(); + if (propagationUserControl != null) { + dto.setPropagation(propagationUserControl); + } + PasswordChangeSecurityType passwordChangeSecurity = passwordCredentialsPolicy.getPasswordChangeSecurity(); + if (passwordChangeSecurity != null) { + dto.setPasswordChangeSecurity(passwordChangeSecurity); + } + + } + + } + + if (dto.getPropagation() == null || dto.getPropagation().equals(CredentialsPropagationUserControlType.USER_CHOICE)) { + PrismReference reference = focus.findReference(FocusType.F_LINK_REF); + if (reference == null || reference.getValues() == null) { + LOGGER.debug("No accounts found for user {}.", new Object[]{focusOid}); + return dto; + } + + final Collection> options = getOperationOptionsBuilder() + .noFetch() + .item(ShadowType.F_RESOURCE_REF).resolve() + .build(); + List values = reference.getValues(); + for (PrismReferenceValue value : values) { + subResult = result.createSubresult(OPERATION_LOAD_ACCOUNT); + try { + String accountOid = value.getOid(); + task = createSimpleTask(OPERATION_LOAD_ACCOUNT); + + PrismObject account = getModelService().getObject(ShadowType.class, + accountOid, options, task, subResult); + + + dto.getAccounts().add(createPasswordAccountDto(account, task, subResult)); + subResult.recordSuccessIfUnknown(); + } catch (Exception ex) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load account", ex); + subResult.recordFatalError(getString("PageAbstractSelfCredentials.message.couldntLoadAccount.fatalError"), ex); + } + } + } + result.recordSuccessIfUnknown(); + } catch (Exception ex) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load accounts", ex); + result.recordFatalError(getString("PageAbstractSelfCredentials.message.couldntLoadAccounts.fatalError"), ex); + } finally { + result.recomputeStatus(); + } + + Collections.sort(dto.getAccounts()); + + if (!result.isSuccess() && !result.isHandledError()) { + showResult(result); + } + + return dto; + } + + + private void initLayout() { + Form mainForm = new com.evolveum.midpoint.web.component.form.Form<>(ID_MAIN_FORM); + + List tabs = new ArrayList<>(); + tabs.add(new AbstractTab(createStringResource("PageSelfCredentials.tabs.password")) { + private static final long serialVersionUID = 1L; + + @Override + public WebMarkupContainer getPanel(String panelId) { + return new ChangePasswordPanel(panelId, isCheckOldPassword(), model, model.getObject()); + } + }); + + TabbedPanel credentialsTabPanel = WebComponentUtil.createTabPanel(ID_TAB_PANEL, this, tabs, null); + credentialsTabPanel.setOutputMarkupId(true); + + mainForm.add(credentialsTabPanel); + initButtons(mainForm); + + add(mainForm); + + } + + private void initButtons(Form mainForm) { + AjaxSubmitButton save = new AjaxSubmitButton(ID_SAVE_BUTTON, createStringResource("PageBase.button.save")) { + + private static final long serialVersionUID = 1L; + + @Override + protected void onError(AjaxRequestTarget target) { + target.add(getFeedbackPanel()); + } + + @Override + protected void onSubmit(AjaxRequestTarget target) { + onSavePerformed(target); + } + }; + mainForm.setDefaultButton(save); + mainForm.add(save); + + AjaxSubmitButton cancel = new AjaxSubmitButton(ID_CANCEL_BUTTON, createStringResource("PageBase.button.back")) { + + private static final long serialVersionUID = 1L; + + @Override + protected void onError(AjaxRequestTarget target) { + onCancelPerformed(target); + } + + @Override + protected void onSubmit(AjaxRequestTarget target) { + onCancelPerformed(target); + } + }; + mainForm.add(cancel); + } + + private PasswordAccountDto createDefaultPasswordAccountDto(PrismObject focus) { + String customSystemName = WebComponentUtil.getMidpointCustomSystemName(PageAbstractSelfCredentials.this, "midpoint.default.system.name"); + return new PasswordAccountDto(focus.getOid(), focus.getName().getOrig(), + getString("PageSelfCredentials.resourceMidpoint", customSystemName), + WebComponentUtil.isActivationEnabled(focus), true); + } + + private PasswordAccountDto createPasswordAccountDto(PrismObject account, Task task, OperationResult result) throws ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { + PrismReference resourceRef = account.findReference(ShadowType.F_RESOURCE_REF); + String resourceName; + if (resourceRef == null || resourceRef.getValue() == null || resourceRef.getValue().getObject() == null) { + resourceName = getString("PageSelfCredentials.couldntResolve"); + } else { + resourceName = WebComponentUtil.getName(resourceRef.getValue().getObject()); + } + + PasswordAccountDto passwordAccountDto = new PasswordAccountDto(account.getOid(), WebComponentUtil.getName(account), + resourceName, WebComponentUtil.isActivationEnabled(account)); + + passwordAccountDto.setPasswordOutbound(getPasswordOutbound(account, task, result)); + passwordAccountDto.setPasswordCapabilityEnabled(hasPasswordCapability(account)); + return passwordAccountDto; + } + + protected void onSavePerformed(AjaxRequestTarget target) { + List selectedAccounts = getSelectedAccountsList(); + + ProtectedStringType oldPassword = null; + if (isCheckOldPassword()) { + LOGGER.debug("Check old password"); + if (model.getObject().getOldPassword() == null + || model.getObject().getOldPassword().trim().equals("")){ + warn(getString("PageSelfCredentials.specifyOldPasswordMessage")); + target.add(getFeedbackPanel()); + return; + } else { + OperationResult checkPasswordResult = new OperationResult(OPERATION_CHECK_PASSWORD); + Task checkPasswordTask = createSimpleTask(OPERATION_CHECK_PASSWORD); + try { + oldPassword = new ProtectedStringType(); + oldPassword.setClearValue(model.getObject().getOldPassword()); + boolean isCorrectPassword = getModelInteractionService().checkPassword(focus.getOid(), oldPassword, + checkPasswordTask, checkPasswordResult); + if (!isCorrectPassword) { + error(getString("PageSelfCredentials.incorrectOldPassword")); + target.add(getFeedbackPanel()); + return; + } + } catch (Exception ex) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't check password", ex); + checkPasswordResult.recordFatalError( + getString("PageAbstractSelfCredentials.message.onSavePerformed.fatalError", ex.getMessage()), ex); + target.add(getFeedbackPanel()); + return; + } finally { + checkPasswordResult.computeStatus(); + } + } + } + if (selectedAccounts.isEmpty()) { + warn(getString("PageSelfCredentials.noAccountSelected")); + target.add(getFeedbackPanel()); + return; + } + if (getModelObject().getPassword() == null ) { + warn(getString("PageSelfCredentials.emptyPasswordFiled")); + target.add(getFeedbackPanel()); + return; + } + + OperationResult result = new OperationResult(OPERATION_SAVE_PASSWORD); + try { + MyPasswordsDto dto = model.getObject(); + ProtectedStringType password = dto.getPassword(); + if (!password.isEncrypted()) { + WebComponentUtil.encryptProtectedString(password, true, getMidpointApplication()); + } + final ItemPath valuePath = ItemPath.create(SchemaConstantsGenerated.C_CREDENTIALS, + CredentialsType.F_PASSWORD, PasswordType.F_VALUE); + SchemaRegistry registry = getPrismContext().getSchemaRegistry(); + Collection> deltas = new ArrayList<>(); + + + for (PasswordAccountDto accDto : selectedAccounts) { + PrismObjectDefinition objDef = accDto.isMidpoint() ? + registry.findObjectDefinitionByCompileTimeClass(UserType.class) : + registry.findObjectDefinitionByCompileTimeClass(ShadowType.class); + + PropertyDelta delta = getPrismContext().deltaFactory().property() + .createModificationReplaceProperty(valuePath, objDef, password); + if (oldPassword != null) { + delta.addEstimatedOldValue(getPrismContext().itemFactory().createPropertyValue(oldPassword)); + } + + Class type = accDto.isMidpoint() ? UserType.class : ShadowType.class; + + deltas.add(getPrismContext().deltaFactory().object().createModifyDelta(accDto.getOid(), delta, type + )); + } + getModelService().executeChanges(deltas, null, createSimpleTask(OPERATION_SAVE_PASSWORD, SchemaConstants.CHANNEL_GUI_SELF_SERVICE_URI), result); + + result.computeStatus(); + } catch (Exception ex) { + setEncryptedPasswordData(null); + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't save password changes", ex); + result.recordFatalError(getString("PageAbstractSelfCredentials.save.password.failed", ex.getMessage()), ex); + } finally { + result.computeStatusIfUnknown(); + } + + finishChangePassword(result, target); + } + + protected void setEncryptedPasswordData(EncryptedDataType data) { + MyPasswordsDto dto = model.getObject(); + ProtectedStringType password = dto.getPassword(); + if (password != null){ + password.setEncryptedData(data); + } + } + + protected abstract boolean isCheckOldPassword(); + + protected abstract void finishChangePassword(OperationResult result, AjaxRequestTarget target); + + private List getSelectedAccountsList(){ + List passwordAccountDtos = model.getObject().getAccounts(); + List selectedAccountList = new ArrayList<>(); + if (model.getObject().getPropagation() != null + && model.getObject().getPropagation().equals(CredentialsPropagationUserControlType.MAPPING)){ + selectedAccountList.addAll(passwordAccountDtos); + } else { + for (PasswordAccountDto passwordAccountDto : passwordAccountDtos) { + if (passwordAccountDto.getCssClass().equals(ChangePasswordPanel.SELECTED_ACCOUNT_ICON_CSS)) { + selectedAccountList.add(passwordAccountDto); + } + } + } + return selectedAccountList; + } + private void onCancelPerformed(AjaxRequestTarget target) { + redirectBack(); + } + + private boolean getPasswordOutbound(PrismObject shadow, Task task, OperationResult result) throws ObjectNotFoundException, ExpressionEvaluationException, CommunicationException, ConfigurationException, SecurityViolationException { + try { + + //TODO cannot be null? + PrismObject resource = shadow.asObjectable().getResourceRef().asReferenceValue().getObject(); + + RefinedObjectClassDefinition rOCDef = getModelInteractionService().getEditObjectClassDefinition(shadow, + resource, AuthorizationPhaseType.REQUEST, task, result); + + List passwordOutbound = rOCDef.getPasswordOutbound(); + for (MappingType mapping : passwordOutbound) { + if (MappingStrengthType.WEAK == mapping.getStrength()) { + CredentialsCapabilityType capability = ResourceTypeUtil.getEffectiveCapability(resource.asObjectable(), CredentialsCapabilityType.class); + if (CapabilityUtil.isPasswordReadable(capability)) { + return true; + } + continue; + } + // at least one mapping which is not WEAK + return true; + } + + } catch (SchemaException ex) { + LoggingUtils.logUnexpectedException(LOGGER, "Failed to compute password propagation for {} ", ex, shadow); + result.recordFatalError("Faile to compute password propagation for " + shadow, ex); + showResult(result); + } + + return false; + + } + + + private boolean hasPasswordCapability(PrismObject shadow) { + + ShadowType shadowType = shadow.asObjectable(); + ResourceType resource = (ResourceType) shadowType.getResourceRef().asReferenceValue().getObject().asObjectable(); + ResourceObjectTypeDefinitionType resourceObjectTypeDefinitionType = ResourceTypeUtil.findObjectTypeDefinition(resource.asPrismObject(), shadowType.getKind(), shadowType.getIntent()); + + return ResourceTypeUtil.isPasswordCapabilityEnabled(resource, resourceObjectTypeDefinitionType); + + } + + public PrismObject getFocus() { + return focus; + } + + private CredentialsPolicyType getPasswordCredentialsPolicy (){ + LOGGER.debug("Getting credentials policy"); + Task task = createSimpleTask(OPERATION_GET_CREDENTIALS_POLICY); + OperationResult result = new OperationResult(OPERATION_GET_CREDENTIALS_POLICY); + CredentialsPolicyType credentialsPolicyType = null; + try { + credentialsPolicyType = getModelInteractionService().getCredentialsPolicy(focus, task, result); + result.recordSuccessIfUnknown(); + } catch (Exception ex) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load credentials policy", ex); + result.recordFatalError( + getString("PageAbstractSelfCredentials.message.getPasswordCredentialsPolicy.fatalError", ex.getMessage()), ex); + } finally { + result.computeStatus(); + } + return credentialsPolicyType; + } + + protected MyPasswordsDto getModelObject() { + return model.getObject(); + } +} diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/CapabilityUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/CapabilityUtil.java index 2e77a9cd27a..5540a6f5c74 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/CapabilityUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/CapabilityUtil.java @@ -1,338 +1,359 @@ -/* - * Copyright (c) 2010-2013 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.schema; - -import java.util.Collection; -import java.util.List; - -import javax.xml.bind.JAXBElement; -import javax.xml.namespace.QName; - -import com.evolveum.midpoint.xml.ns._public.common.common_3.CapabilitiesType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.CapabilityCollectionType; -import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.*; -import org.jetbrains.annotations.NotNull; -import org.w3c.dom.Element; - -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.util.DOMUtil; -import com.evolveum.midpoint.util.JAXBUtil; -import com.evolveum.midpoint.util.exception.SchemaException; - -/** - * @author semancik - * - */ -public class CapabilityUtil { - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static T getCapability(Collection capabilities, Class capabilityClass) { - if (capabilities == null) { - return null; - } - for (Object cap : capabilities) { - if (cap instanceof JAXBElement) { - JAXBElement element = (JAXBElement) cap; - if (capabilityClass.isAssignableFrom(element.getDeclaredType())) { - return (T) element.getValue(); - } - } else if (capabilityClass.isAssignableFrom(cap.getClass())) { - return (T) cap; - } - } - return null; - } - - public static boolean isCapabilityEnabled(Object capability) { - if (capability == null) { - return false; - } - if (capability instanceof JAXBElement) { - capability = ((JAXBElement)capability).getValue(); - } - - if (capability instanceof CapabilityType) { - return CapabilityUtil.isCapabilityEnabled((CapabilityType)capability); - } else if (capability instanceof Element) { - return CapabilityUtil.isCapabilityEnabled((Element)capability); - } else { - throw new IllegalArgumentException("Unexpected capability type "+capability.getClass()); - } - } - - private static boolean isCapabilityEnabled(Element capability) { - if (capability == null) { - return false; - } - ObjectFactory capabilitiesObjectFactory = new ObjectFactory(); - QName enabledElementName = capabilitiesObjectFactory.createEnabled(true).getName(); - Element enabledElement = DOMUtil.getChildElement(capability, enabledElementName); - return enabledElement == null || Boolean.parseBoolean(enabledElement.getTextContent()); - } - - public static boolean isCapabilityEnabled(T capability) { - if (capability == null) { - return false; - } - if (capability.isEnabled() == null) { - return true; - } - return capability.isEnabled(); - } - - public static Object getCapabilityWithSameElementName(List capabilities, Object capability) { - if (capabilities == null) { - return false; - } - QName capabilityElementName = JAXBUtil.getElementQName(capability); - for (Object cap: capabilities) { - QName capElementName = JAXBUtil.getElementQName(cap); - if (capabilityElementName.equals(capElementName)) { - return cap; - } - } - return null; - } - - public static boolean containsCapabilityWithSameElementName(List capabilities, Object capability) { - return getCapabilityWithSameElementName(capabilities, capability) != null; - } - - public static String getCapabilityDisplayName(Object capability) { - // TODO: look for schema annotation - String className; - if (capability instanceof JAXBElement) { - className = ((JAXBElement) capability).getDeclaredType().getSimpleName(); - } else { - className = capability.getClass().getSimpleName(); - } - if (className.endsWith("CapabilityType")) { - return className.substring(0, className.length() - "CapabilityType".length()); - } - return className; - } - - public static boolean isPasswordReturnedByDefault(CredentialsCapabilityType capability) { - if (capability == null) { - return false; - } - PasswordCapabilityType password = capability.getPassword(); - if (password == null) { - return false; - } - if (password.isReturnedByDefault() == null) { - return true; - } - return password.isReturnedByDefault(); - } - - public static boolean isActivationStatusReturnedByDefault(ActivationCapabilityType capability) { - if (capability == null) { - return false; - } - ActivationStatusCapabilityType statusCap = getEffectiveActivationStatus(capability); - if (statusCap == null) { - return false; - } - if (statusCap.isReturnedByDefault() == null) { - return true; - } - return statusCap.isReturnedByDefault(); - } - - public static boolean isActivationLockoutStatusReturnedByDefault(ActivationCapabilityType capability) { - if (capability == null) { - return false; - } - ActivationLockoutStatusCapabilityType statusCap = capability.getLockoutStatus(); - if (statusCap == null) { - return false; - } - if (statusCap.isReturnedByDefault() == null) { - return true; - } - return statusCap.isReturnedByDefault(); - } - - public static boolean isActivationValidFromReturnedByDefault(ActivationCapabilityType capability) { - if (capability == null) { - return false; - } - ActivationValidityCapabilityType valCap = capability.getValidFrom(); - if (valCap == null) { - return false; - } - if (valCap.isReturnedByDefault() == null) { - return true; - } - return valCap.isReturnedByDefault(); - } - - public static boolean isActivationValidToReturnedByDefault(ActivationCapabilityType capability) { - if (capability == null) { - return false; - } - ActivationValidityCapabilityType valCap = capability.getValidTo(); - if (valCap == null) { - return false; - } - if (valCap.isReturnedByDefault() == null) { - return true; - } - return valCap.isReturnedByDefault(); - } - - @SuppressWarnings("unchecked") - public static CapabilityType asCapabilityType(Object capabilityObject) { - return capabilityObject instanceof CapabilityType ? - (CapabilityType) capabilityObject : - ((JAXBElement) capabilityObject).getValue(); - } - - public static void fillDefaults(@NotNull CapabilityType capability) { - if (capability.isEnabled() == null) { - capability.setEnabled(true); - } - if (capability instanceof ActivationCapabilityType) { - ActivationCapabilityType act = ((ActivationCapabilityType) capability); - if (act.getStatus() == null) { - ActivationStatusCapabilityType st = new ActivationStatusCapabilityType(); - act.setStatus(st); - st.setEnabled(false); // TODO check if all midPoint code honors this flag! - st.setReturnedByDefault(false); - st.setIgnoreAttribute(true); - } else { - ActivationStatusCapabilityType st = act.getStatus(); - st.setEnabled(def(st.isEnabled(), true)); - st.setReturnedByDefault(def(st.isReturnedByDefault(), true)); - st.setIgnoreAttribute(def(st.isIgnoreAttribute(), true)); - } - if (act.getLockoutStatus() == null) { - ActivationLockoutStatusCapabilityType st = new ActivationLockoutStatusCapabilityType(); - act.setLockoutStatus(st); - st.setEnabled(false); - st.setReturnedByDefault(false); - st.setIgnoreAttribute(true); - } else { - ActivationLockoutStatusCapabilityType st = act.getLockoutStatus(); - st.setEnabled(def(st.isEnabled(), true)); - st.setReturnedByDefault(def(st.isReturnedByDefault(), true)); - st.setIgnoreAttribute(def(st.isIgnoreAttribute(), true)); - } - if (act.getValidFrom() == null) { - ActivationValidityCapabilityType vf = new ActivationValidityCapabilityType(); - act.setValidFrom(vf); - vf.setEnabled(false); - vf.setReturnedByDefault(false); - } else { - ActivationValidityCapabilityType vf = act.getValidFrom(); - vf.setEnabled(def(vf.isEnabled(), true)); - vf.setReturnedByDefault(def(vf.isReturnedByDefault(), true)); - } - if (act.getValidTo() == null) { - ActivationValidityCapabilityType vt = new ActivationValidityCapabilityType(); - act.setValidTo(vt); - vt.setEnabled(false); - vt.setReturnedByDefault(false); - } else { - ActivationValidityCapabilityType vt = act.getValidTo(); - vt.setEnabled(def(vt.isEnabled(), true)); - vt.setReturnedByDefault(def(vt.isReturnedByDefault(), true)); - } - } else if (capability instanceof CredentialsCapabilityType) { - CredentialsCapabilityType cred = ((CredentialsCapabilityType) capability); - if (cred.getPassword() == null) { - PasswordCapabilityType pc = new PasswordCapabilityType(); - cred.setPassword(pc); - pc.setEnabled(false); - pc.setReturnedByDefault(false); - } else { - PasswordCapabilityType pc = cred.getPassword(); - pc.setEnabled(def(pc.isEnabled(), true)); - pc.setReturnedByDefault(def(pc.isReturnedByDefault(), true)); - } - } - } - - private static Boolean def(Boolean originalValue, boolean defaultValue) { - return originalValue != null ? originalValue : defaultValue; - } - - public static T getEffectiveCapability(CapabilitiesType capabilitiesType, Class capabilityClass) { - if (capabilitiesType == null) { - return null; - } - if (capabilitiesType.getConfigured() != null) { - T configuredCapability = CapabilityUtil.getCapability(capabilitiesType.getConfigured().getAny(), capabilityClass); - if (configuredCapability != null) { - return configuredCapability; - } - // No configured capability entry, fallback to native capability - } - if (capabilitiesType.getNative() != null) { - T nativeCapability = CapabilityUtil.getCapability(capabilitiesType.getNative().getAny(), capabilityClass); - if (nativeCapability != null) { - return nativeCapability; - } - } - return null; - } - - public static ActivationStatusCapabilityType getEffectiveActivationStatus(ActivationCapabilityType act) { - if (act != null && act.getStatus() != null && !Boolean.FALSE.equals(act.getStatus().isEnabled())) { - return act.getStatus(); - } else { - return null; - } - } - - public static ActivationValidityCapabilityType getEffectiveActivationValidFrom(ActivationCapabilityType act) { - if (act != null && act.getValidFrom() != null && !Boolean.FALSE.equals(act.getValidFrom().isEnabled())) { - return act.getValidFrom(); - } else { - return null; - } - } - - public static ActivationValidityCapabilityType getEffectiveActivationValidTo(ActivationCapabilityType act) { - if (act != null && act.getValidTo() != null && !Boolean.FALSE.equals(act.getValidTo().isEnabled())) { - return act.getValidTo(); - } else { - return null; - } - } - - public static ActivationLockoutStatusCapabilityType getEffectiveActivationLockoutStatus(ActivationCapabilityType act) { - if (act != null && act.getLockoutStatus() != null && !Boolean.FALSE.equals(act.getLockoutStatus().isEnabled())) { - return act.getLockoutStatus(); - } else { - return null; - } - } - - public static boolean hasNativeCapability(CapabilitiesType capabilities, Class capabilityClass) { - if (capabilities == null) { - return false; - } - CapabilityCollectionType nativeCaps = capabilities.getNative(); - if (nativeCaps == null) { - return false; - } - return getCapability(nativeCaps.getAny(), capabilityClass) != null; - } - - public static boolean hasConfiguredCapability(CapabilitiesType capabilities, Class capabilityClass) { - if (capabilities == null) { - return false; - } - CapabilityCollectionType configuredCaps = capabilities.getConfigured(); - if (configuredCaps == null) { - return false; - } - return getCapability(configuredCaps.getAny(), capabilityClass) != null; - } -} +/* + * Copyright (c) 2010-2013 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.schema; + +import java.util.Collection; +import java.util.List; + +import javax.xml.bind.JAXBElement; +import javax.xml.namespace.QName; + +import com.evolveum.midpoint.schema.util.ResourceTypeUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CapabilitiesType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CapabilityCollectionType; +import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.*; + +import org.apache.commons.lang.BooleanUtils; +import org.jetbrains.annotations.NotNull; +import org.w3c.dom.Element; + +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.util.DOMUtil; +import com.evolveum.midpoint.util.JAXBUtil; +import com.evolveum.midpoint.util.exception.SchemaException; + +/** + * @author semancik + * + */ +public class CapabilityUtil { + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static T getCapability(Collection capabilities, Class capabilityClass) { + if (capabilities == null) { + return null; + } + for (Object cap : capabilities) { + if (cap instanceof JAXBElement) { + JAXBElement element = (JAXBElement) cap; + if (capabilityClass.isAssignableFrom(element.getDeclaredType())) { + return (T) element.getValue(); + } + } else if (capabilityClass.isAssignableFrom(cap.getClass())) { + return (T) cap; + } + } + return null; + } + + public static boolean isCapabilityEnabled(Object capability) { + if (capability == null) { + return false; + } + if (capability instanceof JAXBElement) { + capability = ((JAXBElement)capability).getValue(); + } + + if (capability instanceof CapabilityType) { + return CapabilityUtil.isCapabilityEnabled((CapabilityType)capability); + } else if (capability instanceof Element) { + return CapabilityUtil.isCapabilityEnabled((Element)capability); + } else { + throw new IllegalArgumentException("Unexpected capability type "+capability.getClass()); + } + } + + private static boolean isCapabilityEnabled(Element capability) { + if (capability == null) { + return false; + } + ObjectFactory capabilitiesObjectFactory = new ObjectFactory(); + QName enabledElementName = capabilitiesObjectFactory.createEnabled(true).getName(); + Element enabledElement = DOMUtil.getChildElement(capability, enabledElementName); + return enabledElement == null || Boolean.parseBoolean(enabledElement.getTextContent()); + } + + public static boolean isCapabilityEnabled(T capability) { + if (capability == null) { + return false; + } + if (capability.isEnabled() == null) { + return true; + } + return capability.isEnabled(); + } + + public static Object getCapabilityWithSameElementName(List capabilities, Object capability) { + if (capabilities == null) { + return false; + } + QName capabilityElementName = JAXBUtil.getElementQName(capability); + for (Object cap: capabilities) { + QName capElementName = JAXBUtil.getElementQName(cap); + if (capabilityElementName.equals(capElementName)) { + return cap; + } + } + return null; + } + + public static boolean containsCapabilityWithSameElementName(List capabilities, Object capability) { + return getCapabilityWithSameElementName(capabilities, capability) != null; + } + + public static String getCapabilityDisplayName(Object capability) { + // TODO: look for schema annotation + String className; + if (capability instanceof JAXBElement) { + className = ((JAXBElement) capability).getDeclaredType().getSimpleName(); + } else { + className = capability.getClass().getSimpleName(); + } + if (className.endsWith("CapabilityType")) { + return className.substring(0, className.length() - "CapabilityType".length()); + } + return className; + } + + public static boolean isPasswordReturnedByDefault(CredentialsCapabilityType capability) { + if (capability == null) { + return false; + } + PasswordCapabilityType password = capability.getPassword(); + if (password == null) { + return false; + } + if (password.isReturnedByDefault() == null) { + return true; + } + return password.isReturnedByDefault(); + } + + public static boolean isPasswordReadable(CredentialsCapabilityType capabilityType) { + if (capabilityType == null) { + return false; + } + + PasswordCapabilityType passwordCapabilityType = capabilityType.getPassword(); + if (passwordCapabilityType == null) { + return false; + } + + if (BooleanUtils.isFalse(passwordCapabilityType.isEnabled())) { + return false; + } + + Boolean readable = passwordCapabilityType.isReadable(); + return BooleanUtils.isTrue(readable); + } + + public static boolean isActivationStatusReturnedByDefault(ActivationCapabilityType capability) { + if (capability == null) { + return false; + } + ActivationStatusCapabilityType statusCap = getEffectiveActivationStatus(capability); + if (statusCap == null) { + return false; + } + if (statusCap.isReturnedByDefault() == null) { + return true; + } + return statusCap.isReturnedByDefault(); + } + + public static boolean isActivationLockoutStatusReturnedByDefault(ActivationCapabilityType capability) { + if (capability == null) { + return false; + } + ActivationLockoutStatusCapabilityType statusCap = capability.getLockoutStatus(); + if (statusCap == null) { + return false; + } + if (statusCap.isReturnedByDefault() == null) { + return true; + } + return statusCap.isReturnedByDefault(); + } + + public static boolean isActivationValidFromReturnedByDefault(ActivationCapabilityType capability) { + if (capability == null) { + return false; + } + ActivationValidityCapabilityType valCap = capability.getValidFrom(); + if (valCap == null) { + return false; + } + if (valCap.isReturnedByDefault() == null) { + return true; + } + return valCap.isReturnedByDefault(); + } + + public static boolean isActivationValidToReturnedByDefault(ActivationCapabilityType capability) { + if (capability == null) { + return false; + } + ActivationValidityCapabilityType valCap = capability.getValidTo(); + if (valCap == null) { + return false; + } + if (valCap.isReturnedByDefault() == null) { + return true; + } + return valCap.isReturnedByDefault(); + } + + @SuppressWarnings("unchecked") + public static CapabilityType asCapabilityType(Object capabilityObject) { + return capabilityObject instanceof CapabilityType ? + (CapabilityType) capabilityObject : + ((JAXBElement) capabilityObject).getValue(); + } + + public static void fillDefaults(@NotNull CapabilityType capability) { + if (capability.isEnabled() == null) { + capability.setEnabled(true); + } + if (capability instanceof ActivationCapabilityType) { + ActivationCapabilityType act = ((ActivationCapabilityType) capability); + if (act.getStatus() == null) { + ActivationStatusCapabilityType st = new ActivationStatusCapabilityType(); + act.setStatus(st); + st.setEnabled(false); // TODO check if all midPoint code honors this flag! + st.setReturnedByDefault(false); + st.setIgnoreAttribute(true); + } else { + ActivationStatusCapabilityType st = act.getStatus(); + st.setEnabled(def(st.isEnabled(), true)); + st.setReturnedByDefault(def(st.isReturnedByDefault(), true)); + st.setIgnoreAttribute(def(st.isIgnoreAttribute(), true)); + } + if (act.getLockoutStatus() == null) { + ActivationLockoutStatusCapabilityType st = new ActivationLockoutStatusCapabilityType(); + act.setLockoutStatus(st); + st.setEnabled(false); + st.setReturnedByDefault(false); + st.setIgnoreAttribute(true); + } else { + ActivationLockoutStatusCapabilityType st = act.getLockoutStatus(); + st.setEnabled(def(st.isEnabled(), true)); + st.setReturnedByDefault(def(st.isReturnedByDefault(), true)); + st.setIgnoreAttribute(def(st.isIgnoreAttribute(), true)); + } + if (act.getValidFrom() == null) { + ActivationValidityCapabilityType vf = new ActivationValidityCapabilityType(); + act.setValidFrom(vf); + vf.setEnabled(false); + vf.setReturnedByDefault(false); + } else { + ActivationValidityCapabilityType vf = act.getValidFrom(); + vf.setEnabled(def(vf.isEnabled(), true)); + vf.setReturnedByDefault(def(vf.isReturnedByDefault(), true)); + } + if (act.getValidTo() == null) { + ActivationValidityCapabilityType vt = new ActivationValidityCapabilityType(); + act.setValidTo(vt); + vt.setEnabled(false); + vt.setReturnedByDefault(false); + } else { + ActivationValidityCapabilityType vt = act.getValidTo(); + vt.setEnabled(def(vt.isEnabled(), true)); + vt.setReturnedByDefault(def(vt.isReturnedByDefault(), true)); + } + } else if (capability instanceof CredentialsCapabilityType) { + CredentialsCapabilityType cred = ((CredentialsCapabilityType) capability); + if (cred.getPassword() == null) { + PasswordCapabilityType pc = new PasswordCapabilityType(); + cred.setPassword(pc); + pc.setEnabled(false); + pc.setReturnedByDefault(false); + } else { + PasswordCapabilityType pc = cred.getPassword(); + pc.setEnabled(def(pc.isEnabled(), true)); + pc.setReturnedByDefault(def(pc.isReturnedByDefault(), true)); + } + } + } + + private static Boolean def(Boolean originalValue, boolean defaultValue) { + return originalValue != null ? originalValue : defaultValue; + } + + public static T getEffectiveCapability(CapabilitiesType capabilitiesType, Class capabilityClass) { + if (capabilitiesType == null) { + return null; + } + if (capabilitiesType.getConfigured() != null) { + T configuredCapability = CapabilityUtil.getCapability(capabilitiesType.getConfigured().getAny(), capabilityClass); + if (configuredCapability != null) { + return configuredCapability; + } + // No configured capability entry, fallback to native capability + } + if (capabilitiesType.getNative() != null) { + T nativeCapability = CapabilityUtil.getCapability(capabilitiesType.getNative().getAny(), capabilityClass); + if (nativeCapability != null) { + return nativeCapability; + } + } + return null; + } + + public static ActivationStatusCapabilityType getEffectiveActivationStatus(ActivationCapabilityType act) { + if (act != null && act.getStatus() != null && !Boolean.FALSE.equals(act.getStatus().isEnabled())) { + return act.getStatus(); + } else { + return null; + } + } + + public static ActivationValidityCapabilityType getEffectiveActivationValidFrom(ActivationCapabilityType act) { + if (act != null && act.getValidFrom() != null && !Boolean.FALSE.equals(act.getValidFrom().isEnabled())) { + return act.getValidFrom(); + } else { + return null; + } + } + + public static ActivationValidityCapabilityType getEffectiveActivationValidTo(ActivationCapabilityType act) { + if (act != null && act.getValidTo() != null && !Boolean.FALSE.equals(act.getValidTo().isEnabled())) { + return act.getValidTo(); + } else { + return null; + } + } + + public static ActivationLockoutStatusCapabilityType getEffectiveActivationLockoutStatus(ActivationCapabilityType act) { + if (act != null && act.getLockoutStatus() != null && !Boolean.FALSE.equals(act.getLockoutStatus().isEnabled())) { + return act.getLockoutStatus(); + } else { + return null; + } + } + + public static boolean hasNativeCapability(CapabilitiesType capabilities, Class capabilityClass) { + if (capabilities == null) { + return false; + } + CapabilityCollectionType nativeCaps = capabilities.getNative(); + if (nativeCaps == null) { + return false; + } + return getCapability(nativeCaps.getAny(), capabilityClass) != null; + } + + public static boolean hasConfiguredCapability(CapabilitiesType capabilities, Class capabilityClass) { + if (capabilities == null) { + return false; + } + CapabilityCollectionType configuredCaps = capabilities.getConfigured(); + if (configuredCaps == null) { + return false; + } + return getCapability(configuredCaps.getAny(), capabilityClass) != null; + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java index 2aba3949e5f..47d0d89e598 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java @@ -1,492 +1,483 @@ -/* - * Copyright (c) 2010-2019 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.model.impl.lens.projector.credentials; - -import static com.evolveum.midpoint.prism.delta.ChangeType.MODIFY; - -import java.util.Collection; -import java.util.List; - -import javax.xml.datatype.XMLGregorianCalendar; - -import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.prism.delta.*; -import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.util.LocalizableMessageBuilder; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; -import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; -import com.evolveum.midpoint.model.common.mapping.MappingFactory; -import com.evolveum.midpoint.model.common.stringpolicy.ObjectValuePolicyEvaluator; -import com.evolveum.midpoint.model.common.stringpolicy.ShadowValuePolicyOriginResolver; -import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyProcessor; -import com.evolveum.midpoint.model.impl.ModelObjectResolver; -import com.evolveum.midpoint.model.impl.lens.LensContext; -import com.evolveum.midpoint.model.impl.lens.LensFocusContext; -import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; -import com.evolveum.midpoint.model.impl.lens.OperationalDataManager; -import com.evolveum.midpoint.model.impl.lens.projector.ContextLoader; -import com.evolveum.midpoint.model.impl.lens.projector.mappings.MappingEvaluator; -import com.evolveum.midpoint.model.impl.lens.projector.mappings.MappingInitializer; -import com.evolveum.midpoint.model.impl.lens.projector.mappings.MappingOutputProcessor; -import com.evolveum.midpoint.model.impl.lens.projector.mappings.MappingTimeEval; -import com.evolveum.midpoint.prism.crypto.EncryptionException; -import com.evolveum.midpoint.prism.crypto.Protector; -import com.evolveum.midpoint.prism.util.ItemDeltaItem; -import com.evolveum.midpoint.repo.common.expression.Source; -import com.evolveum.midpoint.repo.common.expression.ValuePolicyResolver; -import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; -import com.evolveum.midpoint.schema.constants.ExpressionConstants; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.util.ResourceTypeUtil; -import com.evolveum.midpoint.security.api.SecurityUtil; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.PolicyViolationException; -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.FocusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityPolicyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.VariableBindingDefinitionType; -import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType; -import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.PasswordCapabilityType; -import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; -import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; - -/** - * Processor for projection credentials. Which at this moment means just the password. - * - * @author Radovan Semancik - */ -@Component -public class ProjectionCredentialsProcessor { - - private static final Trace LOGGER = TraceManager.getTrace(ProjectionCredentialsProcessor.class); - - @Autowired private PrismContext prismContext; - @Autowired private ContextLoader contextLoader; - @Autowired private MappingFactory mappingFactory; - @Autowired private MappingEvaluator mappingEvaluator; - @Autowired private ValuePolicyProcessor valuePolicyProcessor; - @Autowired private Protector protector; - @Autowired private OperationalDataManager operationalDataManager; - @Autowired private ModelObjectResolver modelObjectResolver; - - public void processProjectionCredentials(LensContext context, - LensProjectionContext projectionContext, XMLGregorianCalendar now, Task task, - OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, - SchemaException, PolicyViolationException, CommunicationException, ConfigurationException, SecurityViolationException { - - if (projectionContext.isDelete()) { - return; - } - - LensFocusContext focusContext = context.getFocusContext(); - if (focusContext != null && FocusType.class.isAssignableFrom(focusContext.getObjectTypeClass())) { - - processProjectionCredentialsFocus((LensContext) context, projectionContext, now, task, result); - - } - } - - private void processProjectionCredentialsFocus(LensContext context, - LensProjectionContext projectionContext, XMLGregorianCalendar now, Task task, - OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, - SchemaException, PolicyViolationException, CommunicationException, ConfigurationException, SecurityViolationException { - - SecurityPolicyType securityPolicy = determineSecurityPolicy(context, projectionContext, now, task, result); - - processProjectionPasswordMapping(context, projectionContext, securityPolicy, now, task, result); - - validateProjectionPassword(context, projectionContext, securityPolicy, now, task, result); - - applyMetadata(context, projectionContext, now, task, result); - } - - private void processProjectionPasswordMapping(LensContext context, - final LensProjectionContext projCtx, final SecurityPolicyType securityPolicy, XMLGregorianCalendar now, Task task, OperationResult result) - throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { - LensFocusContext focusContext = context.getFocusContext(); - - PrismObject 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 accountDefinition = prismContext.getSchemaRegistry() - .findObjectDefinitionByCompileTimeClass(ShadowType.class); - PrismPropertyDefinition projPasswordPropertyDefinition = accountDefinition - .findPropertyDefinition(SchemaConstants.PATH_PASSWORD_VALUE); - - ResourceShadowDiscriminator rsd = projCtx.getResourceShadowDiscriminator(); - - RefinedObjectClassDefinition refinedProjDef = projCtx.getStructuralObjectClassDefinition(); - if (refinedProjDef == null) { - LOGGER.trace("No RefinedObjectClassDefinition, therefore also no password outbound definition, skipping credentials processing for projection {}", rsd); - return; - } - - List outboundMappingTypes = refinedProjDef.getPasswordOutbound(); - if (outboundMappingTypes == null || outboundMappingTypes.isEmpty()) { - LOGGER.trace("No outbound password mapping for {}, skipping credentials processing", rsd); - return; - } - - // HACK - if (!projCtx.isDoReconciliation() && !projCtx.isAdd() && !isActivated(outboundMappingTypes, focusContext.getDelta())) { - LOGGER.trace("Outbound password mappings not activated for type {}, skipping credentials processing", rsd); - return; - } - - ObjectDelta projDelta = projCtx.getDelta(); - PropertyDelta projPasswordDelta; - if (projDelta != null && projDelta.getChangeType() == MODIFY) { - projPasswordDelta = projDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); - } else { - projPasswordDelta = null; - } - checkExistingDeltaSanity(projCtx, projPasswordDelta); - - boolean evaluateWeak = getEvaluateWeak(projCtx); - - ItemDeltaItem, PrismPropertyDefinition> focusPasswordIdi = focusContext - .getObjectDeltaObject().findIdi(SchemaConstants.PATH_PASSWORD_VALUE); - - ValuePolicyResolver stringPolicyResolver = new ValuePolicyResolver() { - @Override - public void setOutputPath(ItemPath outputPath) { - } - @Override - public void setOutputDefinition(ItemDefinition outputDefinition) { - } - @Override - public ValuePolicyType resolve() { - return SecurityUtil.getPasswordPolicy(securityPolicy); - } - }; - - MappingInitializer,PrismPropertyDefinition> initializer = - (builder) -> { - builder.defaultTargetDefinition(projPasswordPropertyDefinition); - builder.defaultSource(new Source<>(focusPasswordIdi, ExpressionConstants.VAR_INPUT_QNAME)); - builder.valuePolicyResolver(stringPolicyResolver); - return builder; - }; - - MappingOutputProcessor> processor = - (mappingOutputPath, outputStruct) -> { - PrismValueDeltaSetTriple> 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> newValues; - if (projectionIsNew) { - newValues = outputTriple.getNonNegativeValues(); - } else { - newValues = outputTriple.getPlusSet(); - } - - if (!canGetCleartext(newValues)) { - ObjectDelta projectionPrimaryDelta = projCtx.getPrimaryDelta(); - if (projectionPrimaryDelta != null) { - PropertyDelta 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> minusSet = outputTriple.getMinusSet(); - if (minusSet != null && !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 focusPasswordDelta = (PropertyDelta) focusPasswordIdi.getDelta(); - Collection> focusPasswordDeltaOldValues = focusPasswordDelta.getEstimatedOldValues(); - if (focusPasswordDeltaOldValues != null && !focusPasswordDeltaOldValues.isEmpty()) { - ProtectedStringType oldFocusPassword = 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; - }; - - - mappingEvaluator.evaluateOutboundMapping(context, projCtx, outboundMappingTypes, - SchemaConstants.PATH_PASSWORD_VALUE, SchemaConstants.PATH_PASSWORD_VALUE, initializer, processor, - now, MappingTimeEval.CURRENT, evaluateWeak, "password mapping", task, result); - - } - - private boolean isActivated(List outboundMappingTypes, ObjectDelta focusDelta) { - if (focusDelta == null) { - return false; - } - for (MappingType outboundMappingType: outboundMappingTypes) { - List sources = outboundMappingType.getSource(); - if (sources.isEmpty()) { - // Default source - if (focusDelta.hasItemDelta(SchemaConstants.PATH_PASSWORD_VALUE)) { - return true; - } - } - for (VariableBindingDefinitionType source: sources) { - ItemPathType pathType = source.getPath(); - ItemPath path = pathType.getItemPath().stripVariableSegment(); - if (focusDelta.hasItemDelta(path)) { - return true; - } - } - } - return false; - } - - private boolean canGetCleartext(Collection> pvals) { - if (pvals == null) { - return false; - } - for (PrismPropertyValue pval: pvals) { - if (pval.getValue().canGetCleartext()) { - return true; - } - } - return false; - } - - private boolean getEvaluateWeak(LensProjectionContext projCtx) { - CredentialsCapabilityType credentialsCapabilityType = ResourceTypeUtil.getEffectiveCapability(projCtx.getResource(), CredentialsCapabilityType.class); - if (credentialsCapabilityType != null) { - PasswordCapabilityType passwordCapabilityType = credentialsCapabilityType.getPassword(); - if (passwordCapabilityType != null) { - if (passwordCapabilityType.isEnabled() != Boolean.FALSE) { - Boolean readable = passwordCapabilityType.isReadable(); - if (readable != null && readable) { - // If we have readable password then we can evaluate the weak mappings - // normally (even if the reads return incomplete values). - return true; - } - } - } - } - // Password not readable. Therefore evaluate weak mappings only during add operaitons. - // We do not know whether there is a password already set on the resource. And we do not - // want to overwrite it every time. - return projCtx.isAdd(); - } - - private void validateProjectionPassword(LensContext context, - final LensProjectionContext projectionContext, final SecurityPolicyType securityPolicy, XMLGregorianCalendar now, Task task, OperationResult result) - throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException, CommunicationException, ConfigurationException, SecurityViolationException { - - if (securityPolicy == null) { - LOGGER.trace("Skipping processing password policies. Security policy not specified."); - return; - } - - ObjectDelta accountDelta = projectionContext.getDelta(); - - if (accountDelta == null){ - LOGGER.trace("Skipping processing password policies. Shadow delta not specified."); - return; - } - - if (accountDelta.isDelete()) { - return; - } - - PrismObject accountShadow = null; - PrismProperty password = null; - if (accountDelta.isAdd()) { - accountShadow = accountDelta.getObjectToAdd(); - if (accountShadow != null){ - password = accountShadow.findProperty(SchemaConstants.PATH_PASSWORD_VALUE); - } - } - if (accountDelta.isModify() || password == null) { - PropertyDelta passwordValueDelta = - accountDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); - // Modification sanity check - if (accountDelta.getChangeType() == ChangeType.MODIFY && passwordValueDelta != null - && (passwordValueDelta.isAdd() || passwordValueDelta.isDelete())) { - throw new SchemaException("Shadow password value cannot be added or deleted, it can only be replaced"); - } - if (passwordValueDelta == null) { - LOGGER.trace("Skipping processing password policies. Shadow delta does not contain password change."); - return; - } - password = (PrismProperty) passwordValueDelta.getItemNewMatchingPath(null); - } - - if (accountShadow == null) { - accountShadow = projectionContext.getObjectNew(); - } - - String passwordValue = determinePasswordValue(password); - - ObjectValuePolicyEvaluator objectValuePolicyEvaluator = new ObjectValuePolicyEvaluator.Builder() - .now(now) - .originResolver(getOriginResolver(accountShadow)) - .protector(protector) - .securityPolicy(securityPolicy) - .shortDesc("password for " + accountShadow) - .task(task) - .valueItemPath(SchemaConstants.PATH_PASSWORD_VALUE) - .valuePolicyProcessor(valuePolicyProcessor) - .build(); - OperationResult validationResult = objectValuePolicyEvaluator.validateStringValue(passwordValue, result); - -// boolean isValid = valuePolicyProcessor.validateValue(passwordValue, securityPolicy, getOriginResolver(accountShadow), "projection password policy", task, result); - - if (!validationResult.isSuccess()) { - LOGGER.debug("Password for projection {} is not valid (policy={}): {}", projectionContext.getHumanReadableName(), securityPolicy, validationResult.getUserFriendlyMessage()); - result.computeStatus(); - throw new PolicyViolationException( - new LocalizableMessageBuilder() - .key("PolicyViolationException.message.projectionPassword") - .arg(projectionContext.getHumanReadableName()) - .arg(validationResult.getUserFriendlyMessage()) - .build()); - } - } - - private ShadowValuePolicyOriginResolver getOriginResolver(PrismObject accountShadow) { - return new ShadowValuePolicyOriginResolver(accountShadow, modelObjectResolver); - } - - private void applyMetadata(LensContext context, - final LensProjectionContext projectionContext, XMLGregorianCalendar now, Task task, OperationResult result) - throws SchemaException { - - ObjectDelta accountDelta = projectionContext.getDelta(); - - if (projectionContext.isDelete()) { - return; - } - - if (accountDelta == null) { - LOGGER.trace("Skipping application of password metadata. Shadow delta not specified."); - return; - } - - PropertyDelta passwordValueDelta = - accountDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); - if (passwordValueDelta == null) { - LOGGER.trace("Skipping application of password metadata. No password change."); - return; - } - - if (projectionContext.isAdd()) { - MetadataType metadataType = operationalDataManager.createCreateMetadata(context, now, task); - ContainerDelta metadataDelta = prismContext.deltaFactory().container() - .createDelta(SchemaConstants.PATH_PASSWORD_METADATA, projectionContext.getObjectDefinition()); - PrismContainerValue cval = metadataType.asPrismContainerValue(); - cval.setOriginTypeRecursive(OriginType.OUTBOUND); - metadataDelta.addValuesToAdd(metadataType.asPrismContainerValue()); - projectionContext.swallowToSecondaryDelta(metadataDelta); - - } else if (projectionContext.isModify()) { - ContainerDelta metadataDelta = accountDelta.findContainerDelta(SchemaConstants.PATH_PASSWORD_METADATA); - if (metadataDelta == null) { - Collection> modifyMetadataDeltas = operationalDataManager.createModifyMetadataDeltas(context, SchemaConstants.PATH_PASSWORD_METADATA, projectionContext.getObjectTypeClass(), now, task); - for (ItemDelta itemDelta: modifyMetadataDeltas) { - itemDelta.setOriginTypeRecursive(OriginType.OUTBOUND); - projectionContext.swallowToSecondaryDelta(itemDelta); - } - } - } - - } - - private SecurityPolicyType determineSecurityPolicy(LensContext context, - final LensProjectionContext projCtx, XMLGregorianCalendar now, Task task, OperationResult result) { - SecurityPolicyType securityPolicy = projCtx.getProjectionSecurityPolicy(); - if (securityPolicy != null) { - return securityPolicy; - } - return context.getGlobalSecurityPolicy(); - } - - // On missing password this returns empty string (""). It is then up to password policy whether it allows empty passwords or not. - private String determinePasswordValue(PrismProperty password) { - if (password == null || password.getValue(ProtectedStringType.class) == null) { - return null; - } - - ProtectedStringType passValue = password.getRealValue(); - - return determinePasswordValue(passValue); - } - - private String determinePasswordValue(ProtectedStringType passValue) { - if (passValue == null) { - return null; - } - - String passwordStr = passValue.getClearValue(); - - if (passwordStr == null && passValue.getEncryptedDataType () != null) { - // TODO: is this appropriate handling??? - try { - passwordStr = protector.decryptString(passValue); - } catch (EncryptionException ex) { - throw new SystemException("Failed to process password for focus: " + ex.getMessage(), ex); - } - } - - return passwordStr; - } - - private void checkExistingDeltaSanity(LensProjectionContext projCtx, - PropertyDelta passwordDelta) throws SchemaException { - if (passwordDelta != null && (passwordDelta.isAdd() || passwordDelta.isDelete())) { - throw new SchemaException("Password for projection " + projCtx.getResourceShadowDiscriminator() - + " cannot be added or deleted, it can only be replaced"); - } - } - -} +/* + * Copyright (c) 2010-2019 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.model.impl.lens.projector.credentials; + +import static com.evolveum.midpoint.prism.delta.ChangeType.MODIFY; + +import java.util.Collection; +import java.util.List; + +import javax.xml.datatype.XMLGregorianCalendar; + +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.*; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.schema.CapabilityUtil; +import com.evolveum.midpoint.util.LocalizableMessageBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; +import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; +import com.evolveum.midpoint.model.common.mapping.MappingFactory; +import com.evolveum.midpoint.model.common.stringpolicy.ObjectValuePolicyEvaluator; +import com.evolveum.midpoint.model.common.stringpolicy.ShadowValuePolicyOriginResolver; +import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyProcessor; +import com.evolveum.midpoint.model.impl.ModelObjectResolver; +import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.model.impl.lens.LensFocusContext; +import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; +import com.evolveum.midpoint.model.impl.lens.OperationalDataManager; +import com.evolveum.midpoint.model.impl.lens.projector.ContextLoader; +import com.evolveum.midpoint.model.impl.lens.projector.mappings.MappingEvaluator; +import com.evolveum.midpoint.model.impl.lens.projector.mappings.MappingInitializer; +import com.evolveum.midpoint.model.impl.lens.projector.mappings.MappingOutputProcessor; +import com.evolveum.midpoint.model.impl.lens.projector.mappings.MappingTimeEval; +import com.evolveum.midpoint.prism.crypto.EncryptionException; +import com.evolveum.midpoint.prism.crypto.Protector; +import com.evolveum.midpoint.prism.util.ItemDeltaItem; +import com.evolveum.midpoint.repo.common.expression.Source; +import com.evolveum.midpoint.repo.common.expression.ValuePolicyResolver; +import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; +import com.evolveum.midpoint.schema.constants.ExpressionConstants; +import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ResourceTypeUtil; +import com.evolveum.midpoint.security.api.SecurityUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.CommunicationException; +import com.evolveum.midpoint.util.exception.ConfigurationException; +import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.PolicyViolationException; +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.FocusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityPolicyType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.VariableBindingDefinitionType; +import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType; +import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.PasswordCapabilityType; +import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; + +/** + * Processor for projection credentials. Which at this moment means just the password. + * + * @author Radovan Semancik + */ +@Component +public class ProjectionCredentialsProcessor { + + private static final Trace LOGGER = TraceManager.getTrace(ProjectionCredentialsProcessor.class); + + @Autowired private PrismContext prismContext; + @Autowired private ContextLoader contextLoader; + @Autowired private MappingFactory mappingFactory; + @Autowired private MappingEvaluator mappingEvaluator; + @Autowired private ValuePolicyProcessor valuePolicyProcessor; + @Autowired private Protector protector; + @Autowired private OperationalDataManager operationalDataManager; + @Autowired private ModelObjectResolver modelObjectResolver; + + public void processProjectionCredentials(LensContext context, + LensProjectionContext projectionContext, XMLGregorianCalendar now, Task task, + OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, + SchemaException, PolicyViolationException, CommunicationException, ConfigurationException, SecurityViolationException { + + if (projectionContext.isDelete()) { + return; + } + + LensFocusContext focusContext = context.getFocusContext(); + if (focusContext != null && FocusType.class.isAssignableFrom(focusContext.getObjectTypeClass())) { + + processProjectionCredentialsFocus((LensContext) context, projectionContext, now, task, result); + + } + } + + private void processProjectionCredentialsFocus(LensContext context, + LensProjectionContext projectionContext, XMLGregorianCalendar now, Task task, + OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, + SchemaException, PolicyViolationException, CommunicationException, ConfigurationException, SecurityViolationException { + + SecurityPolicyType securityPolicy = determineSecurityPolicy(context, projectionContext, now, task, result); + + processProjectionPasswordMapping(context, projectionContext, securityPolicy, now, task, result); + + validateProjectionPassword(context, projectionContext, securityPolicy, now, task, result); + + applyMetadata(context, projectionContext, now, task, result); + } + + private void processProjectionPasswordMapping(LensContext context, + final LensProjectionContext projCtx, final SecurityPolicyType securityPolicy, XMLGregorianCalendar now, Task task, OperationResult result) + throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { + LensFocusContext focusContext = context.getFocusContext(); + + PrismObject 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 accountDefinition = prismContext.getSchemaRegistry() + .findObjectDefinitionByCompileTimeClass(ShadowType.class); + PrismPropertyDefinition projPasswordPropertyDefinition = accountDefinition + .findPropertyDefinition(SchemaConstants.PATH_PASSWORD_VALUE); + + ResourceShadowDiscriminator rsd = projCtx.getResourceShadowDiscriminator(); + + RefinedObjectClassDefinition refinedProjDef = projCtx.getStructuralObjectClassDefinition(); + if (refinedProjDef == null) { + LOGGER.trace("No RefinedObjectClassDefinition, therefore also no password outbound definition, skipping credentials processing for projection {}", rsd); + return; + } + + List outboundMappingTypes = refinedProjDef.getPasswordOutbound(); + if (outboundMappingTypes == null || outboundMappingTypes.isEmpty()) { + LOGGER.trace("No outbound password mapping for {}, skipping credentials processing", rsd); + return; + } + + // HACK + if (!projCtx.isDoReconciliation() && !projCtx.isAdd() && !isActivated(outboundMappingTypes, focusContext.getDelta())) { + LOGGER.trace("Outbound password mappings not activated for type {}, skipping credentials processing", rsd); + return; + } + + ObjectDelta projDelta = projCtx.getDelta(); + PropertyDelta projPasswordDelta; + if (projDelta != null && projDelta.getChangeType() == MODIFY) { + projPasswordDelta = projDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); + } else { + projPasswordDelta = null; + } + checkExistingDeltaSanity(projCtx, projPasswordDelta); + + boolean evaluateWeak = getEvaluateWeak(projCtx); + + ItemDeltaItem, PrismPropertyDefinition> focusPasswordIdi = focusContext + .getObjectDeltaObject().findIdi(SchemaConstants.PATH_PASSWORD_VALUE); + + ValuePolicyResolver stringPolicyResolver = new ValuePolicyResolver() { + @Override + public void setOutputPath(ItemPath outputPath) { + } + @Override + public void setOutputDefinition(ItemDefinition outputDefinition) { + } + @Override + public ValuePolicyType resolve() { + return SecurityUtil.getPasswordPolicy(securityPolicy); + } + }; + + MappingInitializer,PrismPropertyDefinition> initializer = + (builder) -> { + builder.defaultTargetDefinition(projPasswordPropertyDefinition); + builder.defaultSource(new Source<>(focusPasswordIdi, ExpressionConstants.VAR_INPUT_QNAME)); + builder.valuePolicyResolver(stringPolicyResolver); + return builder; + }; + + MappingOutputProcessor> processor = + (mappingOutputPath, outputStruct) -> { + PrismValueDeltaSetTriple> 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> newValues; + if (projectionIsNew) { + newValues = outputTriple.getNonNegativeValues(); + } else { + newValues = outputTriple.getPlusSet(); + } + + if (!canGetCleartext(newValues)) { + ObjectDelta projectionPrimaryDelta = projCtx.getPrimaryDelta(); + if (projectionPrimaryDelta != null) { + PropertyDelta 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> minusSet = outputTriple.getMinusSet(); + if (minusSet != null && !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 focusPasswordDelta = (PropertyDelta) focusPasswordIdi.getDelta(); + Collection> focusPasswordDeltaOldValues = focusPasswordDelta.getEstimatedOldValues(); + if (focusPasswordDeltaOldValues != null && !focusPasswordDeltaOldValues.isEmpty()) { + ProtectedStringType oldFocusPassword = 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; + }; + + + mappingEvaluator.evaluateOutboundMapping(context, projCtx, outboundMappingTypes, + SchemaConstants.PATH_PASSWORD_VALUE, SchemaConstants.PATH_PASSWORD_VALUE, initializer, processor, + now, MappingTimeEval.CURRENT, evaluateWeak, "password mapping", task, result); + + } + + private boolean isActivated(List outboundMappingTypes, ObjectDelta focusDelta) { + if (focusDelta == null) { + return false; + } + for (MappingType outboundMappingType: outboundMappingTypes) { + List sources = outboundMappingType.getSource(); + if (sources.isEmpty()) { + // Default source + if (focusDelta.hasItemDelta(SchemaConstants.PATH_PASSWORD_VALUE)) { + return true; + } + } + for (VariableBindingDefinitionType source: sources) { + ItemPathType pathType = source.getPath(); + ItemPath path = pathType.getItemPath().stripVariableSegment(); + if (focusDelta.hasItemDelta(path)) { + return true; + } + } + } + return false; + } + + private boolean canGetCleartext(Collection> pvals) { + if (pvals == null) { + return false; + } + for (PrismPropertyValue pval: pvals) { + if (pval.getValue().canGetCleartext()) { + return true; + } + } + return false; + } + + private boolean getEvaluateWeak(LensProjectionContext projCtx) { + CredentialsCapabilityType credentialsCapabilityType = ResourceTypeUtil.getEffectiveCapability(projCtx.getResource(), CredentialsCapabilityType.class); + if (CapabilityUtil.isPasswordReadable(credentialsCapabilityType)) { + return true; + } + // Password not readable. Therefore evaluate weak mappings only during add operaitons. + // We do not know whether there is a password already set on the resource. And we do not + // want to overwrite it every time. + return projCtx.isAdd(); + } + + private void validateProjectionPassword(LensContext context, + final LensProjectionContext projectionContext, final SecurityPolicyType securityPolicy, XMLGregorianCalendar now, Task task, OperationResult result) + throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException, CommunicationException, ConfigurationException, SecurityViolationException { + + if (securityPolicy == null) { + LOGGER.trace("Skipping processing password policies. Security policy not specified."); + return; + } + + ObjectDelta accountDelta = projectionContext.getDelta(); + + if (accountDelta == null){ + LOGGER.trace("Skipping processing password policies. Shadow delta not specified."); + return; + } + + if (accountDelta.isDelete()) { + return; + } + + PrismObject accountShadow = null; + PrismProperty password = null; + if (accountDelta.isAdd()) { + accountShadow = accountDelta.getObjectToAdd(); + if (accountShadow != null){ + password = accountShadow.findProperty(SchemaConstants.PATH_PASSWORD_VALUE); + } + } + if (accountDelta.isModify() || password == null) { + PropertyDelta passwordValueDelta = + accountDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); + // Modification sanity check + if (accountDelta.getChangeType() == ChangeType.MODIFY && passwordValueDelta != null + && (passwordValueDelta.isAdd() || passwordValueDelta.isDelete())) { + throw new SchemaException("Shadow password value cannot be added or deleted, it can only be replaced"); + } + if (passwordValueDelta == null) { + LOGGER.trace("Skipping processing password policies. Shadow delta does not contain password change."); + return; + } + password = (PrismProperty) passwordValueDelta.getItemNewMatchingPath(null); + } + + if (accountShadow == null) { + accountShadow = projectionContext.getObjectNew(); + } + + String passwordValue = determinePasswordValue(password); + + ObjectValuePolicyEvaluator objectValuePolicyEvaluator = new ObjectValuePolicyEvaluator.Builder() + .now(now) + .originResolver(getOriginResolver(accountShadow)) + .protector(protector) + .securityPolicy(securityPolicy) + .shortDesc("password for " + accountShadow) + .task(task) + .valueItemPath(SchemaConstants.PATH_PASSWORD_VALUE) + .valuePolicyProcessor(valuePolicyProcessor) + .build(); + OperationResult validationResult = objectValuePolicyEvaluator.validateStringValue(passwordValue, result); + +// boolean isValid = valuePolicyProcessor.validateValue(passwordValue, securityPolicy, getOriginResolver(accountShadow), "projection password policy", task, result); + + if (!validationResult.isSuccess()) { + LOGGER.debug("Password for projection {} is not valid (policy={}): {}", projectionContext.getHumanReadableName(), securityPolicy, validationResult.getUserFriendlyMessage()); + result.computeStatus(); + throw new PolicyViolationException( + new LocalizableMessageBuilder() + .key("PolicyViolationException.message.projectionPassword") + .arg(projectionContext.getHumanReadableName()) + .arg(validationResult.getUserFriendlyMessage()) + .build()); + } + } + + private ShadowValuePolicyOriginResolver getOriginResolver(PrismObject accountShadow) { + return new ShadowValuePolicyOriginResolver(accountShadow, modelObjectResolver); + } + + private void applyMetadata(LensContext context, + final LensProjectionContext projectionContext, XMLGregorianCalendar now, Task task, OperationResult result) + throws SchemaException { + + ObjectDelta accountDelta = projectionContext.getDelta(); + + if (projectionContext.isDelete()) { + return; + } + + if (accountDelta == null) { + LOGGER.trace("Skipping application of password metadata. Shadow delta not specified."); + return; + } + + PropertyDelta passwordValueDelta = + accountDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); + if (passwordValueDelta == null) { + LOGGER.trace("Skipping application of password metadata. No password change."); + return; + } + + if (projectionContext.isAdd()) { + MetadataType metadataType = operationalDataManager.createCreateMetadata(context, now, task); + ContainerDelta metadataDelta = prismContext.deltaFactory().container() + .createDelta(SchemaConstants.PATH_PASSWORD_METADATA, projectionContext.getObjectDefinition()); + PrismContainerValue cval = metadataType.asPrismContainerValue(); + cval.setOriginTypeRecursive(OriginType.OUTBOUND); + metadataDelta.addValuesToAdd(metadataType.asPrismContainerValue()); + projectionContext.swallowToSecondaryDelta(metadataDelta); + + } else if (projectionContext.isModify()) { + ContainerDelta metadataDelta = accountDelta.findContainerDelta(SchemaConstants.PATH_PASSWORD_METADATA); + if (metadataDelta == null) { + Collection> modifyMetadataDeltas = operationalDataManager.createModifyMetadataDeltas(context, SchemaConstants.PATH_PASSWORD_METADATA, projectionContext.getObjectTypeClass(), now, task); + for (ItemDelta itemDelta: modifyMetadataDeltas) { + itemDelta.setOriginTypeRecursive(OriginType.OUTBOUND); + projectionContext.swallowToSecondaryDelta(itemDelta); + } + } + } + + } + + private SecurityPolicyType determineSecurityPolicy(LensContext context, + final LensProjectionContext projCtx, XMLGregorianCalendar now, Task task, OperationResult result) { + SecurityPolicyType securityPolicy = projCtx.getProjectionSecurityPolicy(); + if (securityPolicy != null) { + return securityPolicy; + } + return context.getGlobalSecurityPolicy(); + } + + // On missing password this returns empty string (""). It is then up to password policy whether it allows empty passwords or not. + private String determinePasswordValue(PrismProperty password) { + if (password == null || password.getValue(ProtectedStringType.class) == null) { + return null; + } + + ProtectedStringType passValue = password.getRealValue(); + + return determinePasswordValue(passValue); + } + + private String determinePasswordValue(ProtectedStringType passValue) { + if (passValue == null) { + return null; + } + + String passwordStr = passValue.getClearValue(); + + if (passwordStr == null && passValue.getEncryptedDataType () != null) { + // TODO: is this appropriate handling??? + try { + passwordStr = protector.decryptString(passValue); + } catch (EncryptionException ex) { + throw new SystemException("Failed to process password for focus: " + ex.getMessage(), ex); + } + } + + return passwordStr; + } + + private void checkExistingDeltaSanity(LensProjectionContext projCtx, + PropertyDelta passwordDelta) throws SchemaException { + if (passwordDelta != null && (passwordDelta.isAdd() || passwordDelta.isDelete())) { + throw new SchemaException("Password for projection " + projCtx.getResourceShadowDiscriminator() + + " cannot be added or deleted, it can only be replaced"); + } + } + +} From cd64620ab321839c4d53e2a3fa5aa6b0dbd271a0 Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Thu, 12 Mar 2020 23:35:50 +0100 Subject: [PATCH 5/5] fix for MID-6036 --- .../web/util/ExpressionValidator.java | 287 +++++++++--------- 1 file changed, 139 insertions(+), 148 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionValidator.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionValidator.java index 679029f1823..55e2f6bbc33 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionValidator.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/util/ExpressionValidator.java @@ -1,148 +1,139 @@ -/* - * Copyright (c) 2010-2019 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ -package com.evolveum.midpoint.web.util; - -import java.util.Collection; - -import com.evolveum.midpoint.prism.PrismContext; - -import org.apache.wicket.model.IModel; -import org.apache.wicket.validation.INullAcceptingValidator; -import org.apache.wicket.validation.IValidatable; -import org.apache.wicket.validation.ValidationError; - -import com.evolveum.midpoint.gui.api.util.ModelServiceLocator; -import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; -import com.evolveum.midpoint.prism.PrismPropertyDefinition; -import com.evolveum.midpoint.prism.PrismPropertyValue; -import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; -import com.evolveum.midpoint.repo.common.expression.Expression; -import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext; -import com.evolveum.midpoint.repo.common.expression.ExpressionFactory; -import com.evolveum.midpoint.repo.common.expression.ExpressionVariables; -import com.evolveum.midpoint.schema.constants.ExpressionConstants; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.util.MiscSchemaUtil; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -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.xml.ns._public.common.common_3.ExpressionType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; - -public class ExpressionValidator implements INullAcceptingValidator { - - private static final long serialVersionUID = 1L; - -// private InputPanel inputPanel; - private IModel expressionTypeModel; - private ModelServiceLocator serviceLocator; -// private T realValue; - - private static final String OPERATION_EVALUATE_EXPRESSION = ExpressionValidator.class.getName() + ".evaluateValidationExpression"; - - public ExpressionValidator(IModel expressionType, ModelServiceLocator serviceLocator) { -// this.inputPanel = inputPanel; - this.expressionTypeModel = expressionType; - this.serviceLocator = serviceLocator; -// this.realValue = realValue; - } - - - - @Override - public void validate(IValidatable validatable) { - ExpressionType expressionType = expressionTypeModel.getObject(); - - if (expressionType == null) { - return; - } - - PrismContext prismContext = serviceLocator.getPrismContext(); - Object valueToValidate = getValueToValidate(validatable); - String contextDesc = " form component expression validation "; - PrismPropertyDefinition outputDefinition = prismContext.definitionFactory().createPropertyDefinition(ExpressionConstants.OUTPUT_ELEMENT_NAME, - OperationResultType.COMPLEX_TYPE); - Task task = serviceLocator.createSimpleTask(OPERATION_EVALUATE_EXPRESSION); - OperationResult result = new OperationResult(OPERATION_EVALUATE_EXPRESSION); - ExpressionFactory expressionFactory = serviceLocator.getExpressionFactory(); - Expression, PrismPropertyDefinition> expression; - try { - - expression = expressionFactory - .makeExpression(expressionType, outputDefinition, MiscSchemaUtil.getExpressionProfile(), contextDesc, task, result); - } catch (SchemaException | ObjectNotFoundException | SecurityViolationException e) { - ValidationError error = new ValidationError(); - error.setMessage("Cannot make expression: " + e.getMessage()); - validatable.error(error); -// form.error("Cannot make expression: " + e.getMessage()); - return; - } - ExpressionVariables variables = new ExpressionVariables(); - if (valueToValidate != null) { - variables.put(ExpressionConstants.VAR_INPUT, valueToValidate, valueToValidate.getClass()); - } - variables.putObject(ExpressionConstants.VAR_OBJECT, (ObjectType)getObjectType(), ObjectType.class); -// addAdditionalExpressionVariables(variables); - ExpressionEvaluationContext context = new ExpressionEvaluationContext(null, variables, contextDesc, task); - PrismValueDeltaSetTriple> outputTriple; - try { - outputTriple = expression.evaluate(context, result); - } catch (SchemaException | ExpressionEvaluationException | ObjectNotFoundException | CommunicationException - | ConfigurationException | SecurityViolationException e) { - ValidationError error = new ValidationError(); - error.setMessage("Cannot evaluate expression: " + e.getMessage()); - validatable.error(error); -// form.error("Cannot evaluate expression: " + e.getMessage()); - return; - } - if (outputTriple == null) { - return; - } - Collection> outputValues = outputTriple.getNonNegativeValues(); - if (outputValues.isEmpty()) { - return; - } - if (outputValues.size() > 1) { - ValidationError error = new ValidationError(); - error.setMessage("Expression "+contextDesc+" produced more than one value"); - validatable.error(error); -// form.error("Expression "+contextDesc+" produced more than one value"); - } - - OperationResultType operationResultType = outputValues.iterator().next().getRealValue(); - - if (operationResultType == null) { - return; - } - - OperationResult returnResult = OperationResult.createOperationResult(operationResultType); - if (!returnResult.isSuccess()) { - ValidationError error = new ValidationError(); - if (returnResult.getUserFriendlyMessage() != null) { - error.setMessage(WebModelServiceUtils.translateMessage(returnResult, serviceLocator)); - } else { - error.setMessage(returnResult.getMessage()); - } - validatable.error(error); - } - - } - - protected O getObjectType() { - return null; - } - - protected Object getValueToValidate(IValidatable validatable) { - return validatable.getValue(); - } - -} +/* + * Copyright (c) 2010-2019 Evolveum and contributors + * + * This work is dual-licensed under the Apache License 2.0 + * and European Union Public License. See LICENSE file for details. + */ +package com.evolveum.midpoint.web.util; + +import java.util.Collection; + +import com.evolveum.midpoint.prism.PrismContext; + +import org.apache.wicket.model.IModel; +import org.apache.wicket.validation.INullAcceptingValidator; +import org.apache.wicket.validation.IValidatable; +import org.apache.wicket.validation.ValidationError; + +import com.evolveum.midpoint.gui.api.util.ModelServiceLocator; +import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; +import com.evolveum.midpoint.prism.PrismPropertyDefinition; +import com.evolveum.midpoint.prism.PrismPropertyValue; +import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.repo.common.expression.Expression; +import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext; +import com.evolveum.midpoint.repo.common.expression.ExpressionFactory; +import com.evolveum.midpoint.repo.common.expression.ExpressionVariables; +import com.evolveum.midpoint.schema.constants.ExpressionConstants; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.MiscSchemaUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.CommunicationException; +import com.evolveum.midpoint.util.exception.ConfigurationException; +import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; +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.xml.ns._public.common.common_3.ExpressionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; + +public class ExpressionValidator implements INullAcceptingValidator { + + private static final long serialVersionUID = 1L; + + private IModel expressionTypeModel; + private ModelServiceLocator serviceLocator; + + private static final String OPERATION_EVALUATE_EXPRESSION = ExpressionValidator.class.getName() + ".evaluateValidationExpression"; + + public ExpressionValidator(IModel expressionType, ModelServiceLocator serviceLocator) { + this.expressionTypeModel = expressionType; + this.serviceLocator = serviceLocator; + } + + + + @Override + public void validate(IValidatable validatable) { + ExpressionType expressionType = expressionTypeModel.getObject(); + + if (expressionType == null) { + return; + } + + PrismContext prismContext = serviceLocator.getPrismContext(); + Object valueToValidate = getValueToValidate(validatable); + String contextDesc = " form component expression validation "; + PrismPropertyDefinition outputDefinition = prismContext.definitionFactory().createPropertyDefinition(ExpressionConstants.OUTPUT_ELEMENT_NAME, + OperationResultType.COMPLEX_TYPE); + Task task = serviceLocator.createSimpleTask(OPERATION_EVALUATE_EXPRESSION); + OperationResult result = new OperationResult(OPERATION_EVALUATE_EXPRESSION); + ExpressionFactory expressionFactory = serviceLocator.getExpressionFactory(); + Expression, PrismPropertyDefinition> expression; + try { + + expression = expressionFactory + .makeExpression(expressionType, outputDefinition, MiscSchemaUtil.getExpressionProfile(), contextDesc, task, result); + } catch (SchemaException | ObjectNotFoundException | SecurityViolationException e) { + ValidationError error = new ValidationError(); + error.setMessage("Cannot make expression: " + e.getMessage()); + validatable.error(error); + return; + } + ExpressionVariables variables = new ExpressionVariables(); + Class typeClass = (valueToValidate == null ? String.class : valueToValidate.getClass()); + variables.put(ExpressionConstants.VAR_INPUT, valueToValidate, typeClass); + variables.putObject(ExpressionConstants.VAR_OBJECT, (ObjectType)getObjectType(), ObjectType.class); + ExpressionEvaluationContext context = new ExpressionEvaluationContext(null, variables, contextDesc, task); + PrismValueDeltaSetTriple> outputTriple; + try { + outputTriple = expression.evaluate(context, result); + } catch (SchemaException | ExpressionEvaluationException | ObjectNotFoundException | CommunicationException + | ConfigurationException | SecurityViolationException e) { + ValidationError error = new ValidationError(); + error.setMessage("Cannot evaluate expression: " + e.getMessage()); + validatable.error(error); + return; + } + if (outputTriple == null) { + return; + } + Collection> outputValues = outputTriple.getNonNegativeValues(); + if (outputValues.isEmpty()) { + return; + } + if (outputValues.size() > 1) { + ValidationError error = new ValidationError(); + error.setMessage("Expression "+contextDesc+" produced more than one value"); + validatable.error(error); + } + + OperationResultType operationResultType = outputValues.iterator().next().getRealValue(); + + if (operationResultType == null) { + return; + } + + OperationResult returnResult = OperationResult.createOperationResult(operationResultType); + if (!returnResult.isSuccess()) { + ValidationError error = new ValidationError(); + if (returnResult.getUserFriendlyMessage() != null) { + error.setMessage(WebModelServiceUtils.translateMessage(returnResult, serviceLocator)); + } else { + error.setMessage(returnResult.getMessage()); + } + validatable.error(error); + } + + } + + protected O getObjectType() { + return null; + } + + protected Object getValueToValidate(IValidatable validatable) { + return validatable.getValue(); + } + +}