diff --git a/config/rest/index.html b/config/rest/index.html
index e9ebc4c7fb5..80037e91c9a 100644
--- a/config/rest/index.html
+++ b/config/rest/index.html
@@ -18778,9 +18778,9 @@
Usage and SDK Samples
m_basic.setPassword("YOUR PASSWORD");
DefaultApi apiInstance = new DefaultApi();
- String type = type_example; // String | type of the object for which the value will be generated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
- String id = id_example; // String | oid of the object for which the value will be generated
- Object body = ; // Object | path to the property which will be generated
+ String type = type_example; // String | type of the object for which the value will be validated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
+ String id = id_example; // String | oid of the object for which the value will be validated
+ Object body = ; // Object | It can contain either path to the existing property which should be validated (e.g. policy for generating/validating employeeNumber changed and we need to check if the existing employeeNumber still satisfy constraints or it should be generated again) or value which will be set to the target object if it satisfy policy constraints. Definition of path to the existing property is used only if no value is provided to validate.
try {
Object result = apiInstance.validateValue(type, id, body);
System.out.println(result);
@@ -18803,9 +18803,9 @@ Usage and SDK Samples
public static void main(String[] args) {
DefaultApi apiInstance = new DefaultApi();
- String type = type_example; // String | type of the object for which the value will be generated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
- String id = id_example; // String | oid of the object for which the value will be generated
- Object body = ; // Object | path to the property which will be generated
+ String type = type_example; // String | type of the object for which the value will be validated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
+ String id = id_example; // String | oid of the object for which the value will be validated
+ Object body = ; // Object | It can contain either path to the existing property which should be validated (e.g. policy for generating/validating employeeNumber changed and we need to check if the existing employeeNumber still satisfy constraints or it should be generated again) or value which will be set to the target object if it satisfy policy constraints. Definition of path to the existing property is used only if no value is provided to validate.
try {
Object result = apiInstance.validateValue(type, id, body);
System.out.println(result);
@@ -18833,9 +18833,9 @@ Usage and SDK Samples
[apiConfig setPassword:@"YOUR_PASSWORD"];
-String *type = type_example; // type of the object for which the value will be generated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
-String *id = id_example; // oid of the object for which the value will be generated
-Object *body = ; // path to the property which will be generated
+String *type = type_example; // type of the object for which the value will be validated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
+String *id = id_example; // oid of the object for which the value will be validated
+Object *body = ; // It can contain either path to the existing property which should be validated (e.g. policy for generating/validating employeeNumber changed and we need to check if the existing employeeNumber still satisfy constraints or it should be generated again) or value which will be set to the target object if it satisfy policy constraints. Definition of path to the existing property is used only if no value is provided to validate.
DefaultApi *apiInstance = [[DefaultApi alloc] init];
@@ -18866,11 +18866,11 @@ Usage and SDK Samples
var api = new .DefaultApi()
-var type = type_example; // {String} type of the object for which the value will be generated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
+var type = type_example; // {String} type of the object for which the value will be validated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
-var id = id_example; // {String} oid of the object for which the value will be generated
+var id = id_example; // {String} oid of the object for which the value will be validated
-var body = ; // {Object} path to the property which will be generated
+var body = ; // {Object} It can contain either path to the existing property which should be validated (e.g. policy for generating/validating employeeNumber changed and we need to check if the existing employeeNumber still satisfy constraints or it should be generated again) or value which will be set to the target object if it satisfy policy constraints. Definition of path to the existing property is used only if no value is provided to validate.
var callback = function(error, data, response) {
@@ -18909,9 +18909,9 @@ Usage and SDK Samples
Configuration.Default.Password = "YOUR_PASSWORD";
var apiInstance = new DefaultApi();
- var type = type_example; // String | type of the object for which the value will be generated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
- var id = id_example; // String | oid of the object for which the value will be generated
- var body = new Object(); // Object | path to the property which will be generated
+ var type = type_example; // String | type of the object for which the value will be validated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
+ var id = id_example; // String | oid of the object for which the value will be validated
+ var body = new Object(); // Object | It can contain either path to the existing property which should be validated (e.g. policy for generating/validating employeeNumber changed and we need to check if the existing employeeNumber still satisfy constraints or it should be generated again) or value which will be set to the target object if it satisfy policy constraints. Definition of path to the existing property is used only if no value is provided to validate.
try
{
@@ -18941,9 +18941,9 @@ Usage and SDK Samples
io.swagger.client\Configuration::getDefaultConfiguration()->setPassword('YOUR_PASSWORD');
$api_instance = new io.swagger.client\Api\DefaultApi();
-$type = type_example; // String | type of the object for which the value will be generated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
-$id = id_example; // String | oid of the object for which the value will be generated
-$body = ; // Object | path to the property which will be generated
+$type = type_example; // String | type of the object for which the value will be validated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services
+$id = id_example; // String | oid of the object for which the value will be validated
+$body = ; // Object | It can contain either path to the existing property which should be validated (e.g. policy for generating/validating employeeNumber changed and we need to check if the existing employeeNumber still satisfy constraints or it should be generated again) or value which will be set to the target object if it satisfy policy constraints. Definition of path to the existing property is used only if no value is provided to validate.
try {
$result = $api_instance->validateValue($type, $id, $body);
@@ -18981,7 +18981,7 @@ Parameters
var schemaWrapper = {
"name" : "type",
"in" : "path",
- "description" : "type of the object for which the value will be generated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services",
+ "description" : "type of the object for which the value will be validated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services",
"required" : true,
"type" : "string"
};
@@ -19014,7 +19014,7 @@ Parameters
var schemaWrapper = {
"name" : "id",
"in" : "path",
- "description" : "oid of the object for which the value will be generated",
+ "description" : "oid of the object for which the value will be validated",
"required" : true,
"type" : "string"
};
@@ -19058,7 +19058,7 @@ Parameters
var schemaWrapper = {
"in" : "body",
"name" : "body",
- "description" : "path to the property which will be generated",
+ "description" : "It can contain either path to the existing property which should be validated (e.g. policy for generating/validating employeeNumber changed and we need to check if the existing employeeNumber still satisfy constraints or it should be generated again) or value which will be set to the target object if it satisfy policy constraints. Definition of path to the existing property is used only if no value is provided to validate.",
"required" : true,
"schema" : {
"type" : "object",
@@ -19784,7 +19784,7 @@ Status: 503 - Communication problem while provisioning
- Generated 2017-03-02T14:25:03.802+01:00
+ Generated 2017-03-16T13:50:39.152+01:00
diff --git a/config/rest/swagger.yml b/config/rest/swagger.yml
index c7d238046df..8ac4609aa6a 100644
--- a/config/rest/swagger.yml
+++ b/config/rest/swagger.yml
@@ -233,20 +233,20 @@ paths:
- name: "type"
in: "path"
required: true
- description: "type of the object for which the value will be generated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services"
+ description: "type of the object for which the value will be validated. Possible values are connectors, connectorHosts, genericObjects, resources, users, objectTemplates, systemConfigurations, tasks, shadows, roles, valuePolicies, orgs, services"
type: "string"
- name: "id"
in: "path"
required: true
type: "string"
- description: "oid of the object for which the value will be generated"
+ description: "oid of the object for which the value will be validated"
- in: "body"
name: "body"
required: true
schema:
type: "object"
description: "see PolicyItemsDefinitionType"
- description: "path to the property which will be generated"
+ description: "It can contain either path to the existing property which should be validated (e.g. policy for generating/validating employeeNumber changed and we need to check if the existing employeeNumber still satisfy constraints or it should be generated again) or value which will be set to the target object if it satisfy policy constraints. Definition of path to the existing property is used only if no value is provided to validate."
responses:
200:
description: "Successful operation"
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/forgetpassword/PageForgotPassword.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/forgetpassword/PageForgotPassword.java
index 0cedd4c4417..9e769f3be33 100644
--- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/forgetpassword/PageForgotPassword.java
+++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/forgetpassword/PageForgotPassword.java
@@ -30,7 +30,7 @@
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils;
-import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyGenerator;
+import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyProcessor;
import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismProperty;
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/forgetpassword/PageSecurityQuestions.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/forgetpassword/PageSecurityQuestions.java
index 76e4bc32c12..c03ac4af35d 100644
--- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/forgetpassword/PageSecurityQuestions.java
+++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/forgetpassword/PageSecurityQuestions.java
@@ -45,7 +45,7 @@
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.gui.api.util.WebComponentUtil;
import com.evolveum.midpoint.model.api.ModelService;
-import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyGenerator;
+import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyProcessor;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismObjectDefinition;
import com.evolveum.midpoint.prism.crypto.EncryptionException;
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.java
index 43d68be4403..c0f1eaba8fa 100644
--- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.java
+++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.java
@@ -37,7 +37,7 @@
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils;
import com.evolveum.midpoint.model.api.ModelExecuteOptions;
-import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyGenerator;
+import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyProcessor;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismObjectDefinition;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/crypto/ProtectedData.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/crypto/ProtectedData.java
index 2e40d9470e9..c2de3b4e22e 100644
--- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/crypto/ProtectedData.java
+++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/crypto/ProtectedData.java
@@ -24,15 +24,17 @@
*/
public interface ProtectedData {
- abstract byte[] getClearBytes();
+ byte[] getClearBytes();
- abstract void setClearBytes(byte[] bytes);
+ void setClearBytes(byte[] bytes);
- abstract T getClearValue();
+ T getClearValue();
- abstract void setClearValue(T data);
+ void setClearValue(T data);
- abstract void destroyCleartext();
+ void destroyCleartext();
+
+ boolean canGetCleartext();
EncryptedDataType getEncryptedDataType();
diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java
index c5899268aaa..df95ebcc088 100644
--- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java
+++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java
@@ -1688,4 +1688,24 @@ public List getNewValuesFor(ItemPath itemPath) {
}
}
}
+
+ public List getDeletedValuesFor(ItemPath itemPath) {
+ if (isAdd()) {
+ Item item = objectToAdd.findItem(itemPath);
+ return item != null ? item.getValues() : Collections.emptyList();
+ } else if (isDelete()) {
+ return Collections.emptyList();
+ } else {
+ ItemDelta itemDelta = ItemDelta.findItemDelta(modifications, itemPath, ItemDelta.class);
+ if (itemDelta != null) {
+ if (itemDelta.getValuesToDelete() != null) {
+ return (List) itemDelta.getValuesToDelete();
+ } else {
+ return Collections.emptyList();
+ }
+ } else {
+ return Collections.emptyList();
+ }
+ }
+ }
}
diff --git a/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ProtectedDataType.java b/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ProtectedDataType.java
index b1d62f231f8..6f2375d7514 100644
--- a/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ProtectedDataType.java
+++ b/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ProtectedDataType.java
@@ -166,6 +166,11 @@ public T getClearValue() {
public void setClearValue(T clearValue) {
this.clearValue = clearValue;
}
+
+ @Override
+ public boolean canGetCleartext() {
+ return clearValue != null || encryptedDataType != null;
+ }
@Override
public void destroyCleartext() {
diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java
index 13355c6e1f4..b4c71e19350 100644
--- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java
+++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java
@@ -65,6 +65,11 @@ public abstract class SchemaConstants {
public static final String NS_MATCHING_RULE = NS_MIDPOINT_PUBLIC + "/common/matching-rule-3";
public static final String NS_FAULT = "http://midpoint.evolveum.com/xml/ns/public/common/fault-3";
public static final String NS_SAMPLES_EXTENSION = "http://midpoint.evolveum.com/xml/ns/samples/extension-3";
+
+ /**
+ * Namespace for default (bult-in) object collections, such as "all objects", "all roles", ...
+ */
+ public static final String NS_OBJECT_COLLECTIONS = NS_MIDPOINT_PUBLIC + "/common/object-collections-3";
// COMMON NAMESPACE
@@ -216,6 +221,7 @@ public abstract class SchemaConstants {
public static final ItemPath PATH_CREDENTIALS_PASSWORD_FAILED_LOGINS = new ItemPath(
UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_FAILED_LOGINS);
public static final ItemPath PATH_LINK_REF = new ItemPath(FocusType.F_LINK_REF);
+ public static final ItemPath PATH_LIFECYCLE_STATE = new ItemPath(ObjectType.F_LIFECYCLE_STATE);
public static final String NS_PROVISIONING = NS_MIDPOINT_PUBLIC + "/provisioning";
public static final String NS_PROVISIONING_LIVE_SYNC = NS_PROVISIONING + "/liveSync-3";
@@ -398,6 +404,34 @@ public abstract class SchemaConstants {
public static final String LIFECYCLE_FAILED = "failed";
+ // Object collections
+
+ /**
+ * All objects in role catalog. It means all the objects in all the categories that are placed under the
+ * primary role catalog defined in the system. If used in a context where the role catalog can be displayed
+ * as a tree then this collection will be displayed as a tree.
+ */
+ public static final QName OBJECT_COLLECTION_ROLE_CATALOG_QNAME = new QName(NS_OBJECT_COLLECTIONS, "roleCatalog");
+ public static final String OBJECT_COLLECTION_ROLE_CATALOG_URI = QNameUtil.qNameToUri(OBJECT_COLLECTION_ROLE_CATALOG_QNAME);
+
+ /**
+ * Collection that contains all roles.
+ */
+ public static final QName OBJECT_COLLECTION_ALL_ROLES_QNAME = new QName(NS_OBJECT_COLLECTIONS, "allRoles");
+ public static final String OBJECT_COLLECTION_ALL_ROLES_URI = QNameUtil.qNameToUri(OBJECT_COLLECTION_ALL_ROLES_QNAME);
+
+ /**
+ * Collection that contains all orgs.
+ */
+ public static final QName OBJECT_COLLECTION_ALL_ORGS_QNAME = new QName(NS_OBJECT_COLLECTIONS, "allOrgs");
+ public static final String OBJECT_COLLECTION_ALL_ORGS_URI = QNameUtil.qNameToUri(OBJECT_COLLECTION_ALL_ORGS_QNAME);
+
+ /**
+ * Collection that contains all services.
+ */
+ public static final QName OBJECT_COLLECTION_ALL_SERVICES_QNAME = new QName(NS_OBJECT_COLLECTIONS, "allServices");
+ public static final String OBJECT_COLLECTION_ALL_SERVICES_URI = QNameUtil.qNameToUri(OBJECT_COLLECTION_ALL_SERVICES_QNAME);
+
// Samples
public static final QName SAMPLES_SSN = new QName(SchemaConstants.NS_SAMPLES_EXTENSION, "ssn");
diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/FocusTypeUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/FocusTypeUtil.java
index ae5171c3f4d..06d1703f9ce 100644
--- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/FocusTypeUtil.java
+++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/FocusTypeUtil.java
@@ -23,11 +23,15 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentSelectorType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ConstructionType;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OrderConstraintsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
+import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;
/**
* @author semancik
@@ -147,4 +151,19 @@ public static ShadowKindType determineConstructionKind(AssignmentType assignment
throw new IllegalArgumentException("Construction not defined in the assigment.");
}
+
+ public static ProtectedStringType getPasswordValue(UserType user) {
+ if (user == null) {
+ return null;
+ }
+ CredentialsType creds = user.getCredentials();
+ if (creds == null) {
+ return null;
+ }
+ PasswordType passwd = creds.getPassword();
+ if (passwd == null) {
+ return null;
+ }
+ return passwd.getValue();
+ }
}
diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd
index 30ffdd89e99..5c46f5cc2de 100644
--- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd
+++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd
@@ -4183,6 +4183,18 @@
+
+
+
+ Definition of resource object lifecycle handling. It defines
+ how the initial lifecycle state is determined, constraints for lifecycle
+ transitions, etc.
+
+
+ 3.6
+
+
+
@@ -5078,6 +5090,39 @@
+
+
+
+
+ Definition of resource object lifecycle handling. It defines
+ how the initial lifecycle state is determined, constraints for lifecycle
+ transitions, etc.
+
+
+ 3.6
+
+
+
+
+
+
+ Lifecycle state mapping. This mapping influences how shadow lifecycle state and focus
+ lifecycle state are mapped.
+ Default outbound lifecycleState mapping is somehow smart algorithm that will consider
+ presence of the focus password, resource password capability, operation and so on.
+ It is defined to work well with hashed passwords.
+ Default inbound lifecycle mapping is empty: no mapping at all. In midPoint 3.6 the inbound
+ lifecycle mapping is not implemented.
+
+
+
+
+
+
@@ -6255,6 +6300,21 @@
+
+
+
+ Reference to the user whose identity will be used to execute the expression.
+ The expression will use authorizations that this user has. If the expression
+ triggers any change then the change will be audited under the identity of
+ this user.
+ If no user is specified then the identify of currently logged-in user or
+ the owner of the task will be used.
+
+
+ tns:UserType
+
+
+
@@ -11072,6 +11132,19 @@
+
+
+
+ Specifies the set of object collections ("role catalog views") to display in role
+ catalog. If this element is not specified then the default (hardcoded) collections
+ will be displayed. If this element is specified then only those collections specified
+ in this element are displayed.
+
+
+ 3.6
+
+
+
@@ -11137,6 +11210,61 @@
+
+
+
+ Specifies a set of object collections ("views") to be displayed (used) at
+ a specific location in the system.
+ This is generic type that can be used to specify collections to display
+ in role catalog, menu, dashboard and so on.
+
+
+ 3.6
+
+
+
+
+
+
+ Reference to the colleciot, its visibility, etc.
+
+
+ 3.6
+
+
+
+
+
+
+
+
+
+
+ Specifies how a specific collection ("view") is to be displayed (used) at
+ a specific location in the system.
+ This is generic type that can be used to specify collection to display
+ in role catalog, menu, dashboard and so on.
+
+
+ 3.6
+
+
+
+
+
+
+ Reference to the built-in collection.
+
+
+ 3.6
+
+
+
+
+
+
+
@@ -12449,7 +12577,8 @@
- TODO
+ Options for execution of Model operations. These options influence the way how the operations are executed.
+ The options are not mandatory. All options have reasonable default values. They may not be specified at all.
@@ -12475,13 +12604,16 @@
Avoid encryption of any cleartext data on write. Applies only to the encrypted
data formats (ProtectedString, ProtectedByteArray).
+ It is not recommended to use in production environment. This option is provided only for diagnostic
+ purposes to be used in development environments.
- Option to reconcile user while executing changes.
+ Option to reconcile focus and all projections while executing changes.
+ (implies reconcileFocus)
@@ -12557,7 +12689,8 @@
- Business context that describes this request.
+ Options that control selective execution of model logic.
+ Use with extreme care. Some combinations may be dangerous.
@@ -12621,6 +12754,7 @@
+
diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelExecuteOptions.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelExecuteOptions.java
index ffdf9a4f7cc..0937b9bb88b 100644
--- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelExecuteOptions.java
+++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelExecuteOptions.java
@@ -25,8 +25,10 @@
import java.util.List;
/**
+ * Options for execution of Model operations. These options influence the way how the operations are executed.
+ * The options are not mandatory. All options have reasonable default values. They may not be specified at all.
+ *
* @author semancik
- *
*/
public class ModelExecuteOptions extends AbstractOptions implements Serializable, Cloneable {
@@ -46,6 +48,8 @@ public class ModelExecuteOptions extends AbstractOptions implements Serializable
/**
* Encrypt any cleartext data on write, decrypt any encrypted data on read. Applies only to the encrypted
* data formats (ProtectedString, ProtectedByteArray).
+ * It is not recommended to use in production environment. This option is provided only for diagnostic
+ * purposes to be used in development environments.
*/
private Boolean noCrypt;
@@ -88,6 +92,9 @@ public class ModelExecuteOptions extends AbstractOptions implements Serializable
*/
private Boolean overwrite;
+ /**
+ * Option to simulate import operation. E.g. search filters will be resolved.
+ */
private Boolean isImport;
/**
@@ -106,8 +113,15 @@ public class ModelExecuteOptions extends AbstractOptions implements Serializable
*/
private Boolean preAuthorized;
+ /**
+ * Business context that describes this request.
+ */
private OperationBusinessContextType requestBusinessContext;
+ /**
+ * Options that control selective execution of model logic.
+ * Use with extreme care. Some combinations may be dangerous.
+ */
private PartialProcessingOptionsType partialProcessing;
public Boolean getForce() {
diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/expr/MidpointFunctions.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/expr/MidpointFunctions.java
index 42f349d0fc2..2358638b0aa 100644
--- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/expr/MidpointFunctions.java
+++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/expr/MidpointFunctions.java
@@ -28,6 +28,7 @@
import com.evolveum.midpoint.schema.ResultHandler;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.result.OperationResult;
+import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.ExpressionEvaluationException;
@@ -1037,4 +1038,15 @@ List getMembers(String orgOid)
List getMembersAsReferences(String orgOid)
throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException,
ObjectNotFoundException;
+
+ /**
+ * Default function used to compute projection lifecycle. It is provided here so it can be explicitly
+ * invoked from a custom expression and then the result can be changed for special cases.
+ */
+ String computeProjectionLifecycle(F focus, ShadowType shadow, ResourceType resource);
+
+ /**
+ * Returns principal representing the user whose identity is used to execute the expression.
+ */
+ MidPointPrincipal getPrincipal() throws SecurityViolationException;
}
diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/Expression.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/Expression.java
index ba53afc6d66..572d775aec5 100644
--- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/Expression.java
+++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/Expression.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Evolveum
+ * Copyright (c) 2010-2017 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,22 +32,27 @@
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismContext;
+import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.internals.InternalsConfig;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectResolver;
+import com.evolveum.midpoint.security.api.SecurityEnforcer;
import com.evolveum.midpoint.util.MiscUtil;
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.SystemException;
+import com.evolveum.midpoint.util.exception.TunnelException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionVariableDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.prism.xml.ns._public.types_3.RawType;
/**
@@ -56,15 +61,16 @@
*/
public class Expression {
- ExpressionType expressionType;
- D outputDefinition;
- PrismContext prismContext;
- ObjectResolver objectResolver;
- List> evaluators = new ArrayList>(1);
+ final private ExpressionType expressionType;
+ final private D outputDefinition;
+ final private PrismContext prismContext;
+ final private ObjectResolver objectResolver;
+ final private SecurityEnforcer securityEnforcer;
+ private List> evaluators = new ArrayList>(1);
private static final Trace LOGGER = TraceManager.getTrace(Expression.class);
- public Expression(ExpressionType expressionType, D outputDefinition, ObjectResolver objectResolver, PrismContext prismContext) {
+ public Expression(ExpressionType expressionType, D outputDefinition, ObjectResolver objectResolver, SecurityEnforcer securityEnforcer, PrismContext prismContext) {
//Validate.notNull(outputDefinition, "null outputDefinition");
Validate.notNull(objectResolver, "null objectResolver");
Validate.notNull(prismContext, "null prismContext");
@@ -72,6 +78,7 @@ public Expression(ExpressionType expressionType, D outputDefinition, ObjectResol
this.outputDefinition = outputDefinition;
this.objectResolver = objectResolver;
this.prismContext = prismContext;
+ this.securityEnforcer = securityEnforcer;
}
public void parse(ExpressionFactory factory, String contextDescription, Task task, OperationResult result)
@@ -128,43 +135,92 @@ public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context)
ExpressionEvaluationContext processedParameters = context.shallowClone();
processedParameters.setVariables(processedVariables);
+ PrismValueDeltaSetTriple outputTriple;
- for (ExpressionEvaluator,?> evaluator: evaluators) {
- PrismValueDeltaSetTriple outputTriple = (PrismValueDeltaSetTriple) evaluator.evaluate(processedParameters);
- if (outputTriple != null) {
- boolean allowEmptyRealValues = false;
- if (expressionType != null) {
- allowEmptyRealValues = BooleanUtils.isTrue(expressionType.isAllowEmptyValues());
- }
- outputTriple.removeEmptyValues(allowEmptyRealValues);
- if (InternalsConfig.consistencyChecks) {
+ ObjectReferenceType runAsRef = null;
+ if (expressionType != null) {
+ runAsRef = expressionType.getRunAsRef();
+ }
+
+ if (runAsRef == null) {
+
+ outputTriple = evaluateExpressionEvaluators(context, processedParameters);
+
+ } else {
+
+ UserType userType = objectResolver.resolve(runAsRef, UserType.class, null,
+ "runAs in "+context.getContextDescription(), context.getTask(), context.getResult());
+
+ LOGGER.trace("Running {} as {} ({})", context.getContextDescription(), userType, runAsRef);
+
+ try {
+
+ outputTriple = securityEnforcer.runAs(() -> {
try {
- outputTriple.checkConsistence();
- } catch (IllegalStateException e) {
- throw new IllegalStateException(e.getMessage() + "; in expression " + this +", evaluator " + evaluator, e);
+ return evaluateExpressionEvaluators(context, processedParameters);
+ } catch (SchemaException | ExpressionEvaluationException | ObjectNotFoundException e) {
+ throw new TunnelException(e);
}
+ }, userType.asPrismObject());
+
+ } catch (TunnelException te) {
+ Throwable e = te.getCause();
+ if (e instanceof RuntimeException) {
+ throw (RuntimeException)e;
+ }
+ if (e instanceof Error) {
+ throw (Error)e;
+ }
+ if (e instanceof SchemaException) {
+ throw (SchemaException)e;
}
- traceSuccess(context, processedVariables, outputTriple);
- return outputTriple;
+ if (e instanceof ExpressionEvaluationException) {
+ throw (ExpressionEvaluationException)e;
+ }
+ if (e instanceof ObjectNotFoundException) {
+ throw (ObjectNotFoundException)e;
+ }
+ throw te;
}
+
}
- traceSuccess(context, processedVariables, null);
- return null;
- } catch (SchemaException ex) {
- traceFailure(context, processedVariables, ex);
- throw ex;
- } catch (ExpressionEvaluationException ex) {
- traceFailure(context, processedVariables, ex);
- throw ex;
- } catch (ObjectNotFoundException ex) {
- traceFailure(context, processedVariables, ex);
- throw ex;
- } catch (RuntimeException ex) {
- traceFailure(context, processedVariables, ex);
- throw ex;
+
+ traceSuccess(context, processedVariables, outputTriple);
+ return outputTriple;
+
+ } catch (SchemaException | ExpressionEvaluationException | ObjectNotFoundException | RuntimeException | Error e) {
+ traceFailure(context, processedVariables, e);
+ throw e;
}
}
+
+ private PrismValueDeltaSetTriple evaluateExpressionEvaluators(ExpressionEvaluationContext context, ExpressionEvaluationContext processedParameters)
+ throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException {
+
+ for (ExpressionEvaluator,?> evaluator: evaluators) {
+ PrismValueDeltaSetTriple outputTriple = (PrismValueDeltaSetTriple) evaluator.evaluate(processedParameters);
+ if (outputTriple != null) {
+ boolean allowEmptyRealValues = false;
+ if (expressionType != null) {
+ allowEmptyRealValues = BooleanUtils.isTrue(expressionType.isAllowEmptyValues());
+ }
+ outputTriple.removeEmptyValues(allowEmptyRealValues);
+ if (InternalsConfig.consistencyChecks) {
+ try {
+ outputTriple.checkConsistence();
+ } catch (IllegalStateException e) {
+ throw new IllegalStateException(e.getMessage() + "; in expression " + this +", evaluator " + evaluator, e);
+ }
+ }
+ return outputTriple;
+ }
+ }
+
+ return null;
+
+ }
+
private void traceSuccess(ExpressionEvaluationContext context, ExpressionVariables processedVariables, PrismValueDeltaSetTriple outputTriple) {
if (!isTrace()) {
return;
@@ -182,7 +238,7 @@ private void traceSuccess(ExpressionEvaluationContext context, ExpressionVariabl
trace(sb.toString());
}
- private void traceFailure(ExpressionEvaluationContext context, ExpressionVariables processedVariables, Exception e) {
+ private void traceFailure(ExpressionEvaluationContext context, ExpressionVariables processedVariables, Throwable e) {
LOGGER.error("Error evaluating expression in {}: {}", new Object[]{context.getContextDescription(), e.getMessage(), e});
if (!isTrace()) {
return;
@@ -239,14 +295,19 @@ private void appendTraceFooter(StringBuilder sb) {
private ExpressionVariables processInnerVariables(ExpressionVariables variables, String contextDescription,
Task task, OperationResult result) throws SchemaException, ObjectNotFoundException {
- if (expressionType == null || expressionType.getVariable() == null || expressionType.getVariable().isEmpty()) {
+ if (expressionType == null) {
// shortcut
return variables;
}
ExpressionVariables newVariables = new ExpressionVariables();
+
+ // We need to add actor variable before we switch user identity (runAs)
+ ExpressionUtil.addActorVariable(newVariables, securityEnforcer);
+
for(Entry entry: variables.entrySet()) {
newVariables.addVariableDefinition(entry.getKey(), entry.getValue());
}
+
for (ExpressionVariableDefinitionType variableDefType: expressionType.getVariable()) {
QName varName = variableDefType.getName();
if (varName == null) {
@@ -277,6 +338,7 @@ private ExpressionVariables processInnerVariables(ExpressionVariables variables,
throw new SchemaException("No value for variable "+varName+" in "+contextDescription);
}
}
+
return newVariables;
}
diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionFactory.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionFactory.java
index a21add9ab34..9180afb9617 100644
--- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionFactory.java
+++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2015 Evolveum
+ * Copyright (c) 2010-2017 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectResolver;
+import com.evolveum.midpoint.security.api.SecurityEnforcer;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
@@ -40,13 +41,15 @@ public class ExpressionFactory {
private Map evaluatorFactoriesMap = new HashMap();
private ExpressionEvaluatorFactory defaultEvaluatorFactory;
private Map> cache = new HashMap>();
- private PrismContext prismContext;
- private ObjectResolver objectResolver;
+ final private PrismContext prismContext;
+ final private ObjectResolver objectResolver;
+ final private SecurityEnforcer securityEnforcer;
- public ExpressionFactory(ObjectResolver objectResolver, PrismContext prismContext) {
+ public ExpressionFactory(ObjectResolver objectResolver, SecurityEnforcer securityEnforcer, PrismContext prismContext) {
super();
this.objectResolver = objectResolver;
this.prismContext = prismContext;
+ this.securityEnforcer = securityEnforcer;
}
public PrismContext getPrismContext() {
@@ -74,7 +77,7 @@ public Expression makeExpre
private Expression createExpression(ExpressionType expressionType,
D outputDefinition, String shortDesc, Task task, OperationResult result)
throws SchemaException, ObjectNotFoundException {
- Expression expression = new Expression(expressionType, outputDefinition, objectResolver, prismContext);
+ Expression expression = new Expression(expressionType, outputDefinition, objectResolver, securityEnforcer, prismContext);
expression.parse(this, shortDesc, task, result);
return expression;
}
diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionUtil.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionUtil.java
index 71891184f9c..2e7e55b744c 100644
--- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionUtil.java
+++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionUtil.java
@@ -901,9 +901,10 @@ public static void addActorVariable(ExpressionVariables scriptVariables,
try {
if (securityEnforcer != null) {
if (!securityEnforcer.isAuthenticated()) {
- // Nothing to set up. This is most likely evaluation of role
+ // This is most likely evaluation of role
// condition before
// the authentication is complete.
+ scriptVariables.addVariableDefinition(ExpressionConstants.VAR_ACTOR, null);
return;
}
MidPointPrincipal principal = securityEnforcer.getPrincipal();
diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AbstractValueTransformationExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AbstractValueTransformationExpressionEvaluator.java
index 7b5ef546980..eb5c722542b 100644
--- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AbstractValueTransformationExpressionEvaluator.java
+++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AbstractValueTransformationExpressionEvaluator.java
@@ -76,8 +76,6 @@ public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context)
PrismValueDeltaSetTriple outputTriple;
- ExpressionUtil.addActorVariable(context.getVariables(), securityEnforcer);
-
if (expressionEvaluatorType.getRelativityMode() == TransformExpressionRelativityModeType.ABSOLUTE) {
outputTriple = evaluateAbsoluteExpression(context.getSources(), context.getVariables(), context,
diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/GenerateExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/GenerateExpressionEvaluator.java
index 7281e0a6933..6c3c2ee47b5 100644
--- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/GenerateExpressionEvaluator.java
+++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/GenerateExpressionEvaluator.java
@@ -24,7 +24,7 @@
import com.evolveum.midpoint.model.common.expression.ExpressionUtil;
import com.evolveum.midpoint.model.common.expression.ExpressionVariables;
import com.evolveum.midpoint.model.common.expression.StringPolicyResolver;
-import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyGenerator;
+import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyProcessor;
import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismContext;
@@ -62,11 +62,11 @@ public class GenerateExpressionEvaluator List evaluate(ScriptExpressionEvaluatorType
try {
InternalMonitor.recordScriptExecution();
evalRawResult = compiledScript.eval(bindings);
- } catch (ScriptException e) {
- throw new ExpressionEvaluationException(e.getMessage() + " " + contextDescription, e);
+ } catch (Throwable e) {
+ throw new ExpressionEvaluationException(e.getMessage() + " in " + contextDescription, e);
}
if (outputDefinition == null) {
@@ -172,8 +172,8 @@ public Object evaluateReportScript(String codeString, ExpressionVariables va
try {
InternalMonitor.recordScriptExecution();
evalRawResult = compiledScript.eval(bindings);
- } catch (ScriptException e) {
- throw new ExpressionEvaluationException(e.getMessage() + " " + contextDescription, e);
+ } catch (Throwable e) {
+ throw new ExpressionEvaluationException(e.getMessage() + " in " + contextDescription, e);
}
@@ -190,7 +190,7 @@ private CompiledScript createCompiledScript(String codeString, String contextDes
InternalMonitor.recordScriptCompile();
compiledScript = ((Compilable)scriptEngine).compile(codeString);
} catch (ScriptException e) {
- throw new ExpressionEvaluationException(e.getMessage() + " " + contextDescription, e);
+ throw new ExpressionEvaluationException(e.getMessage() + " in " + contextDescription, e);
}
scriptCache.put(codeString, compiledScript);
return compiledScript;
@@ -201,7 +201,7 @@ private T convertScalarResult(Class expectedType, Object rawValue, String
T convertedValue = ExpressionUtil.convertValue(expectedType, rawValue, protector, prismContext);
return convertedValue;
} catch (IllegalArgumentException e) {
- throw new ExpressionEvaluationException(e.getMessage()+" in "+contextDescription, e);
+ throw new ExpressionEvaluationException(e.getMessage() + " in " + contextDescription, e);
}
}
diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java
index 10752463d88..07856e0d5d2 100644
--- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java
+++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java
@@ -348,8 +348,6 @@ public void evaluate(Task task, OperationResult parentResult) throws ExpressionE
OperationResult result = parentResult.createMinorSubresult(Mapping.class.getName()+".evaluate");
- ExpressionUtil.addActorVariable(variables, securityEnforcer);
-
traceEvaluationStart();
try {
diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyGenerator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyProcessor.java
similarity index 58%
rename from model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyGenerator.java
rename to model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyProcessor.java
index d304845c365..0d3cd469453 100644
--- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyGenerator.java
+++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/stringpolicy/ValuePolicyProcessor.java
@@ -28,45 +28,54 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
+import java.util.Set;
import org.apache.commons.lang.RandomStringUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.Validate;
import org.apache.commons.lang.text.StrBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import com.evolveum.midpoint.model.common.expression.Expression;
import com.evolveum.midpoint.model.common.expression.ExpressionFactory;
import com.evolveum.midpoint.model.common.expression.ExpressionUtil;
import com.evolveum.midpoint.model.common.expression.ExpressionVariables;
import com.evolveum.midpoint.prism.PrismObject;
-import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.PrismPropertyValue;
+import com.evolveum.midpoint.prism.xml.XsdTypeMapper;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
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.exception.ExpressionEvaluationException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.CharacterClassType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CheckExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LimitationsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordLifeTimeType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.StringLimitType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.StringPolicyType;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType;
@Component
-public class ValuePolicyGenerator {
+public class ValuePolicyProcessor {
- private static final String OP_GENERATE = ValuePolicyGenerator.class.getName() + ".generate";
- private static final transient Trace LOGGER = TraceManager.getTrace(ValuePolicyGenerator.class);
+ private static final String OP_GENERATE = ValuePolicyProcessor.class.getName() + ".generate";
+ private static final transient Trace LOGGER = TraceManager.getTrace(ValuePolicyProcessor.class);
private static final Random RAND = new Random(System.currentTimeMillis());
+ private static final String DOT_CLASS = ValuePolicyProcessor.class.getName() + ".";
+ private static final String OPERATION_STRING_POLICY_VALIDATION = DOT_CLASS + "stringPolicyValidation";
private static final int DEFAULT_MAX_ATTEMPTS = 10;
@Autowired
@@ -121,6 +130,292 @@ public String generate(StringPolicyType policy, int defa
}
+ public boolean validateValue(String newValue, ValuePolicyType pp,
+ PrismObject object, String shortDesc, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
+ return validateValue(newValue, pp, object, new StringBuilder(), shortDesc, task, parentResult);
+ }
+
+ public boolean validateValue(String newValue, ValuePolicyType pp,
+ PrismObject object, StringBuilder message, String shortDesc, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
+
+ Validate.notNull(pp, "Password policy must not be null.");
+
+ OperationResult result = parentResult.createSubresult(OPERATION_STRING_POLICY_VALIDATION);
+ result.addParam("policyName", pp.getName());
+ normalize(pp);
+
+ if (newValue == null &&
+ (pp.getMinOccurs() == null || XsdTypeMapper.multiplicityToInteger(pp.getMinOccurs()) == 0)) {
+ // No password is allowed
+ result.recordSuccess();
+ return true;
+ }
+
+ if (newValue == null) {
+ newValue = "";
+ }
+
+ LimitationsType lims = pp.getStringPolicy().getLimitations();
+
+ testMinimalLength(newValue, lims, result, message);
+ testMaximalLength(newValue, lims, result, message);
+
+ testMinimalUniqueCharacters(newValue, lims, result, message);
+
+ if (lims.getLimit() == null || lims.getLimit().isEmpty()) {
+ if (message.toString() == null || message.toString().isEmpty()) {
+ result.computeStatus();
+ } else {
+ result.computeStatus(message.toString());
+
+ }
+
+ return result.isAcceptable();
+ }
+
+ // check limitation
+ HashSet validChars = null;
+ HashSet allValidChars = new HashSet<>();
+ List passwd = StringPolicyUtils.stringTokenizer(newValue);
+ for (StringLimitType stringLimitationType : lims.getLimit()) {
+ OperationResult limitResult = new OperationResult(
+ "Tested limitation: " + stringLimitationType.getDescription());
+
+ validChars = getValidCharacters(stringLimitationType.getCharacterClass(), pp);
+ int count = countValidCharacters(validChars, passwd);
+ allValidChars.addAll(validChars);
+ testMinimalOccurence(stringLimitationType, count, limitResult, message);
+ testMaximalOccurence(stringLimitationType, count, limitResult, message);
+ testMustBeFirst(stringLimitationType, count, limitResult, message, newValue, validChars);
+
+ limitResult.computeStatus();
+ result.addSubresult(limitResult);
+ }
+ testInvalidCharacters(passwd, allValidChars, result, message);
+
+ testCheckExpression(newValue, lims, object, shortDesc, task, result, message);
+
+ if (message.toString() == null || message.toString().isEmpty()) {
+ result.computeStatus();
+ } else {
+ result.computeStatus(message.toString());
+
+ }
+
+ return result.isAcceptable();
+ }
+
+ /**
+ * add defined default values
+ */
+ private void normalize(ValuePolicyType pp) {
+ if (null == pp) {
+ throw new IllegalArgumentException("Password policy cannot be null");
+ }
+
+ if (null == pp.getStringPolicy()) {
+ StringPolicyType sp = new StringPolicyType();
+ pp.setStringPolicy(StringPolicyUtils.normalize(sp));
+ } else {
+ pp.setStringPolicy(StringPolicyUtils.normalize(pp.getStringPolicy()));
+ }
+
+ if (null == pp.getLifetime()) {
+ PasswordLifeTimeType lt = new PasswordLifeTimeType();
+ lt.setExpiration(-1);
+ lt.setWarnBeforeExpiration(0);
+ lt.setLockAfterExpiration(0);
+ lt.setMinPasswordAge(0);
+ lt.setPasswordHistoryLength(0);
+ }
+ return;
+ }
+
+ private void testMustBeFirst(StringLimitType stringLimitationType, int count,
+ OperationResult limitResult, StringBuilder message, String password, Set validChars) {
+ // test if first character is valid
+ if (stringLimitationType.isMustBeFirst() == null) {
+ stringLimitationType.setMustBeFirst(false);
+ }
+ // we check mustBeFirst only for non-empty passwords
+ if (StringUtils.isNotEmpty(password) && stringLimitationType.isMustBeFirst()
+ && !validChars.contains(password.substring(0, 1))) {
+ String msg = "First character is not from allowed set. Allowed set: " + validChars.toString();
+ limitResult.addSubresult(
+ new OperationResult("Check valid first char", OperationResultStatus.FATAL_ERROR, msg));
+ message.append(msg);
+ message.append("\n");
+ }
+ // else {
+ // limitResult.addSubresult(new OperationResult("Check valid first char
+ // in password OK.",
+ // OperationResultStatus.SUCCESS, "PASSED"));
+ // }
+
+ }
+
+ private void testMaximalOccurence(StringLimitType stringLimitationType, int count,
+ OperationResult limitResult, StringBuilder message) {
+ // Test maximal occurrence
+ if (stringLimitationType.getMaxOccurs() != null) {
+
+ if (stringLimitationType.getMaxOccurs() < count) {
+ String msg = "Required maximal occurrence (" + stringLimitationType.getMaxOccurs()
+ + ") of characters (" + stringLimitationType.getDescription()
+ + ") in password was exceeded (occurrence of characters in password " + count + ").";
+ limitResult.addSubresult(new OperationResult("Check maximal occurrence of characters",
+ OperationResultStatus.FATAL_ERROR, msg));
+ message.append(msg);
+ message.append("\n");
+ }
+ // else {
+ // limitResult.addSubresult(new OperationResult(
+ // "Check maximal occurrence of characters in password OK.",
+ // OperationResultStatus.SUCCESS,
+ // "PASSED"));
+ // }
+ }
+
+ }
+
+ private void testMinimalOccurence(StringLimitType stringLimitation, int count,
+ OperationResult result, StringBuilder message) {
+ // Test minimal occurrence
+ if (stringLimitation.getMinOccurs() == null) {
+ stringLimitation.setMinOccurs(0);
+ }
+ if (stringLimitation.getMinOccurs() > count) {
+ String msg = "Required minimal occurrence (" + stringLimitation.getMinOccurs()
+ + ") of characters (" + stringLimitation.getDescription()
+ + ") in password is not met (occurrence of characters in password " + count + ").";
+ result.addSubresult(new OperationResult("Check minimal occurrence of characters",
+ OperationResultStatus.FATAL_ERROR, msg));
+ message.append(msg);
+ message.append("\n");
+ }
+ }
+
+ private int countValidCharacters(Set validChars, List password) {
+ int count = 0;
+ for (String s : password) {
+ if (validChars.contains(s)) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private HashSet getValidCharacters(CharacterClassType characterClassType,
+ ValuePolicyType passwordPolicy) {
+ if (null != characterClassType.getValue()) {
+ return new HashSet(StringPolicyUtils.stringTokenizer(characterClassType.getValue()));
+ } else {
+ return new HashSet(StringPolicyUtils.stringTokenizer(StringPolicyUtils
+ .collectCharacterClass(passwordPolicy.getStringPolicy().getCharacterClass(),
+ characterClassType.getRef())));
+ }
+ }
+
+ private void testMinimalUniqueCharacters(String password, LimitationsType limitations,
+ OperationResult result, StringBuilder message) {
+ // Test uniqueness criteria
+ HashSet tmp = new HashSet(StringPolicyUtils.stringTokenizer(password));
+ if (limitations.getMinUniqueChars() != null) {
+ if (limitations.getMinUniqueChars() > tmp.size()) {
+ String msg = "Required minimal count of unique characters (" + limitations.getMinUniqueChars()
+ + ") in password are not met (unique characters in password " + tmp.size() + ")";
+ result.addSubresult(new OperationResult("Check minimal count of unique chars",
+ OperationResultStatus.FATAL_ERROR, msg));
+ message.append(msg);
+ message.append("\n");
+ }
+
+ }
+ }
+
+ private void testMinimalLength(String password, LimitationsType limitations,
+ OperationResult result, StringBuilder message) {
+ // Test minimal length
+ if (limitations.getMinLength() == null) {
+ limitations.setMinLength(0);
+ }
+ if (limitations.getMinLength() > password.length()) {
+ String msg = "Required minimal size (" + limitations.getMinLength()
+ + ") of password is not met (password length: " + password.length() + ")";
+ result.addSubresult(new OperationResult("Check global minimal length",
+ OperationResultStatus.FATAL_ERROR, msg));
+ message.append(msg);
+ message.append("\n");
+ }
+ }
+
+ private void testMaximalLength(String password, LimitationsType limitations,
+ OperationResult result, StringBuilder message) {
+ // Test maximal length
+ if (limitations.getMaxLength() != null) {
+ if (limitations.getMaxLength() < password.length()) {
+ String msg = "Required maximal size (" + limitations.getMaxLength()
+ + ") of password was exceeded (password length: " + password.length() + ").";
+ result.addSubresult(new OperationResult("Check global maximal length",
+ OperationResultStatus.FATAL_ERROR, msg));
+ message.append(msg);
+ message.append("\n");
+ }
+ }
+ }
+
+ private void testInvalidCharacters(List password, HashSet validChars,
+ OperationResult result, StringBuilder message) {
+
+ // Check if there is no invalid character
+ StringBuilder invalidCharacters = new StringBuilder();
+ for (String s : password) {
+ if (!validChars.contains(s)) {
+ // memorize all invalid characters
+ invalidCharacters.append(s);
+ }
+ }
+ if (invalidCharacters.length() > 0) {
+ String msg = "Characters [ " + invalidCharacters + " ] are not allowed in password";
+ result.addSubresult(new OperationResult("Check if password does not contain invalid characters",
+ OperationResultStatus.FATAL_ERROR, msg));
+ message.append(msg);
+ message.append("\n");
+ }
+ // else {
+ // ret.addSubresult(new OperationResult("Check if password does not
+ // contain invalid characters OK.",
+ // OperationResultStatus.SUCCESS, "PASSED"));
+ // }
+
+ }
+
+ private void testCheckExpression(String newPassword, LimitationsType lims, PrismObject object,
+ String shortDesc, Task task, OperationResult result, StringBuilder message) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
+
+ List checkExpressions = lims.getCheckExpression();
+ if (checkExpressions.isEmpty()) {
+ return;
+ }
+ for (CheckExpressionType checkExpression: checkExpressions) {
+ ExpressionType expressionType = checkExpression.getExpression();
+ if (expressionType == null) {
+ return;
+ }
+ if (!checkExpression(newPassword, expressionType, object, shortDesc, task, result)) {
+ String msg = checkExpression.getFailureMessage();
+ if (msg == null) {
+ msg = "Check expression failed";
+ }
+ result.addSubresult(new OperationResult("Check expression",
+ OperationResultStatus.FATAL_ERROR, msg));
+ message.append(msg);
+ message.append("\n");
+ }
+ }
+
+ }
+
private String generateAttempt(StringPolicyType policy, int defaultLength, boolean generateMinimalSize,
OperationResult result) {
diff --git a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/ExpressionTestUtil.java b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/ExpressionTestUtil.java
index 532d3faa553..1091e1d3e71 100644
--- a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/ExpressionTestUtil.java
+++ b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/expression/ExpressionTestUtil.java
@@ -29,7 +29,7 @@
import com.evolveum.midpoint.model.common.expression.script.ScriptExpressionFactory;
import com.evolveum.midpoint.model.common.expression.script.jsr223.Jsr223ScriptEvaluator;
import com.evolveum.midpoint.model.common.expression.script.xpath.XPathScriptEvaluator;
-import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyGenerator;
+import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyProcessor;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.crypto.ProtectorImpl;
import com.evolveum.midpoint.schema.util.ObjectResolver;
@@ -53,7 +53,7 @@ public static ProtectorImpl createInitializedProtector(PrismContext prismContext
public static ExpressionFactory createInitializedExpressionFactory(ObjectResolver resolver, ProtectorImpl protector,
PrismContext prismContext, SecurityEnforcer securityEnforcer) {
- ExpressionFactory expressionFactory = new ExpressionFactory(resolver, prismContext);
+ ExpressionFactory expressionFactory = new ExpressionFactory(resolver, securityEnforcer, prismContext);
// asIs
AsIsExpressionEvaluatorFactory asIsFactory = new AsIsExpressionEvaluatorFactory(prismContext, protector);
@@ -69,7 +69,7 @@ public static ExpressionFactory createInitializedExpressionFactory(ObjectResolve
expressionFactory.addEvaluatorFactory(pathFactory);
// generate
- ValuePolicyGenerator valuePolicyGenerator = new ValuePolicyGenerator();
+ ValuePolicyProcessor valuePolicyGenerator = new ValuePolicyProcessor();
valuePolicyGenerator.setExpressionFactory(expressionFactory);
GenerateExpressionEvaluatorFactory generateFactory = new GenerateExpressionEvaluatorFactory(protector, resolver, valuePolicyGenerator, prismContext);
expressionFactory.addEvaluatorFactory(generateFactory);
diff --git a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingStatic.java b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingStatic.java
index f20ebddb9a5..6b6b6011724 100644
--- a/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingStatic.java
+++ b/model/model-common/src/test/java/com/evolveum/midpoint/model/common/mapping/TestMappingStatic.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 Evolveum
+ * Copyright (c) 2010-2017 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -94,33 +94,6 @@ public void testValueMultiShallow() throws Exception {
PrismAsserts.assertTripleNoPlus(outputTriple);
PrismAsserts.assertTripleNoMinus(outputTriple);
}
-
- // We do not have boolean property in the use any more ... but this is covered quite well in dynamic tests
-// @Test
-// public void testValueBooleanTrue() throws Exception {
-// // WHEN
-// PrismValueDeltaSetTriple> outputTriple = evaluator.evaluateMapping(
-// "mapping-value-boolean-true.xml",
-// "testValue",
-// new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_ALLOWED_IDM_ADMIN_GUI_ACCESS)); // target
-// // THEN
-// PrismAsserts.assertTripleZero(outputTriple, Boolean.TRUE);
-// PrismAsserts.assertTripleNoPlus(outputTriple);
-// PrismAsserts.assertTripleNoMinus(outputTriple);
-// }
-//
-// @Test
-// public void testValueBooleanFalse() throws Exception {
-// // WHEN
-// PrismValueDeltaSetTriple> outputTriple = evaluator.evaluateMapping(
-// "mapping-value-boolean-false.xml",
-// "testValue",
-// new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_ALLOWED_IDM_ADMIN_GUI_ACCESS)); // target
-// // THEN
-// PrismAsserts.assertTripleZero(outputTriple, Boolean.FALSE);
-// PrismAsserts.assertTripleNoPlus(outputTriple);
-// PrismAsserts.assertTripleNoMinus(outputTriple);
-// }
@Test
public void testPathNoSource() throws Exception {
diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelRestService.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelRestService.java
index 7796c8ab62d..d0ca3ccccd8 100644
--- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelRestService.java
+++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelRestService.java
@@ -16,6 +16,7 @@
package com.evolveum.midpoint.model.impl;
import java.net.URI;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -38,6 +39,8 @@
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
+import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.apache.cxf.jaxrs.ext.MessageContext;
import org.springframework.beans.factory.annotation.Autowired;
@@ -53,14 +56,17 @@
import com.evolveum.midpoint.model.api.validator.ResourceValidator;
import com.evolveum.midpoint.model.api.validator.Scope;
import com.evolveum.midpoint.model.api.validator.ValidationResult;
+import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyProcessor;
import com.evolveum.midpoint.model.impl.rest.PATCH;
import com.evolveum.midpoint.model.impl.security.SecurityHelper;
import com.evolveum.midpoint.model.impl.util.RestServiceUtil;
import com.evolveum.midpoint.prism.Item;
+import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.prism.delta.ItemDelta;
+import com.evolveum.midpoint.prism.delta.PropertyDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.query.QueryJaxbConvertor;
@@ -75,16 +81,21 @@
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.util.MiscUtil;
+import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
-import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException;
+import com.evolveum.midpoint.util.exception.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.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.CompareResultType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ObjectListType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ObjectModificationType;
+import com.evolveum.midpoint.xml.ns._public.common.api_types_3.PolicyItemDefinitionType;
+import com.evolveum.midpoint.xml.ns._public.common.api_types_3.PolicyItemsDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ScriptOutputsType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.SingleScriptOutputType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsPolicyType;
@@ -94,8 +105,10 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectShadowChangeDescriptionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.StringPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ExecuteScriptsResponseType;
import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ItemListType;
import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType;
@@ -153,6 +166,9 @@ public class ModelRestService {
@Autowired
private SecurityHelper securityHelper;
+ @Autowired
+ ValuePolicyProcessor policyProcessor;
+
@Autowired
private TaskManager taskManager;
@@ -166,6 +182,165 @@ public class ModelRestService {
public ModelRestService() {
// nothing to do
}
+
+ @POST
+ @Path("/{type}/{oid}/generate")
+ @Consumes({"application/xml", "application/json", "application/yaml"})
+ @Produces({"application/xml", "application/json", "application/yaml"})
+ public Response generateValue(@PathParam("type") String type,
+ @PathParam("oid") String oid, PolicyItemsDefinitionType policyItemsDefinition,
+ @Context MessageContext mc) {
+
+ Task task = RestServiceUtil.initRequest(mc);
+ OperationResult parentResult = task.getResult().createSubresult(OPERATION_GET);
+
+ Class clazz = ObjectTypes.getClassFromRestType(type);
+ Response response = null;
+ if (policyItemsDefinition == null) {
+ LOGGER.error("Policy items definition must not be null");
+ parentResult.recordFatalError("Policy items definition must not be null");
+ ResponseBuilder builder = Response.status(Status.BAD_REQUEST).entity(parentResult);
+ return builder.build();
+ }
+ try {
+ PrismObject object = model.getObject(clazz, oid, null, task, parentResult);
+
+ PrismObject valuePolicy = resolveUserPolicy((PrismObject) object, task,
+ parentResult);
+
+ boolean executeImmediatelly = false;
+ Collection propertyDeltas = new ArrayList<>();
+ for (PolicyItemDefinitionType policyItemDefinition : policyItemsDefinition
+ .getPolicyItemDefinition()) {
+
+ generateValue(object, valuePolicy, policyItemDefinition, task, parentResult);
+
+ if (BooleanUtils.isTrue(policyItemDefinition.isExecute())) {
+ executeImmediatelly = true;
+ PropertyDelta propertyDelta = PropertyDelta.createModificationReplaceProperty(policyItemDefinition.getTarget().getPath().getItemPath(), object.getDefinition(), policyItemDefinition.getValue());
+ propertyDeltas.add(propertyDelta);
+ }
+
+ }
+
+ if (executeImmediatelly) {
+ model.modifyObject(clazz, oid, propertyDeltas, null, task, parentResult);
+ }
+
+ ResponseBuilder responseBuilder = Response.ok(policyItemsDefinition);
+ response = responseBuilder.build();
+ } catch (Exception ex) {
+ response = RestServiceUtil.handleException(parentResult, ex);
+ }
+
+ parentResult.computeStatus();
+ finishRequest(task);
+ return response;
+
+ }
+
+ private PrismObject resolveUserPolicy(PrismObject user, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException {
+ CredentialsPolicyType policy = modelInteraction.getCredentialsPolicy(user, task, parentResult);
+
+
+ PrismObject valuePolicy = null;
+ if (policy.getPassword().getPasswordPolicyRef() != null) {
+ valuePolicy = model.getObject(ValuePolicyType.class, policy.getPassword().getPasswordPolicyRef().getOid(), null, task, parentResult);
+ }
+
+ return valuePolicy;
+ }
+
+ private void generateValue(PrismObject object, PrismObject policy, PolicyItemDefinitionType policyItemDefinition, Task task, OperationResult result) throws ExpressionEvaluationException, SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException {
+
+ StringPolicyType stringPolicy = null;
+ if (policyItemDefinition.getValuePolicyRef() != null) {
+ PrismObject valuePolicy = model.getObject(ValuePolicyType.class, policyItemDefinition.getValuePolicyRef().getOid(), null, task, result);
+ PrismObject policyOverride = valuePolicy.clone();
+ stringPolicy = policyOverride != null ? policyOverride.asObjectable().getStringPolicy() : null;
+ } else {
+
+ stringPolicy = policy != null ? policy.asObjectable().getStringPolicy() : null;
+ }
+ String newValue = policyProcessor.generate(stringPolicy, 10, object, "generating value for" + policyItemDefinition.getTarget().getPath(), task, result);
+ policyItemDefinition.setValue(newValue);
+ }
+
+ @POST
+ @Path("/{type}/{oid}/validate")
+ public Response validateValue(@PathParam("type") String type, @PathParam("oid") String oid, PolicyItemsDefinitionType policyItemsDefinition, @Context MessageContext mc) {
+
+ Task task = RestServiceUtil.initRequest(mc);
+ OperationResult parentResult = task.getResult().createSubresult(OPERATION_GET);
+
+ Class clazz = ObjectTypes.getClassFromRestType(type);
+ Response response = null;
+ if (policyItemsDefinition == null) {
+ LOGGER.error("Policy items definition must not be null");
+ parentResult.recordFatalError("Policy items definition must not be null");
+ ResponseBuilder builder = Response.status(Status.BAD_REQUEST).entity(parentResult);
+ return builder.build();
+ }
+ try {
+ PrismObject object = model.getObject(clazz, oid, null, task, parentResult);
+
+ PrismObject valuePolicy = resolveUserPolicy((PrismObject) object, task,
+ parentResult);
+
+ boolean executeImmediatelly = false;
+ Collection propertyDeltas = new ArrayList<>();
+ for (PolicyItemDefinitionType policyItemDefinition : policyItemsDefinition
+ .getPolicyItemDefinition()) {
+
+ validateValue(object, valuePolicy, policyItemDefinition, task, parentResult);
+
+ }
+
+
+
+ ResponseBuilder responseBuilder = Response.ok(policyItemsDefinition);
+ response = responseBuilder.build();
+ } catch (Exception ex) {
+ response = RestServiceUtil.handleException(parentResult, ex);
+ }
+
+ parentResult.computeStatus();
+ finishRequest(task);
+ return response;
+
+
+ }
+
+private void validateValue(PrismObject object, PrismObject policy, PolicyItemDefinitionType policyItemDefinition, Task task, OperationResult result) throws ExpressionEvaluationException, SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, PolicyViolationException {
+
+ ValuePolicyType stringPolicy = null;
+ if (policyItemDefinition.getValuePolicyRef() != null) {
+ PrismObject valuePolicy = model.getObject(ValuePolicyType.class, policyItemDefinition.getValuePolicyRef().getOid(), null, task, result);
+ PrismObject policyOverride = valuePolicy.clone();
+ stringPolicy = policyOverride != null ? policyOverride.asObjectable() : null;
+ } else {
+
+ stringPolicy = policy != null ? policy.asObjectable() : null;
+ }
+
+ ItemDefinition itemToValidateDefinition = object.findItem(policyItemDefinition.getTarget().getPath().getItemPath()).getDefinition();
+ itemToValidateDefinition.getTypeName();
+
+ prismContext.getEntityResolver();
+
+ //TODO
+ String valueToValidate = (String) policyItemDefinition.getValue();
+ if (StringUtils.isBlank(valueToValidate)) {
+ valueToValidate = object.findItem(policyItemDefinition.getTarget().getPath().getItemPath()).getRealValue();
+ }
+
+ if (!policyProcessor.validateValue(valueToValidate, stringPolicy, object, "validate value for " + object + " value " + valueToValidate, task, result)) {
+ result.computeStatus();
+ throw new PolicyViolationException("Validation for value: " + valueToValidate + " failed." + result.getMessage());
+ }
+
+ }
+
@GET
@Path("/users/{id}/policy")
@@ -177,6 +352,7 @@ public Response getValuePolicyForUser(@PathParam("id") String oid, @Context Mess
Response response;
try {
+
Collection> options =
SelectorOptions.createCollection(GetOperationOptions.createRaw());
PrismObject user = model.getObject(UserType.class, oid, options, task, parentResult);
diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java
index e7614418cbb..a8865af0647 100644
--- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java
+++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java
@@ -23,7 +23,7 @@
import com.evolveum.midpoint.model.api.*;
import com.evolveum.midpoint.model.api.visualizer.Scene;
import com.evolveum.midpoint.model.common.SystemObjectCache;
-import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyGenerator;
+import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyProcessor;
import com.evolveum.midpoint.model.impl.visualizer.Visualizer;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
@@ -122,7 +122,7 @@ public class ModelInteractionServiceImpl implements ModelInteractionService {
private SystemObjectCache systemObjectCache;
@Autowired(required = true)
- private ValuePolicyGenerator valuePolicyGenerator;
+ private ValuePolicyProcessor valuePolicyGenerator;
@Autowired(required = true)
private Protector protector;
diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java
index 248ab2c38fa..bd47fc3c04e 100644
--- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java
+++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java
@@ -44,8 +44,11 @@
import com.evolveum.midpoint.schema.ResourceShadowDiscriminator;
import com.evolveum.midpoint.schema.ResultHandler;
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.*;
+import com.evolveum.midpoint.security.api.MidPointPrincipal;
+import com.evolveum.midpoint.security.api.SecurityEnforcer;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.Holder;
import com.evolveum.midpoint.util.exception.CommunicationException;
@@ -60,6 +63,9 @@
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
+import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationCapabilityType;
+import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType;
+import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.PasswordCapabilityType;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
@@ -119,6 +125,9 @@ public class MidpointFunctionsImpl implements MidpointFunctions {
@Autowired
private ProvisioningService provisioningService;
+
+ @Autowired
+ private SecurityEnforcer securityEnforcer;
@Autowired(required = true)
private transient Protector protector;
@@ -1241,4 +1250,37 @@ public List getMembers(String orgOid) throws SchemaException, ObjectNo
.build();
return searchObjects(UserType.class, query, null);
}
+
+ @Override
+ public String computeProjectionLifecycle(F focus, ShadowType shadow, ResourceType resource) {
+ if (focus == null || shadow == null) {
+ return null;
+ }
+ if (!(focus instanceof UserType)) {
+ return null;
+ }
+ if (shadow.getKind() != null && shadow.getKind() != ShadowKindType.ACCOUNT) {
+ return null;
+ }
+ ProtectedStringType passwordPs = FocusTypeUtil.getPasswordValue((UserType)focus);
+ if (passwordPs != null && passwordPs.canGetCleartext()) {
+ return null;
+ }
+ CredentialsCapabilityType credentialsCapabilityType = ResourceTypeUtil.getEffectiveCapability(resource, CredentialsCapabilityType.class);
+ if (credentialsCapabilityType == null) {
+ return null;
+ }
+ PasswordCapabilityType passwordCapabilityType = credentialsCapabilityType.getPassword();
+ if (passwordCapabilityType == null) {
+ return null;
+ }
+ if (passwordCapabilityType.isEnabled() == Boolean.FALSE) {
+ return null;
+ }
+ return SchemaConstants.LIFECYCLE_PROPOSED;
+ }
+
+ public MidPointPrincipal getPrincipal() throws SecurityViolationException {
+ return securityEnforcer.getPrincipal();
+ }
}
diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java
index 6e50a3db262..59c5c2ab424 100644
--- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java
+++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java
@@ -15,8 +15,10 @@
*/
package com.evolveum.midpoint.model.impl.lens;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.function.Consumer;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
@@ -60,21 +62,7 @@
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
-import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType;
-import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentSelectorType;
-import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType;
-import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationType;
-import com.evolveum.midpoint.xml.ns._public.common.common_3.ConstructionType;
-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.MappingsType;
-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.OrgType;
-import com.evolveum.midpoint.xml.ns._public.common.common_3.PolicyConstraintsType;
-import com.evolveum.midpoint.xml.ns._public.common.common_3.PolicyRuleType;
-import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType;
-import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -636,7 +624,7 @@ private void evaluateSegmentTarget(AssignmentPathSegmentImpl segment, PlusMinusZ
ctx.evalAssignment.addRole(evalAssignmentTarget, mode);
if ((isNonNegative(mode)) && segment.isProcessMembership()) {
- evaluateMembership(targetType, relation, ctx);
+ collectMembership(targetType, relation, ctx);
}
// We continue evaluation even if the relation is non-membership and non-delegation.
@@ -655,10 +643,13 @@ private void evaluateSegmentTarget(AssignmentPathSegmentImpl segment, PlusMinusZ
if (matchesOrder && targetType instanceof AbstractRoleType && isNonNegative(mode)) {
for (AuthorizationType authorizationType: ((AbstractRoleType)targetType).getAuthorization()) {
Authorization authorization = createAuthorization(authorizationType, targetType.toString());
- ctx.evalAssignment.addAuthorization(authorization);
+ if (!ctx.evalAssignment.getAuthorizations().contains(authorization)) {
+ ctx.evalAssignment.addAuthorization(authorization);
+ }
}
- if (((AbstractRoleType)targetType).getAdminGuiConfiguration() != null) {
- ctx.evalAssignment.addAdminGuiConfiguration(((AbstractRoleType)targetType).getAdminGuiConfiguration());
+ AdminGuiConfigurationType adminGuiConfiguration = ((AbstractRoleType) targetType).getAdminGuiConfiguration();
+ if (adminGuiConfiguration != null && !ctx.evalAssignment.getAdminGuiConfigurations().contains(adminGuiConfiguration)) {
+ ctx.evalAssignment.addAdminGuiConfiguration(adminGuiConfiguration);
}
PolicyConstraintsType policyConstraints = ((AbstractRoleType)targetType).getPolicyConstraints();
if (policyConstraints != null) {
@@ -792,7 +783,7 @@ private void evaluateInducement(AssignmentPathSegmentImpl segment, PlusMinusZero
evaluateFromSegment(nextSegment, mode, ctx);
}
- private void evaluateMembership(FocusType targetType, QName relation, EvaluationContext ctx) {
+ private void collectMembership(FocusType targetType, QName relation, EvaluationContext ctx) {
PrismReferenceValue refVal = new PrismReferenceValue();
refVal.setObject(targetType.asPrismObject());
refVal.setTargetType(ObjectTypes.getObjectType(targetType.getClass()).getTypeQName());
@@ -800,18 +791,27 @@ private void evaluateMembership(FocusType targetType, QName relation, Evaluation
refVal.setTargetName(targetType.getName().toPolyString());
if (ctx.assignmentPath.getSegments().stream().anyMatch(aps -> DeputyUtils.isDelegationAssignment(aps.getAssignment()))) {
- LOGGER.trace("Adding target {} to delegationRef", targetType);
- ctx.evalAssignment.addDelegationRefVal(refVal);
+ addIfNotThere(ctx.evalAssignment.getDelegationRefVals(), ctx.evalAssignment::addDelegationRefVal, refVal,
+ "delegationRef", targetType);
} else {
if (targetType instanceof AbstractRoleType) {
- LOGGER.trace("Adding target {} to membershipRef", targetType);
- ctx.evalAssignment.addMembershipRefVal(refVal);
+ addIfNotThere(ctx.evalAssignment.getMembershipRefVals(), ctx.evalAssignment::addMembershipRefVal, refVal,
+ "membershipRef", targetType);
}
}
-
if (targetType instanceof OrgType) {
- LOGGER.trace("Adding target {} to orgRef", targetType);
- ctx.evalAssignment.addOrgRefVal(refVal);
+ addIfNotThere(ctx.evalAssignment.getOrgRefVals(), ctx.evalAssignment::addOrgRefVal, refVal,
+ "orgRef", targetType);
+ }
+ }
+
+ private void addIfNotThere(Collection collection, Consumer setter,
+ PrismReferenceValue refVal, String collectionName, FocusType targetType) {
+ if (!collection.contains(refVal)) {
+ LOGGER.trace("Adding target {} to {}", targetType, collectionName);
+ setter.accept(refVal);
+ } else {
+ LOGGER.trace("Would add target {} to {}, but it's already there", targetType, collectionName);
}
}
diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java
index 4f09dc5f197..a14182a976a 100644
--- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java
+++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java
@@ -246,7 +246,7 @@ public String getIntent() {
return refinedObjectClassDefinition.getIntent();
}
- public Object getDescription() {
+ public String getDescription() {
return constructionType.getDescription();
}
diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignmentImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignmentImpl.java
index 0ee2517c333..4f0835edb45 100644
--- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignmentImpl.java
+++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignmentImpl.java
@@ -198,9 +198,6 @@ public void addDelegationRefVal(PrismReferenceValue org) {
delegationRefVals.add(org);
}
- /* (non-Javadoc)
- * @see com.evolveum.midpoint.model.impl.lens.EvaluatedAssignment#getAuthorizations()
- */
@NotNull
@Override
public Collection getAuthorizations() {
diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java
index 4377d447aa2..6b9d596fe47 100644
--- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java
+++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java
@@ -59,7 +59,7 @@ public class LensContext implements ModelContext {
private String channel;
private LensFocusContext focusContext;
- private Collection projectionContexts = new ArrayList();
+ private Collection projectionContexts = new ArrayList<>();
/**
* EXPERIMENTAL. A trace of resource objects that once existed but were
@@ -92,7 +92,7 @@ public class LensContext implements ModelContext {
/*
* Executed deltas from rotten contexts.
*/
- private List> rottenExecutedDeltas = new ArrayList>();
+ private List> rottenExecutedDeltas = new ArrayList<>();
transient private ObjectTemplateType focusTemplate;
transient private ProjectionPolicyType accountSynchronizationSettings;
@@ -188,10 +188,6 @@ public ProvisioningService getProvisioningService() {
return provisioningService;
}
- public void setTriggeredResource(String triggeredResourceOid) {
- this.triggeredResourceOid = triggeredResourceOid;
- }
-
public void setTriggeredResource(ResourceType triggeredResource) {
if (triggeredResource != null) {
this.triggeredResourceOid = triggeredResource.getOid();
@@ -228,7 +224,7 @@ public LensFocusContext createFocusContext(Class explicitFocusClass) {
if (explicitFocusClass != null) {
this.focusClass = explicitFocusClass;
}
- focusContext = new LensFocusContext(focusClass, this);
+ focusContext = new LensFocusContext<>(focusClass, this);
return focusContext;
}
@@ -524,7 +520,7 @@ public OperationBusinessContextType getRequestBusinessContext() {
* better to merge them.
*/
public Collection> getAllChanges() throws SchemaException {
- Collection> allChanges = new ArrayList>();
+ Collection> allChanges = new ArrayList<>();
if (focusContext != null) {
addChangeIfNotNull(allChanges, focusContext.getPrimaryDelta());
addChangeIfNotNull(allChanges, focusContext.getSecondaryDelta());
@@ -551,7 +547,7 @@ public boolean hasAnyPrimaryChange() throws SchemaException {
}
public Collection> getPrimaryChanges() throws SchemaException {
- Collection> allChanges = new ArrayList>();
+ Collection> allChanges = new ArrayList<>();
if (focusContext != null) {
addChangeIfNotNull(allChanges, focusContext.getPrimaryDelta());
}
@@ -603,7 +599,7 @@ public Collection> getUnauditedExecut
*/
Collection> getExecutedDeltas(Boolean audited)
throws SchemaException {
- Collection> executedDeltas = new ArrayList>();
+ Collection> executedDeltas = new ArrayList<>();
if (focusContext != null) {
executedDeltas.addAll(focusContext.getExecutedDeltas(audited));
}
@@ -611,7 +607,7 @@ Collection> getExecutedDeltas(Boolean
executedDeltas.addAll(projCtx.getExecutedDeltas(audited));
}
if (audited == null) {
- executedDeltas.addAll(getRottenExecutedDeltas());
+ executedDeltas.addAll((Collection extends ObjectDeltaOperation extends ObjectType>>) getRottenExecutedDeltas());
}
return executedDeltas;
}
@@ -696,7 +692,7 @@ public LensProjectionContext createProjectionContext(ResourceShadowDiscriminator
private Map getResourceCache() {
if (resourceCache == null) {
- resourceCache = new HashMap();
+ resourceCache = new HashMap<>();
}
return resourceCache;
}
@@ -780,7 +776,7 @@ public void normalize() {
}
public LensContext clone() {
- LensContext clone = new LensContext(focusClass, prismContext, provisioningService);
+ LensContext clone = new LensContext<>(focusClass, prismContext, provisioningService);
copyValues(clone);
return clone;
}
@@ -813,7 +809,7 @@ private Map cloneResourceCache() {
if (resourceCache == null) {
return null;
}
- Map clonedMap = new HashMap();
+ Map clonedMap = new HashMap<>();
for (Entry entry : resourceCache.entrySet()) {
clonedMap.put(entry.getKey(), entry.getValue());
}
@@ -977,31 +973,40 @@ private void dumpPolicyRulesCollection(String label, int indent, StringBuilder s
}
}
- private void dumpEvaluatedAssignments(StringBuilder sb, String label,
- Collection> set, int indent) {
+ // of LensContext is of ObjectType; so we need to override it (but using another name to avoid IDE warnings)
+ private void dumpEvaluatedAssignments(StringBuilder sb, String label,
+ Collection> set, int indent) {
sb.append("\n");
DebugUtil.debugDumpLabel(sb, label, indent);
- for (EvaluatedAssignmentImpl assignment : set) {
+ for (EvaluatedAssignmentImpl assignment : set) {
sb.append("\n");
DebugUtil.indentDebugDump(sb, indent + 1);
- sb.append(" -> " + assignment.getTarget());
- dumpRules(sb, "focus rules", assignment.getFocusPolicyRules());
- dumpRules(sb, "this target rules", assignment.getThisTargetPolicyRules());
- dumpRules(sb, "other targets rules", assignment.getOtherTargetsPolicyRules());
+ sb.append("-> ").append(assignment.getTarget());
+ dumpRules(sb, "focus rules", indent + 3, assignment.getFocusPolicyRules());
+ dumpRules(sb, "this target rules", indent + 3, assignment.getThisTargetPolicyRules());
+ dumpRules(sb, "other targets rules", indent + 3, assignment.getOtherTargetsPolicyRules());
}
}
- private void dumpRules(StringBuilder sb, String label, Collection policyRules) {
- sb.append(" [").append(label).append("(").append(policyRules.size()).append("): ");
+ private void dumpRules(StringBuilder sb, String label, int indent, Collection policyRules) {
+ if (policyRules.isEmpty()) {
+ return;
+ }
+ sb.append("\n");
+ DebugUtil.debugDumpLabel(sb, "- " + label + " (" + policyRules.size() + ")", indent);
boolean first = true;
for (EvaluatedPolicyRule rule : policyRules) {
if (first) {
first = false;
+ sb.append(" ");
} else {
sb.append("; ");
}
if (rule.isGlobal()) {
- sb.append("G");
+ sb.append("G:");
+ }
+ if (rule.getName() != null) {
+ sb.append(rule.getName());
}
sb.append("(").append(PolicyRuleTypeUtil.toShortString(rule.getPolicyConstraints())).append(")");
sb.append("->");
@@ -1013,7 +1018,6 @@ private void dumpRules(StringBuilder sb, String label, Col
sb.append(")");
}
}
- sb.append("]");
}
public LensContextType toLensContextType() throws SchemaException {
@@ -1059,6 +1063,7 @@ public PrismContainer toPrismContainer() throws SchemaException
return lensContextTypeContainer;
}
+ @SuppressWarnings({"unchecked", "raw"})
public static LensContext fromLensContextType(LensContextType lensContextType, PrismContext prismContext,
ProvisioningService provisioningService, OperationResult parentResult)
throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException {
diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java
index 73496f6a50f..c9798441d4e 100644
--- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java
+++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java
@@ -1205,16 +1205,34 @@ public static void processRuleWithException(EvaluatedPolicyRule rule, EvaluatedP
}
+
public static void partialExecute(String componentName, ProjectorComponentRunnable runnable, Supplier optionSupplier)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException,
PolicyViolationException, ExpressionEvaluationException, ObjectAlreadyExistsException {
+ partialExecute(componentName, runnable, optionSupplier, null);
+ }
+
+ public static void partialExecute(String componentName, ProjectorComponentRunnable runnable,
+ Supplier optionSupplier, OperationResult result)
+ throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException,
+ PolicyViolationException, ExpressionEvaluationException, ObjectAlreadyExistsException {
PartialProcessingTypeType option = optionSupplier.get();
if (option == PartialProcessingTypeType.SKIP) {
LOGGER.debug("Skipping projector component {} because partial execution option is set to {}", componentName, option);
} else {
LOGGER.trace("Projector component started: {}", componentName);
- runnable.run();
- LOGGER.trace("Projector component finished: {}", componentName);
+ try {
+ runnable.run();
+ LOGGER.trace("Projector component finished: {}", componentName);
+ } catch (SchemaException | ObjectNotFoundException | CommunicationException | ConfigurationException | SecurityViolationException
+ | PolicyViolationException | ExpressionEvaluationException | ObjectAlreadyExistsException | RuntimeException | Error e) {
+ LOGGER.trace("Projector component error: {}: {}: {}", componentName, e.getClass().getSimpleName(), e.getMessage());
+ if (result != null) {
+ result.recordFatalError(e);
+ }
+ throw e;
+ }
+
}
}
diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ActivationProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ActivationProcessor.java
index 33d875c3d31..e52d59babaa 100644
--- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ActivationProcessor.java
+++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ActivationProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Evolveum
+ * Copyright (c) 2010-2017 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,9 @@
*/
package com.evolveum.midpoint.model.impl.lens.projector;
+import com.evolveum.midpoint.common.refinery.CompositeRefinedObjectClassDefinition;
import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision;
+import com.evolveum.midpoint.model.api.expr.MidpointFunctions;
import com.evolveum.midpoint.model.common.expression.ExpressionUtil;
import com.evolveum.midpoint.model.common.expression.ItemDeltaItem;
import com.evolveum.midpoint.model.common.expression.Source;
@@ -50,6 +52,7 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceActivationDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceBidirectionalMappingType;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectLifecycleDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectTypeDefinitionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
@@ -92,6 +95,9 @@ public class ActivationProcessor {
@Autowired
private MappingEvaluator mappingHelper;
+
+ @Autowired
+ private MidpointFunctions midpointFunctions;
public void processActivation(LensContext context,
LensProjectionContext projectionContext, XMLGregorianCalendar now, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException {
@@ -117,12 +123,12 @@ private void processActivationFocal(LensContext context
processActivationUserFuture(context, projectionContext, now, task, result);
}
- public void processActivationUserCurrent(LensContext context, LensProjectionContext accCtx,
+ public void processActivationUserCurrent(LensContext context, LensProjectionContext projCtx,
XMLGregorianCalendar now, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException {
- String accCtxDesc = accCtx.toHumanReadableString();
- SynchronizationPolicyDecision decision = accCtx.getSynchronizationPolicyDecision();
- SynchronizationIntent synchronizationIntent = accCtx.getSynchronizationIntent();
+ String accCtxDesc = projCtx.toHumanReadableString();
+ SynchronizationPolicyDecision decision = projCtx.getSynchronizationPolicyDecision();
+ SynchronizationIntent synchronizationIntent = projCtx.getSynchronizationIntent();
if (decision == SynchronizationPolicyDecision.BROKEN) {
LOGGER.trace("Broken projection {}, skipping further activation processing", accCtxDesc);
@@ -132,31 +138,31 @@ public void processActivationUserCurrent(LensContext co
throw new IllegalStateException("Decision "+decision+" already present for projection "+accCtxDesc);
}
- if (accCtx.isThombstone() || synchronizationIntent == SynchronizationIntent.UNLINK) {
- accCtx.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.UNLINK);
+ if (projCtx.isThombstone() || synchronizationIntent == SynchronizationIntent.UNLINK) {
+ projCtx.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.UNLINK);
LOGGER.trace("Evaluated decision for {} to {}, skipping further activation processing", accCtxDesc, SynchronizationPolicyDecision.UNLINK);
return;
}
- if (synchronizationIntent == SynchronizationIntent.DELETE || accCtx.isDelete()) {
+ if (synchronizationIntent == SynchronizationIntent.DELETE || projCtx.isDelete()) {
// TODO: is this OK?
- accCtx.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.DELETE);
+ projCtx.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.DELETE);
LOGGER.trace("Evaluated decision for {} to {}, skipping further activation processing", accCtxDesc, SynchronizationPolicyDecision.DELETE);
return;
}
- boolean shadowShouldExist = evaluateExistenceMapping(context, accCtx, now, true, task, result);
+ boolean shadowShouldExist = evaluateExistenceMapping(context, projCtx, now, true, task, result);
LOGGER.trace("Evaluated intended existence of projection {} to {}", accCtxDesc, shadowShouldExist);
// Let's reconcile the existence intent (shadowShouldExist) and the synchronization intent in the context
- LensProjectionContext lowerOrderContext = LensUtil.findLowerOrderContext(context, accCtx);
+ LensProjectionContext lowerOrderContext = LensUtil.findLowerOrderContext(context, projCtx);
if (synchronizationIntent == null || synchronizationIntent == SynchronizationIntent.SYNCHRONIZE) {
if (shadowShouldExist) {
- accCtx.setActive(true);
- if (accCtx.isExists()) {
+ projCtx.setActive(true);
+ if (projCtx.isExists()) {
if (lowerOrderContext != null && lowerOrderContext.isDelete()) {
// HACK HACK HACK
decision = SynchronizationPolicyDecision.DELETE;
@@ -180,21 +186,21 @@ public void processActivationUserCurrent(LensContext co
}
} else {
// Delete
- if (accCtx.isExists()) {
+ if (projCtx.isExists()) {
decision = SynchronizationPolicyDecision.DELETE;
} else {
// we should delete the entire context, but then we will lost track of what
// happened. So just ignore it.
decision = SynchronizationPolicyDecision.IGNORE;
// if there are any triggers then move them to focus. We may still need them.
- LensUtil.moveTriggers(accCtx, context.getFocusContext());
+ LensUtil.moveTriggers(projCtx, context.getFocusContext());
}
}
} else if (synchronizationIntent == SynchronizationIntent.ADD) {
if (shadowShouldExist) {
- accCtx.setActive(true);
- if (accCtx.isExists()) {
+ projCtx.setActive(true);
+ if (projCtx.isExists()) {
// Attempt to add something that is already there, but should be OK
decision = SynchronizationPolicyDecision.KEEP;
} else {
@@ -206,8 +212,8 @@ public void processActivationUserCurrent(LensContext co
} else if (synchronizationIntent == SynchronizationIntent.KEEP) {
if (shadowShouldExist) {
- accCtx.setActive(true);
- if (accCtx.isExists()) {
+ projCtx.setActive(true);
+ if (projCtx.isExists()) {
decision = SynchronizationPolicyDecision.KEEP;
} else {
decision = SynchronizationPolicyDecision.ADD;
@@ -222,7 +228,7 @@ public void processActivationUserCurrent(LensContext co
LOGGER.trace("Evaluated decision for projection {} to {}", accCtxDesc, decision);
- accCtx.setSynchronizationPolicyDecision(decision);
+ projCtx.setSynchronizationPolicyDecision(decision);
PrismObject focusNew = context.getFocusContext().getObjectNew();
if (focusNew == null) {
@@ -236,7 +242,7 @@ public void processActivationUserCurrent(LensContext co
return;
}
- ResourceObjectTypeDefinitionType resourceAccountDefType = accCtx.getResourceObjectTypeDefinitionType();
+ ResourceObjectTypeDefinitionType resourceAccountDefType = projCtx.getResourceObjectTypeDefinitionType();
if (resourceAccountDefType == null) {
LOGGER.trace("No refined object definition, therefore also no activation outbound definition, skipping activation processing for account " + accCtxDesc);
return;
@@ -247,9 +253,9 @@ public void processActivationUserCurrent(LensContext co
return;
}
- ActivationCapabilityType capActivation = ResourceTypeUtil.getEffectiveCapability(accCtx.getResource(), ActivationCapabilityType.class);
+ ActivationCapabilityType capActivation = ResourceTypeUtil.getEffectiveCapability(projCtx.getResource(), ActivationCapabilityType.class);
if (capActivation == null) {
- LOGGER.trace("Skipping activation status and validity processing because {} has no activation capability", accCtx.getResource());
+ LOGGER.trace("Skipping activation status and validity processing because {} has no activation capability", projCtx.getResource());
return;
}
@@ -259,43 +265,43 @@ public void processActivationUserCurrent(LensContext co
ActivationLockoutStatusCapabilityType capLockoutStatus = CapabilityUtil.getEffectiveActivationLockoutStatus(capActivation);
if (capStatus != null) {
- evaluateActivationMapping(context, accCtx,
+ evaluateActivationMapping(context, projCtx,
activationType.getAdministrativeStatus(),
SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS, SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS,
capActivation, now, true, ActivationType.F_ADMINISTRATIVE_STATUS.getLocalPart(), task, result);
} else {
- LOGGER.trace("Skipping activation administrative status processing because {} does not have activation administrative status capability", accCtx.getResource());
+ LOGGER.trace("Skipping activation administrative status processing because {} does not have activation administrative status capability", projCtx.getResource());
}
ResourceBidirectionalMappingType validFromMappingType = activationType.getValidFrom();
if (validFromMappingType == null || validFromMappingType.getOutbound() == null) {
- LOGGER.trace("Skipping activation validFrom processing because {} does not have appropriate outbound mapping", accCtx.getResource());
+ LOGGER.trace("Skipping activation validFrom processing because {} does not have appropriate outbound mapping", projCtx.getResource());
} else if (capValidFrom == null && !ExpressionUtil.hasExplicitTarget(validFromMappingType.getOutbound())) {
- LOGGER.trace("Skipping activation validFrom processing because {} does not have activation validFrom capability nor outbound mapping with explicit target", accCtx.getResource());
+ LOGGER.trace("Skipping activation validFrom processing because {} does not have activation validFrom capability nor outbound mapping with explicit target", projCtx.getResource());
} else {
- evaluateActivationMapping(context, accCtx, activationType.getValidFrom(),
+ evaluateActivationMapping(context, projCtx, activationType.getValidFrom(),
SchemaConstants.PATH_ACTIVATION_VALID_FROM, SchemaConstants.PATH_ACTIVATION_VALID_FROM,
null, now, true, ActivationType.F_VALID_FROM.getLocalPart(), task, result);
}
ResourceBidirectionalMappingType validToMappingType = activationType.getValidTo();
if (validToMappingType == null || validToMappingType.getOutbound() == null) {
- LOGGER.trace("Skipping activation validTo processing because {} does not have appropriate outbound mapping", accCtx.getResource());
+ LOGGER.trace("Skipping activation validTo processing because {} does not have appropriate outbound mapping", projCtx.getResource());
} else if (capValidTo == null && !ExpressionUtil.hasExplicitTarget(validToMappingType.getOutbound())) {
- LOGGER.trace("Skipping activation validTo processing because {} does not have activation validTo capability nor outbound mapping with explicit target", accCtx.getResource());
+ LOGGER.trace("Skipping activation validTo processing because {} does not have activation validTo capability nor outbound mapping with explicit target", projCtx.getResource());
} else {
- evaluateActivationMapping(context, accCtx, activationType.getValidTo(),
+ evaluateActivationMapping(context, projCtx, activationType.getValidTo(),
SchemaConstants.PATH_ACTIVATION_VALID_TO, SchemaConstants.PATH_ACTIVATION_VALID_TO,
null, now, true, ActivationType.F_VALID_TO.getLocalPart(), task, result);
}
if (capLockoutStatus != null) {
- evaluateActivationMapping(context, accCtx,
+ evaluateActivationMapping(context, projCtx,
activationType.getLockoutStatus(),
SchemaConstants.PATH_ACTIVATION_LOCKOUT_STATUS, SchemaConstants.PATH_ACTIVATION_LOCKOUT_STATUS,
capActivation, now, true, ActivationType.F_LOCKOUT_STATUS.getLocalPart(), task, result);
} else {
- LOGGER.trace("Skipping activation lockout status processing because {} does not have activation lockout status capability", accCtx.getResource());
+ LOGGER.trace("Skipping activation lockout status processing because {} does not have activation lockout status capability", projCtx.getResource());
}
}
@@ -448,85 +454,75 @@ private boolean evaluateExistenceMapping(final LensContext
// "default mapping"
return legal;
}
-
- MappingInitializer,PrismPropertyDefinition> initializer = new MappingInitializer,PrismPropertyDefinition>() {
- @Override
- public Mapping.Builder,PrismPropertyDefinition> initialize(Mapping.Builder,PrismPropertyDefinition> builder) throws SchemaException {
- // Source: legal
- ItemDeltaItem,PrismPropertyDefinition> legalSourceIdi = getLegalIdi(accCtx);
- Source,PrismPropertyDefinition> legalSource
- = new Source<>(legalSourceIdi, ExpressionConstants.VAR_LEGAL);
- builder.setDefaultSource(legalSource);
-
- // Source: assigned
- ItemDeltaItem,PrismPropertyDefinition> assignedIdi = getAssignedIdi(accCtx);
- Source,PrismPropertyDefinition> assignedSource = new Source<>(assignedIdi, ExpressionConstants.VAR_ASSIGNED);
- builder.addSource(assignedSource);
-
- // Source: focusExists
- ItemDeltaItem,PrismPropertyDefinition> focusExistsSourceIdi = getFocusExistsIdi(context.getFocusContext());
- Source,PrismPropertyDefinition> focusExistsSource
- = new Source<>(focusExistsSourceIdi, ExpressionConstants.VAR_FOCUS_EXISTS);
- builder.addSource(focusExistsSource);
-
- // Variable: focus
- builder.addVariableDefinition(ExpressionConstants.VAR_FOCUS, context.getFocusContext().getObjectDeltaObject());
-
- // Variable: user (for convenience, same as "focus")
- builder.addVariableDefinition(ExpressionConstants.VAR_USER, context.getFocusContext().getObjectDeltaObject());
-
- // Variable: shadow
- builder.addVariableDefinition(ExpressionConstants.VAR_SHADOW, accCtx.getObjectDeltaObject());
-
- // Variable: resource
- builder.addVariableDefinition(ExpressionConstants.VAR_RESOURCE, accCtx.getResource());
-
- builder.setOriginType(OriginType.OUTBOUND);
- builder.setOriginObject(accCtx.getResource());
- return builder;
- }
- };
-
- final MutableBoolean output = new MutableBoolean(false);
-
- MappingOutputProcessor> processor = new MappingOutputProcessor>() {
- @Override
- public void process(ItemPath mappingOutputPath,
- PrismValueDeltaSetTriple> outputTriple) throws ExpressionEvaluationException {
- if (outputTriple == null) {
- // The "default existence mapping"
- output.setValue(legal);
- return;
- }
-
- Collection> nonNegativeValues = outputTriple.getNonNegativeValues();
-
- // MID-3507: this is probably the bug. The processor is executed after every mapping.
- // The processing will die on the error if one mapping returns a value and the other mapping returns null
- // (e.g. because the condition is false). This should be fixed.
- if (nonNegativeValues == null || nonNegativeValues.isEmpty()) {
- throw new ExpressionEvaluationException("Activation existence expression resulted in null or empty value for projection " + accCtxDesc);
- }
- if (nonNegativeValues.size() > 1) {
- throw new ExpressionEvaluationException("Activation existence expression resulted in too many values ("+nonNegativeValues.size()+") for projection " + accCtxDesc);
- }
-
- output.setValue(nonNegativeValues.iterator().next().getValue());
- }
- };
-
+
MappingEvaluatorParams, PrismPropertyDefinition, ShadowType, F> params = new MappingEvaluatorParams<>();
params.setMappingTypes(outbound);
params.setMappingDesc("outbound existence mapping in projection " + accCtxDesc);
params.setNow(now);
- params.setInitializer(initializer);
- params.setProcessor(processor);
params.setAPrioriTargetObject(accCtx.getObjectOld());
params.setEvaluateCurrent(current);
params.setTargetContext(accCtx);
params.setFixTarget(true);
params.setContext(context);
+ params.setInitializer(builder -> {
+ // Source: legal
+ ItemDeltaItem,PrismPropertyDefinition> legalSourceIdi = getLegalIdi(accCtx);
+ Source,PrismPropertyDefinition> legalSource
+ = new Source<>(legalSourceIdi, ExpressionConstants.VAR_LEGAL);
+ builder.defaultSource(legalSource);
+
+ // Source: assigned
+ ItemDeltaItem,PrismPropertyDefinition> assignedIdi = getAssignedIdi(accCtx);
+ Source,PrismPropertyDefinition> assignedSource = new Source<>(assignedIdi, ExpressionConstants.VAR_ASSIGNED);
+ builder.addSource(assignedSource);
+
+ // Source: focusExists
+ ItemDeltaItem,PrismPropertyDefinition> focusExistsSourceIdi = getFocusExistsIdi(context.getFocusContext());
+ Source,PrismPropertyDefinition> focusExistsSource
+ = new Source<>(focusExistsSourceIdi, ExpressionConstants.VAR_FOCUS_EXISTS);
+ builder.addSource(focusExistsSource);
+
+ // Variable: focus
+ builder.addVariableDefinition(ExpressionConstants.VAR_FOCUS, context.getFocusContext().getObjectDeltaObject());
+
+ // Variable: user (for convenience, same as "focus")
+ builder.addVariableDefinition(ExpressionConstants.VAR_USER, context.getFocusContext().getObjectDeltaObject());
+
+ // Variable: shadow
+ builder.addVariableDefinition(ExpressionConstants.VAR_SHADOW, accCtx.getObjectDeltaObject());
+
+ // Variable: resource
+ builder.addVariableDefinition(ExpressionConstants.VAR_RESOURCE, accCtx.getResource());
+
+ builder.originType(OriginType.OUTBOUND);
+ builder.originObject(accCtx.getResource());
+ return builder;
+ });
+
+ final MutableBoolean output = new MutableBoolean(false);
+ params.setProcessor((mappingOutputPath,outputTriple) -> {
+ if (outputTriple == null) {
+ // The "default existence mapping"
+ output.setValue(legal);
+ return;
+ }
+
+ Collection> nonNegativeValues = outputTriple.getNonNegativeValues();
+
+ // MID-3507: this is probably the bug. The processor is executed after every mapping.
+ // The processing will die on the error if one mapping returns a value and the other mapping returns null
+ // (e.g. because the condition is false). This should be fixed.
+ if (nonNegativeValues == null || nonNegativeValues.isEmpty()) {
+ throw new ExpressionEvaluationException("Activation existence expression resulted in null or empty value for projection " + accCtxDesc);
+ }
+ if (nonNegativeValues.size() > 1) {
+ throw new ExpressionEvaluationException("Activation existence expression resulted in too many values ("+nonNegativeValues.size()+") for projection " + accCtxDesc);
+ }
+
+ output.setValue(nonNegativeValues.iterator().next().getValue());
+ });
+
PrismPropertyDefinitionImpl shadowExistsDef = new PrismPropertyDefinitionImpl<>(
SHADOW_EXISTS_PROPERTY_NAME,
DOMUtil.XSD_BOOLEAN, prismContext);
@@ -534,10 +530,6 @@ public void process(ItemPath mappingOutputPath,
shadowExistsDef.setMaxOccurs(1);
params.setTargetItemDefinition(shadowExistsDef);
mappingHelper.evaluateMappingSetProjection(params, task, result);
-
-// PrismValueDeltaSetTriple> outputTriple = mappingHelper.evaluateMappingSetProjection(
-// outbound, "outbound existence mapping in projection " + accCtxDesc,
-// now, initializer, null, null, accCtx.getObjectOld(), current, null, context, accCtx, task, result);
return (boolean) output.getValue();
@@ -713,7 +705,76 @@ private ItemDeltaItem,PrismPr
return new ItemDeltaItem,PrismPropertyDefinition>(existsPropOld, existsDelta, existsProp);
}
}
-
+
+ public void processLifecycle(LensContext context, LensProjectionContext projCtx,
+ XMLGregorianCalendar now, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException {
+
+ LensFocusContext focusContext = context.getFocusContext();
+ if (focusContext != null && !FocusType.class.isAssignableFrom(focusContext.getObjectTypeClass())) {
+ // We can do this only for focal object.
+ return;
+ }
+
+ processLifecycleFocus((LensContext)context, projCtx, now, task, result);
+ }
+
+ private void processLifecycleFocus(LensContext context, LensProjectionContext projCtx,
+ XMLGregorianCalendar now, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException {
+
+ LensFocusContext focusContext = context.getFocusContext();
+ if (focusContext == null) {
+ return;
+ }
+
+ ResourceObjectLifecycleDefinitionType lifecycleDef = null;
+ ResourceObjectTypeDefinitionType resourceAccountDefType = projCtx.getResourceObjectTypeDefinitionType();
+ if (resourceAccountDefType != null) {
+ lifecycleDef = resourceAccountDefType.getLifecycle();
+ }
+ ResourceBidirectionalMappingType lifecycleStateMappingType = null;
+ if (lifecycleDef != null) {
+ lifecycleStateMappingType = lifecycleDef.getLifecycleState();
+ }
+
+ if (lifecycleStateMappingType == null || lifecycleStateMappingType.getOutbound() == null) {
+
+ if (!projCtx.isAdd()) {
+ return;
+ }
+
+ PrismObject focusNew = focusContext.getObjectNew();
+ if (focusNew == null) {
+ return;
+ }
+
+ PrismObject projectionNew = projCtx.getObjectNew();
+ if (projectionNew == null) {
+ return;
+ }
+
+ String lifecycle = midpointFunctions.computeProjectionLifecycle(
+ focusNew.asObjectable(), projectionNew.asObjectable(), projCtx.getResource());
+
+ LOGGER.trace("Computed projection lifecycle (default expression): {}", lifecycle);
+
+ if (lifecycle != null) {
+ PrismPropertyDefinition propDef = projCtx.getObjectDefinition().findPropertyDefinition(SchemaConstants.PATH_LIFECYCLE_STATE);
+ PropertyDelta lifeCycleDelta = propDef.createEmptyDelta(SchemaConstants.PATH_LIFECYCLE_STATE);
+ PrismPropertyValue pval = new PrismPropertyValue(lifecycle);
+ pval.setOriginType(OriginType.OUTBOUND);
+ lifeCycleDelta.setValuesToReplace(pval);
+ projCtx.swallowToSecondaryDelta(lifeCycleDelta);
+ }
+
+ } else {
+
+ evaluateActivationMapping(context, projCtx, lifecycleStateMappingType,
+ SchemaConstants.PATH_LIFECYCLE_STATE, SchemaConstants.PATH_LIFECYCLE_STATE,
+ null, now, false, ObjectType.F_LIFECYCLE_STATE.getLocalPart(), task, result);
+ }
+
+ }
+
private PrismObjectDefinition getUserDefinition() {
if (userDefinition == null) {
userDefinition = prismContext.getSchemaRegistry()
diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java
index 79d2137035a..8787e457c22 100644
--- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java
+++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java
@@ -32,7 +32,7 @@
import org.springframework.stereotype.Component;
import com.evolveum.midpoint.model.common.stringpolicy.StringPolicyUtils;
-import com.evolveum.midpoint.model.common.stringpolicy.ValuePolicyGenerator;
+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;
@@ -116,7 +116,7 @@ public class PasswordPolicyProcessor {
Protector protector;
@Autowired(required = true)
- private ValuePolicyGenerator valuePolicyGenerator;
+ private ValuePolicyProcessor valuePolicyGenerator;
@Autowired(required = true)
ModelObjectResolver resolver;
@@ -180,7 +180,7 @@ void processPasswordPolicy(LensFocusContext focusContex
}
ValuePolicyType passwordPolicy = determinePasswordPolicy(focusContext, task, result);
- processPasswordPolicy(passwordPolicy, focusContext.getObjectOld(), null, passwordValueProperty, task, result);
+ processPasswordPolicy(focusContext, passwordPolicy, passwordValueProperty, task, result);
if (passwordValueProperty != null && isPasswordChange) {
processPasswordHistoryDeltas(focusContext, context, focusContext.getSecurityPolicy(), now, task, result);
@@ -228,7 +228,7 @@ public ValuePolicyType determinePasswordPolicy(LensFocusC
return passwordPolicy.asObjectable();
}
- private void processPasswordPolicy(ValuePolicyType passwordPolicy, PrismObject focus, PrismObject projection, PrismProperty passwordProperty,
+ private void processPasswordPolicy(LensFocusContext focusContext, ValuePolicyType passwordPolicy, PrismProperty passwordProperty,
Task task, OperationResult result) throws PolicyViolationException, SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
if (passwordPolicy == null) {
@@ -237,14 +237,9 @@ private void processPasswordPolicy(ValuePolicyType passwor
}
String passwordValue = determinePasswordValue(passwordProperty);
- PasswordType currentPasswordType = determineCurrentPassword(focus);
+ PasswordType currentPasswordType = determineCurrentPassword(focusContext.getObjectOld());
- boolean isValid;
- if (projection != null) {
- isValid = validatePassword(passwordValue, currentPasswordType, passwordPolicy, projection, "projection password policy", task, result);
- } else {
- isValid = validatePassword(passwordValue, currentPasswordType, passwordPolicy, focus, "focus password policy", task, result);
- }
+ boolean isValid = validatePassword(passwordValue, currentPasswordType, passwordPolicy, focusContext.getObjectAny(), "focus password policy", task, result);
if (!isValid) {
result.computeStatus();
@@ -326,7 +321,19 @@ void processPasswordPolicy(LensProjectionContext projecti
accountShadow = projectionContext.getObjectNew();
}
- processPasswordPolicy(passwordPolicy, null, accountShadow, password, task, result);
+ if (passwordPolicy == null) {
+ LOGGER.trace("Skipping processing password policies. Password policy not specified.");
+ return;
+ }
+
+ String passwordValue = determinePasswordValue(password);
+
+ boolean isValid = validatePassword(passwordValue, null, passwordPolicy, accountShadow, "projection password policy", task, result);
+
+ if (!isValid) {
+ result.computeStatus();
+ throw new PolicyViolationException("Provided password does not satisfy password policies. " + result.getMessage());
+ }
}
@@ -338,66 +345,16 @@ public boolean validatePassword(String newPassword, Passw
OperationResult result = parentResult.createSubresult(OPERATION_PASSWORD_VALIDATION);
result.addParam("policyName", pp.getName());
- normalize(pp);
-
- if (newPassword == null &&
- (pp.getMinOccurs() == null || XsdTypeMapper.multiplicityToInteger(pp.getMinOccurs()) == 0)) {
- // No password is allowed
- result.recordSuccess();
- return true;
- }
-
- if (newPassword == null) {
- newPassword = "";
- }
-
- LimitationsType lims = pp.getStringPolicy().getLimitations();
StringBuilder message = new StringBuilder();
- testMinimalLength(newPassword, lims, result, message);
- testMaximalLength(newPassword, lims, result, message);
-
- testMinimalUniqueCharacters(newPassword, lims, result, message);
+ boolean stringPolicyValid = valuePolicyGenerator.validateValue(newPassword, pp, object, message, shortDesc, task, result);
try {
testPasswordHistoryEntries(newPassword, currentPasswordType, pp, result, message);
} catch (EncryptionException e) {
throw new SystemException(e.getMessage(), e);
}
- if (lims.getLimit() == null || lims.getLimit().isEmpty()) {
- if (message.toString() == null || message.toString().isEmpty()) {
- result.computeStatus();
- } else {
- result.computeStatus(message.toString());
-
- }
-
- return result.isAcceptable();
- }
-
- // check limitation
- HashSet validChars = null;
- HashSet allValidChars = new HashSet<>();
- List passwd = StringPolicyUtils.stringTokenizer(newPassword);
- for (StringLimitType stringLimitationType : lims.getLimit()) {
- OperationResult limitResult = new OperationResult(
- "Tested limitation: " + stringLimitationType.getDescription());
-
- validChars = getValidCharacters(stringLimitationType.getCharacterClass(), pp);
- int count = countValidCharacters(validChars, passwd);
- allValidChars.addAll(validChars);
- testMinimalOccurence(stringLimitationType, count, limitResult, message);
- testMaximalOccurence(stringLimitationType, count, limitResult, message);
- testMustBeFirst(stringLimitationType, count, limitResult, message, newPassword, validChars);
-
- limitResult.computeStatus();
- result.addSubresult(limitResult);
- }
- testInvalidCharacters(passwd, allValidChars, result, message);
-
- testCheckExpression(newPassword, lims, object, shortDesc, task, result, message);
-
if (message.toString() == null || message.toString().isEmpty()) {
result.computeStatus();
} else {
@@ -405,33 +362,7 @@ public boolean validatePassword(String newPassword, Passw
}
- return result.isAcceptable();
- }
-
- /**
- * add defined default values
- */
- private void normalize(ValuePolicyType pp) {
- if (null == pp) {
- throw new IllegalArgumentException("Password policy cannot be null");
- }
-
- if (null == pp.getStringPolicy()) {
- StringPolicyType sp = new StringPolicyType();
- pp.setStringPolicy(StringPolicyUtils.normalize(sp));
- } else {
- pp.setStringPolicy(StringPolicyUtils.normalize(pp.getStringPolicy()));
- }
-
- if (null == pp.getLifetime()) {
- PasswordLifeTimeType lt = new PasswordLifeTimeType();
- lt.setExpiration(-1);
- lt.setWarnBeforeExpiration(0);
- lt.setLockAfterExpiration(0);
- lt.setMinPasswordAge(0);
- lt.setPasswordHistoryLength(0);
- }
- return;
+ return result.isAcceptable() && stringPolicyValid;
}
private void testPasswordHistoryEntries(String newPassword, PasswordType currentPasswordType,
@@ -489,191 +420,6 @@ private void appendHistoryViolationMessage(OperationResult result, StringBuilder
message.append("\n");
}
- private void testInvalidCharacters(List password, HashSet validChars,
- OperationResult result, StringBuilder message) {
-
- // Check if there is no invalid character
- StringBuilder invalidCharacters = new StringBuilder();
- for (String s : password) {
- if (!validChars.contains(s)) {
- // memorize all invalid characters
- invalidCharacters.append(s);
- }
- }
- if (invalidCharacters.length() > 0) {
- String msg = "Characters [ " + invalidCharacters + " ] are not allowed in password";
- result.addSubresult(new OperationResult("Check if password does not contain invalid characters",
- OperationResultStatus.FATAL_ERROR, msg));
- message.append(msg);
- message.append("\n");
- }
- // else {
- // ret.addSubresult(new OperationResult("Check if password does not
- // contain invalid characters OK.",
- // OperationResultStatus.SUCCESS, "PASSED"));
- // }
-
- }
-
- private void testMustBeFirst(StringLimitType stringLimitationType, int count,
- OperationResult limitResult, StringBuilder message, String password, Set validChars) {
- // test if first character is valid
- if (stringLimitationType.isMustBeFirst() == null) {
- stringLimitationType.setMustBeFirst(false);
- }
- // we check mustBeFirst only for non-empty passwords
- if (StringUtils.isNotEmpty(password) && stringLimitationType.isMustBeFirst()
- && !validChars.contains(password.substring(0, 1))) {
- String msg = "First character is not from allowed set. Allowed set: " + validChars.toString();
- limitResult.addSubresult(
- new OperationResult("Check valid first char", OperationResultStatus.FATAL_ERROR, msg));
- message.append(msg);
- message.append("\n");
- }
- // else {
- // limitResult.addSubresult(new OperationResult("Check valid first char
- // in password OK.",
- // OperationResultStatus.SUCCESS, "PASSED"));
- // }
-
- }
-
- private void testMaximalOccurence(StringLimitType stringLimitationType, int count,
- OperationResult limitResult, StringBuilder message) {
- // Test maximal occurrence
- if (stringLimitationType.getMaxOccurs() != null) {
-
- if (stringLimitationType.getMaxOccurs() < count) {
- String msg = "Required maximal occurrence (" + stringLimitationType.getMaxOccurs()
- + ") of characters (" + stringLimitationType.getDescription()
- + ") in password was exceeded (occurrence of characters in password " + count + ").";
- limitResult.addSubresult(new OperationResult("Check maximal occurrence of characters",
- OperationResultStatus.FATAL_ERROR, msg));
- message.append(msg);
- message.append("\n");
- }
- // else {
- // limitResult.addSubresult(new OperationResult(
- // "Check maximal occurrence of characters in password OK.",
- // OperationResultStatus.SUCCESS,
- // "PASSED"));
- // }
- }
-
- }
-
- private void testMinimalOccurence(StringLimitType stringLimitation, int count,
- OperationResult result, StringBuilder message) {
- // Test minimal occurrence
- if (stringLimitation.getMinOccurs() == null) {
- stringLimitation.setMinOccurs(0);
- }
- if (stringLimitation.getMinOccurs() > count) {
- String msg = "Required minimal occurrence (" + stringLimitation.getMinOccurs()
- + ") of characters (" + stringLimitation.getDescription()
- + ") in password is not met (occurrence of characters in password " + count + ").";
- result.addSubresult(new OperationResult("Check minimal occurrence of characters",
- OperationResultStatus.FATAL_ERROR, msg));
- message.append(msg);
- message.append("\n");
- }
- }
-
- private int countValidCharacters(Set