{"id":5980,"date":"2012-09-17T12:28:50","date_gmt":"2012-09-17T17:28:50","guid":{"rendered":"http:\/\/jianmingli.com\/wp\/?p=5980"},"modified":"2012-10-11T14:40:51","modified_gmt":"2012-10-11T19:40:51","slug":"openidm-integration","status":"publish","type":"post","link":"https:\/\/jianmingli.com\/wp\/?p=5980","title":{"rendered":"OpenIDM 2.1 Integration Guide"},"content":{"rendered":"<div class='toc wptoc'>\n<h2>Contents<\/h2>\n<ol class='toc-odd level-1'>\n\t<li>\n\t\t<a href=\"#Architectural_Overview\">Architectural Overview<\/a>\n\t\t<ol class='toc-even level-2'>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Modular_Framework\">Modular Framework<\/a>\n\t\t\t<\/li>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Infrastructure_Modules\">Infrastructure Modules<\/a>\n\t\t\t<\/li>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Core_Services\">Core Services<\/a>\n\t\t\t\t<ol class='toc-odd level-3'>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Object_model\">Object model<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Managed_objects\">Managed objects<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#System_Objects\">System Objects<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Mappings\">Mappings<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Synchronization_and_Reconciliation\">Synchronization and Reconciliation<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t<\/ol>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Access_Layer\">Access Layer<\/a>\n\t\t\t<\/li>\n\t\t<\/ol>\n\t<li>\n\t\t<a href=\"#Configuration_Options\">Configuration Options<\/a>\n\t\t<ol class='toc-even level-2'>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Configuration_Objects\">Configuration Objects<\/a>\n\t\t\t\t<ol class='toc-odd level-3'>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Single_Instance_Configuration_Objects\">Single Instance Configuration Objects<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Multiple_Instance_Configuration_Objects\">Multiple Instance Configuration Objects<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t<\/ol>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Configuration_Over_REST\">Configuration Over REST<\/a>\n\t\t\t<\/li>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Property_Substitution_in_Configuration\">Property Substitution in Configuration<\/a>\n\t\t\t<\/li>\n\t\t<\/ol>\n\t<li>\n\t\t<a href=\"#Configure_Server_Logs\">Configure Server Logs<\/a>\n\t<\/li>\n\t<li>\n\t\t<a href=\"#Connect_to_External_Resources\">Connect to External Resources<\/a>\n\t\t<ol class='toc-even level-2'>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Accessing_Remote_Connectors\">Accessing Remote Connectors<\/a>\n\t\t\t<\/li>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Configure_Connectors\">Configure Connectors<\/a>\n\t\t\t<\/li>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Connector_Configuration_Examples\">Connector Configuration Examples<\/a>\n\t\t\t<\/li>\n\t\t<\/ol>\n\t<li>\n\t\t<a href=\"#Configuring_Synchronization\">Configuring Synchronization<\/a>\n\t\t<ol class='toc-even level-2'>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Types_of_Synchronization\">Types of Synchronization<\/a>\n\t\t\t\t<ol class='toc-odd level-3'>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Reconciliation\">Reconciliation<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#LiveSync\">LiveSync<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t<\/ol>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Flexible_Data_Model\">Flexible Data Model<\/a>\n\t\t\t<\/li>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Basic_Data_Flow_Configuration\">Basic Data Flow Configuration<\/a>\n\t\t\t\t<ol class='toc-odd level-3'>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Connector_Configuration_Files\">Connector Configuration Files<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Synchronization_Mappings_File\">Synchronization Mappings File<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t<\/ol>\n\t\t\t<li>\n\t\t\t\t<a href=\"#\"><\/a>\n\t\t\t\t<ol class='toc-odd level-3'>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#_1\"><\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t<\/ol>\n\t\t\t<li>\n\t\t\t\t<a href=\"#_2\"><\/a>\n\t\t\t<\/li>\n\t\t\t<li>\n\t\t\t\t<a href=\"#_3\"><\/a>\n\t\t\t<\/li>\n\t\t<\/ol>\n\t<li>\n\t\t<a href=\"#Scheduling_Synchronization\">Scheduling Synchronization<\/a>\n\t<\/li>\n\t<li>\n\t\t<a href=\"#Managing_Passwords\">Managing Passwords<\/a>\n\t\t<ol class='toc-even level-2'>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Enforcing_Password_Policies\">Enforcing Password Policies<\/a>\n\t\t\t<\/li>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Password_Synchronization\">Password Synchronization<\/a>\n\t\t\t<\/li>\n\t\t<\/ol>\n\t<li>\n\t\t<a href=\"#Managing_Authentication_Authorization__RBAC\">Managing Authentication, Authorization & RBAC<\/a>\n\t\t<ol class='toc-even level-2'>\n\t\t\t<li>\n\t\t\t\t<a href=\"#OpenIDM_Users\">OpenIDM Users<\/a>\n\t\t\t\t<ol class='toc-odd level-3'>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Internal_Users\">Internal Users<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Managed_Users\">Managed Users<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t<\/ol>\n<\/ol>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Authentication\">Authentication<\/a>\n\t\t\t\t<ol class='toc-even level-2'>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Default_Attributes\">Default Attributes<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Authentication_1\">Authentication<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Roles\">Roles<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Authorization\">Authorization<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t<\/ol>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Securing__Hardening_OpenIDM\">Securing & Hardening OpenIDM<\/a>\n\t\t\t<\/li>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Integrating_Business_Processes__Workflows\">Integrating Business Processes & Workflows<\/a>\n\t\t\t\t<ol class='toc-even level-2'>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Remote_Integration\">Remote Integration<\/a>\n\t\t\t\t\t\t<ol class='toc-odd level-3'>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"#Checkout_Trunk\">Checkout Trunk<\/a>\n\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"#Compile_and_Package_Source_Codes\">Compile and Package Source Codes<\/a>\n\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"#Install_OpenIDM\">Install OpenIDM<\/a>\n\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"#Install_Activiti\">Install Activiti<\/a>\n\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"#Deploy_OpenIDM_Workflow_to_Activiti_Tomcat\">Deploy OpenIDM Workflow to Activiti Tomcat<\/a>\n\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"#Configure_OpenIDM_to_use_Remote_Activiti\">Configure OpenIDM to use Remote Activiti<\/a>\n\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"#Install_the_sample_workflow_example.bpmn20.xml_from_the_openidm-workflow-activiti_project\">Install the sample workflow (example.bpmn20.xml) from the openidm-workflow-activiti project<\/a>\n\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t<\/ol>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Local_Activiti_Integration\">Local Activiti Integration<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Configure_Activiti_Engine\">Configure Activiti Engine<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Define_Activiti_Workflows\">Define Activiti Workflows<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Invoking_Activiti_Workflows\">Invoking Activiti Workflows<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Email_Notification_Example\">Email Notification Example<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Example_Sunset_Workflow_Triggered_By_Reconciliation\">Example Sunset Workflow Triggered By Reconciliation<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t<\/ol>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Sending_Email\">Sending Email<\/a>\n\t\t\t\t<ol class='toc-even level-2'>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Setup_Outbound_Email\">Setup Outbound Email<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Send_mail_from_REST\">Send mail from REST<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#Sending_Mail_from_Script\">Sending Mail from Script<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t<\/ol>\n\t\t\t<li>\n\t\t\t\t<a href=\"#Errors\">Errors<\/a>\n\t\t\t\t<ol class='toc-even level-2'>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<a href=\"#action_method_not_implemented_on_workflow\">action method not implemented on workflow<\/a>\n\t\t\t\t\t<\/li>\n\t\t\t\t<\/ol>\n\t\t\t<li>\n\t\t\t\t<a href=\"#References\">References<\/a>\n\t\t\t<\/li>\n<\/ol>\n<\/ol>\n<\/div>\n<div class='wptoc-end'>&nbsp;<\/div>\n<span id=\"Architectural_Overview\"><h2>Architectural Overview<\/h2><\/span>\n<span id=\"\"><h6><a href=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_Architecture_Overview.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_Architecture_Overview-300x245.jpg\" alt=\"\" title=\"OpenIDM_IntGuide_Architecture_Overview\" width=\"300\" height=\"245\" class=\"aligncenter size-medium wp-image-5987\" srcset=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_Architecture_Overview-300x245.jpg 300w, https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_Architecture_Overview.jpg 543w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/h6><\/span>\n<span id=\"Modular_Framework\"><h3>Modular Framework<\/h3><\/span>\n<p>* OSGi (Felix)<br \/>\n* Servlet (Jetty)<\/p>\n<span id=\"Infrastructure_Modules\"><h3>Infrastructure Modules<\/h3><\/span>\n<p>* Scheduler (Quartz)<br \/>\n* Script engine (JavaScript)<br \/>\n* Audit logging<br \/>\n* Repository<br \/>\n&#8211; MySQL for production use<br \/>\n&#8211; OrientDB for evaluation use<br \/>\n&#8211; Repository API is based on JSON object model and RESTful Web Services<\/p>\n<span id=\"Core_Services\"><h3>Core Services<\/h3><\/span>\n<span id=\"Object_model\"><h4>Object model<\/h4><\/span>\n<p>* Java based object model<br \/>\n* Java object model represents of JSON object model<br \/>\n* Also exposes a set of triggers and functions for scripting hookups<\/p>\n<span id=\"Managed_objects\"><h4>Managed objects<\/h4><\/span>\n<p>* They are identity related data managed by OpenIDM<br \/>\n* Configurable, JSON based data structure living the repository<br \/>\n* Default configuration of a manged object is that of a <em>user<\/em><br \/>\n* Can be access via <em>\/openidm\/managed\/<\/em> context<\/p>\n<pre lang=\"bash\">\r\ncurl\r\n  --header \"X-OpenIDM-Username: openidm-admin\"\r\n  --header \"X-OpenIDM-Password: openidm-admin\"\r\n  --request GET\r\n  \"http:\/\/localhost:8080\/openidm\/managed\/...\"\r\n<\/pre>\n<span id=\"System_Objects\"><h4>System Objects<\/h4><\/span>\n<p>* They are pluggable representations of objects on external systems, e.g. a user entry stored in <strong>external<\/strong> LDAP.<br \/>\n* Can be access via <em>\/openidm\/system\/<\/em> context<\/p>\n<pre lang=\"bash\">\r\ncurl\r\n  --header \"X-OpenIDM-Username: openidm-admin\"\r\n  --header \"X-OpenIDM-Password: openidm-admin\"\r\n  --request GET\r\n  \"http:\/\/localhost:8080\/openidm\/system\/...\"\r\n<\/pre>\n<span id=\"Mappings\"><h4>Mappings<\/h4><\/span>\n<p>* Mappings define policies between source and target objects and their attributes during synchronization and reconciliation<br \/>\n* Can also define triggers for validation, customization, filtering, and transformation of source and target objects<\/p>\n<span id=\"Synchronization_and_Reconciliation\"><h4>Synchronization and Reconciliation<\/h4><\/span>\n<span id=\"Access_Layer\"><h3>Access Layer<\/h3><\/span>\n<p>* Provides UI and public APIs (RESTful) for accessing and managing OpenIDM repository and its functions<\/p>\n<span id=\"Configuration_Options\"><h2>Configuration Options<\/h2><\/span>\n<span id=\"Configuration_Objects\"><h3>Configuration Objects<\/h3><\/span>\n<p>* Exposed as JSON objects<br \/>\n* Can be either single instance (one per installation) or multiple instances (more than one per installation)<\/p>\n<span id=\"Single_Instance_Configuration_Objects\"><h4>Single Instance Configuration Objects<\/h4><\/span>\n<p>* <em>audit<\/em>: specifies how audit events are logged<br \/>\n* <em>authentication<\/em>: controls REST access<br \/>\n* <em>managed<\/em>: defines managed objects and their schemas<br \/>\n* <em>repo.repo-type<\/em>: configures internal repository, e.g. <em>repo.orientd<\/em>b or <em>repo.jdbc<\/em><br \/>\n* <em>router<\/em>: specifies filters for specific operations<br \/>\n* <em>sync<\/em>: defines all sync and reconciliation mappings<\/p>\n<span id=\"Multiple_Instance_Configuration_Objects\"><h4>Multiple Instance Configuration Objects<\/h4><\/span>\n<p>* Naming: <em>objectname\/instancename<\/em>, e.g. <em>provisioner.openicf\/xml<\/em><br \/>\n* JSON file views are named: <em>objectname-instancename.json<\/em>, e.g. <em>provisioner.openicf-xml.json<\/em><\/p>\n<span id=\"Configuration_Over_REST\"><h3>Configuration Over REST<\/h3><\/span>\n<p>* Configuration objects are exposed under <em>\/openidm\/config<\/em> context<br \/>\n* Single instance objects are under <em>\/openidm\/config\/objectname<\/em> context<br \/>\n* Multiple instance objects are under <em>\/openidm\/config\/objectname\/instancename<\/em> context<\/p>\n<pre lang=\"bash\">\r\n# List all configuration objects:\r\ncurl --request GET \\\r\n --header \"X-OpenIDM-Username: openidm-admin\" \\\r\n --header \"X-OpenIDM-Password: openidm-admin\" http:\/\/localhost:8080\/openidm\/config\r\n\r\n# List single instance audit configuration object:\r\ncurl \\\r\n --header \"X-OpenIDM-Username: openidm-admin\" \\\r\n --header \"X-OpenIDM-Password: openidm-admin\" http:\/\/localhost:8080\/openidm\/config\/audit\r\n\r\n# List multiple instance configuration object:\r\ncurl \\\r\n --header \"X-OpenIDM-Username: openidm-admin\" \\\r\n --header \"X-OpenIDM-Password: openidm-admin\" http:\/\/localhost:8080\/openidm\/config\/provisioner.openicf\/xml\r\n<\/pre>\n<span id=\"Property_Substitution_in_Configuration\"><h3>Property Substitution in Configuration<\/h3><\/span>\n<p>* Define properties in <em>conf\/boot.properties<\/em>. For example:<\/p>\n<pre lang=\"bash\">\r\nPROD.location=production\r\nDEV.location=development\r\n<\/pre>\n<p>* Use Property in configuration files with &#038;{} construct. For example, repo.orientdb.json:<\/p>\n<pre lang=\"bash\">\r\n{\r\n\"dbUrl\" : \"local:.\/db\/&{&{environment}.location}-openidm\",\r\n\"user\" : \"admin\",\r\n\"poolMinSize\" : 5,\r\n\"poolMaxSize\" : 20,\r\n...\r\n}\r\n<\/pre>\n<p>* Property &#8220;environment&#8221; is further defined in environment variables:<\/p>\n<pre lang=\"bash\">\r\n# For DEV environment:\r\nexport OPENIDM_OPTS=\"-Xmx1024m -Denvironment=PROD\"\r\n.\/startup.sh\r\n\r\n# For PROD environment:\r\nexport OPENIDM_OPTS=\"-Xmx1024m -Denvironment=DEV\"\r\n.\/startup.sh\r\n<\/pre>\n<p>* Java system properties can also be used. For example:<\/p>\n<pre lang=\"bash\">\r\n{\r\n    \"logTo\" : [\r\n        {\r\n            \"logType\" : \"csv\",\r\n            \"location\" : \"&{user.home}\/audit\",\r\n            \"recordDelimiter\" : \";\"\r\n        }\r\n    ]\r\n}\r\n<\/pre>\n<p>* Also supports nested properties<br \/>\n* Does <strong>not<\/strong> support encrypted values at this time<\/p>\n<span id=\"Configure_Server_Logs\"><h2>Configure Server Logs<\/h2><\/span>\n<p>* Server logging can be configured in <em>openidm\/conf\/logging.properties<\/em><br \/>\n* Logging levels<\/p>\n<pre lang=\"bash\">\r\nSEVERE\r\nWARNING\r\nINFO\r\nCONFIG\r\nFINE\r\nFINER\r\nFINEST\r\n<\/pre>\n<p>* Set logging level in individual script:<\/p>\n<pre lang=\"bash\">\r\norg.forgerock.openidm.script.javascript.JavaScript.level=level\r\n<\/pre>\n<p>* Override log level defined in individual script:<\/p>\n<pre lang=\"bash\">\r\norg.forgerock.openidm.script.javascript.JavaScript.script-name.level=level\r\n<\/pre>\n<span id=\"Connect_to_External_Resources\"><h2>Connect to External Resources<\/h2><\/span>\n<p>* Resources are<br \/>\n&#8211; external systems<br \/>\n&#8211; databases<br \/>\n&#8211; directory servers<br \/>\n&#8211; other sources of identity data<br \/>\nto be managed and audited by an idM<br \/>\n* OpenIDM connects to external resources through <em>OpenICF<\/em> which can be either standalone or embedded<br \/>\n* Connectors are configured through files named <em>openidm\/conf\/provisioner.openicf-connectorname<\/em><br \/>\n* Sample connectors are located in <em>openidm\/samples\/provisioners<\/em> directory (copy them to conf directory to use)<\/p>\n<span id=\"_1\"><h6><a href=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_OpenICF.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_OpenICF-300x222.jpg\" alt=\"\" title=\"OpenIDM_IntGuide_OpenICF\" width=\"300\" height=\"222\" class=\"aligncenter size-medium wp-image-5991\" srcset=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_OpenICF-300x222.jpg 300w, https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_OpenICF.jpg 644w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/h6><\/span>\n<span id=\"Accessing_Remote_Connectors\"><h3>Accessing Remote Connectors<\/h3><\/span>\n<p>* Configure remote connectors in <em>conf\/provisioner.openicf.connectorinfoprovider.json<\/em><br \/>\n* See sample file in <em>conf\/provisioner<\/em> directory<\/p>\n<pre lang=\"bash\">\r\ncat provisioner.openicf.connectorinfoprovider.jsn \r\n{\r\n   \"connectorsLocation\" : \"connectors\",\r\n   \"remoteConnectorServers\" :\r\n      [\r\n         {\r\n            \"name\" : \"dotnet\",\r\n            \"host\" : \"127.0.0.1\",\r\n            \"port\" : 8759,\r\n            \"useSSL\" : false,\r\n            \"timeout\" : 0,\r\n            \"key\" : \"Passw0rd\"\r\n         }\r\n      ]\r\n}\r\n<\/pre>\n<span id=\"Configure_Connectors\"><h3>Configure Connectors<\/h3><\/span>\n<p>* Via OpenICF provisioner service<br \/>\n* Each connector configuration is stored in a file in the <em>conf<\/em> directory named <em>provisioner.openicf-connectorname<\/em><\/p>\n<span id=\"Connector_Configuration_Examples\"><h3>Connector Configuration Examples<\/h3><\/span>\n<span id=\"Configuring_Synchronization\"><h2>Configuring Synchronization<\/h2><\/span>\n<span id=\"Types_of_Synchronization\"><h3>Types of Synchronization<\/h3><\/span>\n<p>* Synchronization happens when<br \/>\n&#8211; OpenIDM receives a change directly: OpenIDM pushes changes immediately to all external resources<br \/>\n&#8211; OpenIDM discovers a change on an external resource: through reconciliation and LiveSync<\/p>\n<span id=\"Reconciliation\"><h4>Reconciliation<\/h4><\/span>\n<p>* Bidirectional synchronization of objects (mainly user objects) between different data stores<br \/>\n* Thorough and heavy weight<br \/>\n* Good for compliance and reports<\/p>\n<span id=\"LiveSync\"><h4>LiveSync<\/h4><\/span>\n<p>* Relies on change log on the external resource (e.g. OpenDJ and AD) to determine which object has changed<br \/>\n* Light weight<br \/>\n* Might miss some changes<\/p>\n<span id=\"Flexible_Data_Model\"><h3>Flexible Data Model<\/h3><\/span>\n<span id=\"Basic_Data_Flow_Configuration\"><h3>Basic Data Flow Configuration<\/h3><\/span>\n<p>* Elements involved:<br \/>\n&#8211; Three types of configuration files<br \/>\n&#8211; A link table that OpenIDM maintains in its repository<br \/>\n&#8211; Scripts to check objects and manipulate attributes<\/p>\n<span id=\"Connector_Configuration_Files\"><h4>Connector Configuration Files<\/h4><\/span>\n<p>* Maps external resource objects to OpenIDM objects<br \/>\n* Lives in <em>conf<\/em> directory<br \/>\n* Naming convention is <em>provisioner.resource-name.json<\/em>, e.g. provisioner.openicf-xml.json<br \/>\n* Mapping naming conventions:<br \/>\n&#8211; <em>nativeName<\/em>: external attribute name<br \/>\n&#8211; <em>nativeType<\/em>: external attribute type<\/p>\n<pre lang=\"json\">\r\n{\r\n    \"name\": \"MyLDAP\",\r\n    \"objectTypes\": {\r\n        \"account\": {\r\n            \"lastName\": {\r\n                \"type\": \"string\",\r\n                \"required\": true,\r\n                \"nativeName\": \"sn\",\r\n                \"nativeType\": \"string\"\r\n            },\r\n            \"homePhone\": {\r\n                \"type\": \"array\",\r\n                \"items\": {\r\n                    \"type\": \"string\",\r\n                    \"nativeType\": \"string\"\r\n                },\r\n                \"nativeName\": \"homePhone\",\r\n                \"nativeType\": \"string\"\r\n            }\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<span id=\"Synchronization_Mappings_File\"><h4>Synchronization Mappings File<\/h4><\/span>\n<p>* Single file: <em>conf\/sync.json<\/em><br \/>\n* Describes a set of mappings<br \/>\n&#8211; Each mapping specifies attribute mapping from source to target objects (i.e. directional from source to target)<br \/>\n&#8211; External objects are identified as <em>system\/name\/object-type<\/em><br \/>\n* By default, synchronize all objects matching those defined in the connector config file for the resource<br \/>\n* Can also do<br \/>\n&#8211; creating new attribute<br \/>\n&#8211; conditional sync<br \/>\n&#8211; transformation<\/p>\n<pre lang=\"json\">\r\n{\r\n    \"mappings\": [\r\n        {\r\n            \"name\": \"systemLdapAccounts_managedUser\",\r\n            \"source\": \"system\/MyLDAP\/account\",\r\n            \"target\": \"managed\/user\",\r\n            \"properties\": [\r\n                {\r\n                    \"target\": \"familyName\",\r\n                    \"source\": \"lastName\"\r\n                },\r\n                {\r\n                    \"target\": \"homePhone\",\r\n                    \"source\": \"homePhone\"\r\n                },\r\n                \/* Creates a new attribute on the target name phoneExtension with default value of 0047 *\/\r\n                {\r\n                    \"target\": \"phoneExtension\",\r\n                    \"default\": \"0047\"\r\n                },\r\n                \/* Sync conditionally (only if source email is not null) *\/\r\n                {\r\n                    \"target\": \"mail\",\r\n                    \"comment\": \"Set mail if non-empty.\",\r\n                    \"source\": \"email\",\r\n                    \"condition\": {\r\n                        \"type\": \"text\/javascript\",\r\n                        \"source\": \"(source.email != null)\"\r\n                    }\r\n                },\r\n                \/* Create a new target attribute named displayName *\/\r\n                {\r\n                    \"target\": \"displayName\",\r\n                    \"source\": \"\";\r\n                    \"transform\": {\r\n                        \"type\": \"text\/javascript\",\r\n                        \"source\": \"(source.lastName +', ' + source.firstName;)\"\r\n                    }\r\n                }\r\n            ]\r\n        }\r\n    ]\r\n}\r\n<\/pre>\n<p>* Filters to determine if source of target is valid to be mapped<br \/>\n&#8211; validSource<\/p>\n<pre lang=\"json\">\r\n{\r\n    \"validSource\": {\r\n        \"type\": \"text\/javascript\",\r\n        \"source\": \"source.ldapPassword != null\"\r\n    }\r\n}\r\n<\/pre>\n<p>&#8211; validTarget<\/p>\n<pre lang=\"json\">\r\n{\r\n    \"validTarget\": {\r\n        \"type\": \"text\/javascript\",\r\n        \"source\": \"target.employeeType == 'internal'\"\r\n    }\r\n}\r\n<\/pre>\n<span id=\"_2\"><h3><\/h3><\/span>\n<span id=\"_3\"><h4><\/h4><\/span>\n<span id=\"_4\"><h3><\/h3><\/span>\n<span id=\"_5\"><h3><\/h3><\/span>\n<span id=\"Scheduling_Synchronization\"><h2>Scheduling Synchronization<\/h2><\/span>\n<span id=\"Managing_Passwords\"><h2>Managing Passwords<\/h2><\/span>\n<span id=\"Enforcing_Password_Policies\"><h3>Enforcing Password Policies<\/h3><\/span>\n<p>* By applying validation rules to attributes of managed user objects<br \/>\n* For example, to exclude the use of password strings: &#8216;password&#8217;,&#8217;123456&#8242;,&#8217;12345678&#8242;, &#8216;qwerty&#8217;, &#8216;abc123&#8217;:<br \/>\n&#8211; In <em>conf\/managed.json<\/em> file:<\/p>\n<pre lang=\"bash\">\r\n{\r\n    \"objects\" : [\r\n        {\r\n            \"name\" : \"user\",\r\n            \"properties\" : [\r\n                {\r\n                    \"name\" : \"password\",\r\n                    \"encryption\" : {\r\n                        \"key\" : \"openidm-sym-default\"\r\n                    }\r\n                }\r\n            ],\r\n            \"onValidate\" : {\r\n                \"type\" : \"text\/javascript\",\r\n                \"file\" : \"script\/password-validator.js\"\r\n            }\r\n        }\r\n    ]\r\n}\r\n<\/pre>\n<p>&#8211; Password validation file (<em>script\/password-validator.js<\/em>)<\/p>\n<pre lang=\"bash\">\r\nconst dictionary = ['password','123456','12345678', 'qwerty', 'abc123'];\r\n \r\nfunction isValidPassword() {\r\n    var cleartextObject = openidm.decrypt(object);\r\n    for (var i = 0; i < dictionary.length; i++) {\r\n        if (cleartextObject.password == dictionary[i]) {\r\n            throw \"Password Policy Violation Exception\";\r\n        };\r\n    };\r\n};\r\n \r\nisValidPassword();\r\n<\/pre>\n<span id=\"Password_Synchronization\"><h3>Password Synchronization<\/h3><\/span>\n<span id=\"Managing_Authentication_Authorization__RBAC\"><h2>Managing Authentication, Authorization & RBAC<\/h2><\/span>\n<span id=\"OpenIDM_Users\"><h3>OpenIDM Users<\/h3><\/span>\n<span id=\"Internal_Users\"><h4>Internal Users<\/h4><\/span>\n<p>* <em>anonymous<\/em>: for self registration. Default password is <em>anonymous<\/em><br \/>\n* <em>openidm-admin<\/em>: super user. Default password is <em>openidm-admin<\/em><\/p>\n<span id=\"Managed_Users\"><h4>Managed Users<\/h4><\/span>\n<p>* Users managed by OpenIDM<\/p>\n<span id=\"Authentication\"><h2>Authentication<\/h2><\/span>\n<span id=\"Default_Attributes\"><h3>Default Attributes<\/h3><\/span>\n<p>* login: email<br \/>\n* password: password<br \/>\n* Default attributes are defined in <em>conf\/repo.repotype.json<\/em> file, e.g. <em>repo.orientdb.json<\/em><br \/>\n- credential-internaluser-query<br \/>\n- credential-query<\/p>\n<pre lang=\"bash\">\r\n        \"credential-query\" : \"SELECT * FROM ${_resource} WHERE userName = '${username}'\",\r\n        \"credential-internaluser-query\" : \"SELECT * FROM internal_user WHERE _openidm_id = ${username}\",\r\n<\/pre>\n<p>* Authentication file <em>conf\/authentication.json<\/em> defines currently active query <\/p>\n<pre lang=\"bash\">\r\ncat authentication.json \r\n{\r\n    \"queryId\" : \"credential-query\",\r\n    \"queryOnResource\" : \"managed\/user\",\r\n    \"propertyMapping\" : {\r\n        \"userId\" : \"_id\",\r\n        \"userCredential\" : \"password\",\r\n        \"userRoles\" : \"roles\"\r\n    },\r\n    \"defaultUserRoles\" : [ ]\r\n}\r\n<\/pre>\n<span id=\"Authentication_1\"><h3>Authentication<\/h3><\/span>\n<p>* With standard header fields:<\/p>\n<pre lang=\"bash\">\r\ncurl --user userName:password\r\n<\/pre>\n<p>* With OpenIDM header fields:<\/p>\n<pre lang=\"bash\">\r\ncurl\r\n --header \"X-OpenIDM-Username: openidm-admin\"\r\n --header \"X-OpenIDM-Password: openidm-admin\"\r\n<\/pre>\n<span id=\"Roles\"><h3>Roles<\/h3><\/span>\n<p>* openidm-reg: anonymous user<br \/>\n* openidm-admin: super user<br \/>\n* openidm-authorized: authenticated users.<br \/>\n- Configured by <em>defaultUserRoles<\/em> property in the <em>conf\/authentication.json<\/em> file:<\/p>\n<pre lang=\"bash\">\r\ncat authentication.json \r\n{\r\n    \"queryId\" : \"credential-query\",\r\n    \"queryOnResource\" : \"managed\/user\",\r\n    \"propertyMapping\" : {\r\n        \"userId\" : \"_id\",\r\n        \"userCredential\" : \"password\",\r\n        \"userRoles\" : \"roles\"\r\n    },\r\n    \"defaultUserRoles\" : [ ]\r\n}\r\n<\/pre>\n<p>* openidm-cert: authenticated by mutual SSL authentication<\/p>\n<span id=\"Authorization\"><h3>Authorization<\/h3><\/span>\n<p>* Based on REST interface URLs<br \/>\n* Defined in <em>script\/router-authz.js<\/em> file<br \/>\n- Return <em>\"Access denied\"<\/em> to deny access:<\/p>\n<pre lang=\"bash\">\r\nif (!allow()) {\r\n    throw \"Access denied\";\r\n}\r\n<\/pre>\n<span id=\"Securing__Hardening_OpenIDM\"><h2>Securing & Hardening OpenIDM<\/h2><\/span>\n<p>TODO<\/p>\n<span id=\"Integrating_Business_Processes__Workflows\"><h2>Integrating Business Processes & Workflows<\/h2><\/span>\n<p>* Two modes of integration<br \/>\n- Local integration: Activiti is embedded in OpenIDM OSGI container<br \/>\n- Remote integration: Standalone Activiti engine<\/p>\n<span id=\"Remote_Integration\"><h3>Remote Integration<\/h3><\/span>\n<span id=\"Checkout_Trunk\"><h4>Checkout Trunk<\/h4><\/span>\n<p>* Checkout OpenIDM trunk from SVN URL: <em>https:\/\/svn.forgerock.org\/openidm\/trunk<\/em><\/p>\n<span id=\"_6\"><h6><a href=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_Checkout_Src.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_Checkout_Src-300x253.jpg\" alt=\"\" title=\"OpenIDM_Checkout_Src\" width=\"300\" height=\"253\" class=\"aligncenter size-medium wp-image-5997\" srcset=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_Checkout_Src-300x253.jpg 300w, https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_Checkout_Src.jpg 538w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/h6><\/span>\n<span id=\"Compile_and_Package_Source_Codes\"><h4>Compile and Package Source Codes<\/h4><\/span>\n<p>* Install Maven 3 if not already done<br \/>\n* Run Maven command:<\/p>\n<pre lang=\"bash\">\r\nmvn package\r\n<\/pre>\n<span id=\"Install_OpenIDM\"><h4>Install OpenIDM<\/h4><\/span>\n<p>* Copy <em>openidm-zip\/target\/openidm-2.1.0-SNAPSHOT<\/em> to target machine<br \/>\n* Unzip<\/p>\n<span id=\"Install_Activiti\"><h4>Install Activiti<\/h4><\/span>\n<p>* Download and unzip <em>activiti-5.10.zip<\/em><br \/>\n* Change Activiti listening port from <em>8080<\/em> to <em>9090<\/em><br \/>\n- Edit setup\/build.xml and do a global replacement of 8080 to 9090 with vi command: <em>:%s\/8080\/9090\/g<\/em><br \/>\n* Start Activiti demo app:<\/p>\n<pre lang=\"bash\">\r\nant demo.start\r\n<\/pre>\n<p>* Access Activiti Explorer from URL: <a href=\"http:\/\/localhost:9090\/activiti-explorer\">http:\/\/localhost:9090\/activiti-explorer<\/a><\/p>\n<span id=\"Deploy_OpenIDM_Workflow_to_Activiti_Tomcat\"><h4>Deploy OpenIDM Workflow to Activiti Tomcat<\/h4><\/span>\n<p>* Stop Tomcat<\/p>\n<pre lang=\"bash\">\r\nant tomcat.stop\r\n<\/pre>\n<p>* Deploy openidm-workflow-remote web app to Tomcat by copying <em>openidm-workflow-remote\/target\/openidm-workflow-remote-2.1.0-SNAPSHOT.war<\/em> to Tomcat <em>webapps<\/em> directory:<\/p>\n<pre lang=\"bash\">\r\n$ cd \/opt\/openidm\/builtFromSrc\/activiti-5.10\/apps\/apache-tomcat-6.0.32\/webapps\r\n$ pwd\r\n\/opt\/openidm\/builtFromSrc\/activiti-5.10\/apps\/apache-tomcat-6.0.32\/webapps\r\n$ ls\r\nactiviti-explorer  activiti-rest  docs  examples  host-manager  manager  ROOT\r\n$ cp \/mnt\/hgfs\/vmshare\/src\/openidm-workflow-remote-2.1.0-SNAPSHOT.war .\r\n<\/pre>\n<p>* Deploy openidm workflow activiti jar file to activiti-explorer web app's WEB-INF\/lib directory<\/p>\n<pre lang=\"bash\">\r\n$ cd \/opt\/openidm\/builtFromSrc\/activiti-5.10\/apps\/apache-tomcat-6.0.32\/webapps\/activiti-explorer\/WEB-INF\/lib\r\n$ pwd\r\n\/opt\/openidm\/builtFromSrc\/activiti-5.10\/apps\/apache-tomcat-6.0.32\/webapps\/activiti-explorer\/WEB-INF\/lib\r\n$ cp \/mnt\/hgfs\/vmshare\/src\/openidm-workflow-activiti-2.1.0-SNAPSHOT-jar-with-dependencies.jar .\r\n<\/pre>\n<p>* Edit Activiti Explorer config file to be able to use OpenIDM extenstions <\/p>\n<pre lang=\"bash\">\r\n$ cd \/opt\/openidm\/builtFromSrc\/activiti-5.10\/apps\/apache-tomcat-6.0.32\/webapps\/activiti-explorer\/WEB-INF\r\n$ pwd\r\n\/opt\/openidm\/builtFromSrc\/activiti-5.10\/apps\/apache-tomcat-6.0.32\/webapps\/activiti-explorer\/WEB-INF\r\n$ ls\r\nactiviti-ui-context.xml  applicationContext.xml  classes  lib  web.xml\r\n$ vi applicationContext.xml \r\n<\/pre>\n<p>- Replace<\/p>\n<pre lang=\"xml\">\r\n<bean id=\"processEngineConfiguration\" class=\"org.activiti.spring.SpringProcessEngineConfiguration\">\r\n <property name=\"dataSource\" ref=\"dataSource\" \/>\r\n <property name=\"transactionManager\" ref=\"transactionManager\" \/>\r\n <property name=\"databaseSchemaUpdate\" value=\"true\" \/>\r\n <property name=\"jobExecutorActivate\" value=\"true\" \/>\r\n <property name=\"customFormTypes\">\r\n  <list>\r\n   <ref bean=\"userFormType\"\/>\r\n  <\/list>\r\n <\/property>\r\n<\/bean>\r\n<\/pre>\n<p>with<\/p>\n<pre lang=\"xml\">\r\n<bean id=\"processEngineConfiguration\" class=\"org.activiti.spring.SpringProcessEngineConfiguration\">\r\n  <property name=\"mailServerHost\" value=\"mail.my.com\" \/> \r\n  <property name=\"mailServerPort\" value=\"26\" \/>    \r\n  <property name=\"mailServerUsername\" value=\"me@my.com\" \/> \r\n  <property name=\"mailServerPassword\" value=\"secret1\" \/>    \r\n  <property name=\"mailServerDefaultFrom\" value=\"activiti@my.com\" \/> \r\n  <property name=\"dataSource\" ref=\"dataSource\" \/>\r\n  <property name=\"transactionManager\" ref=\"transactionManager\" \/>\r\n  <property name=\"databaseSchemaUpdate\" value=\"true\" \/>\r\n  <property name=\"jobExecutorActivate\" value=\"true\" \/>\r\n  <property name=\"customFormTypes\">\r\n  <list>\r\n       <ref bean=\"userFormType\"\/>\r\n      <\/list>\r\n     <\/property>\r\n  <property name=\"customSessionFactories\">\r\n  <list>\r\n       <bean class=\"org.forgerock.openidm.workflow.activiti.impl.session.OpenIDMSessionFactory\">\r\n  <property name=\"url\" value=\"http:\/\/localhost:8080\/openidm\/\"\/>\r\n  <property name=\"user\" value=\"openidm-admin\"\/>\r\n  <property name=\"password\" value=\"openidm-admin\"\/>\r\n       <\/bean>\r\n     <\/list>\r\n   <\/property>\r\n  <property name=\"resolverFactories\">\r\n  <list>\r\n       <bean class=\"org.forgerock.openidm.workflow.activiti.impl.OpenIDMResolverFactory\"><\/bean>\r\n       <bean class=\"org.activiti.engine.impl.scripting.VariableScopeResolverFactory\"><\/bean>\r\n       <bean class=\"org.activiti.engine.impl.scripting.BeansResolverFactory\"><\/bean>\r\n     <\/list>\r\n   <\/property>\r\n  <property name=\"expressionManager\">\r\n     <bean class=\"org.forgerock.openidm.workflow.activiti.impl.OpenIDMExpressionManager\"> <\/bean>\r\n   <\/property>\r\n<\/bean>\r\n<\/pre>\n<p>* Restart Activiti Demo:<\/p>\n<pre lang=\"bash\">\r\ncd $ACTIVITI_HOME\/setup\r\nant demo.stop\r\nant demo.start\r\n<\/pre>\n<p>* Check that Activiti Explorer is accessible.<\/p>\n<span id=\"Configure_OpenIDM_to_use_Remote_Activiti\"><h4>Configure OpenIDM to use Remote Activiti<\/h4><\/span>\n<p>* Copy sample <em>workflow.json<\/em> file to <em>conf<\/em> directory if none exists:<\/p>\n<pre lang=\"bash\">\r\ncd $OPENIDM_HOME\r\ncp samples\/misc\/workflow.json conf\/\r\n<\/pre>\n<p>* Edit workflow.json file to point to remote Activiti instance with correct username and password (i.e. <em>kermit<\/em>\/<em>kermit<\/em>)<\/p>\n<pre lang=\"bash\">\r\n{\r\n    \"enabled\" : true,\r\n    \"location\" : \"remote\",\r\n    \"engine\" : {\r\n        \"url\" : \"http:\/\/localhost:9090\/openidm-workflow-remote-2.1.0-SNAPSHOT\/\",\r\n        \"username\" : \"kermit\",\r\n        \"password\" : \"kermit\"\r\n    },\r\n<\/pre>\n<p>* Start OpenIDM<\/p>\n<pre lang=\"bash\">\r\ncd $OPENIDM_HOME\r\n.\/startup.sh\r\n<\/pre>\n<p>* Test integration:<\/p>\n<pre lang=\"bash\">\r\ncurl \\\r\n  --header \"X-OpenIDM-Username: openidm-admin\" \\\r\n  --header \"X-OpenIDM-Password: openidm-admin\" \\\r\n  --request GET \"http:\/\/localhost:8080\/openidm\/workflow\"\r\n\r\n{\"result\":[{\"name\":\"Vacation request\",\"processDefinitionId\":\"vacationRequest:1:21\",\"key\":\"vacationRequest\"},{\"name\":\"Helpdesk process\",\"processDefinitionId\":\"escalationExample:1:22\",\"key\":\"escalationExample\"},{\"name\":\"Review sales lead\",\"processDefinitionId\":\"reviewSaledLead:1:23\",\"key\":\"reviewSaledLead\"},{\"name\":\"Fix system failure\",\"processDefinitionId\":\"fixSystemFailure:1:24\",\"key\":\"fixSystemFailure\"},{\"name\":\"Expense process\",\"processDefinitionId\":\"adhoc_Expense_process:1:25\",\"key\":\"adhoc_Expense_process\"}]}\r\n<\/pre>\n<span id=\"Install_the_sample_workflow_example.bpmn20.xml_from_the_openidm-workflow-activiti_project\"><h4>Install the sample workflow (example.bpmn20.xml) from the openidm-workflow-activiti project<\/h4><\/span>\n<p>* Login remote Activiti Explorer as kermit\/kermit<br \/>\n* Select <em>Manage > Deployment > Upload New<\/em> <\/p>\n<span id=\"_7\"><h6><a href=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_ActExp_UploadNew1.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_ActExp_UploadNew1-300x69.jpg\" alt=\"\" title=\"OpenIDM_IntGuide_ActExp_UploadNew1\" width=\"300\" height=\"69\" class=\"aligncenter size-medium wp-image-6000\" srcset=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_ActExp_UploadNew1-300x69.jpg 300w, https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_ActExp_UploadNew1.jpg 584w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/h6><\/span>\n<p>* Browse to file <em>openidm-workflow-activiti\/src\/main\/resources\/OSGI-INF\/activiti\/example.bpmn20.xml<\/em><br \/>\n* Start <em>osgiProcess<\/em> from REST API:<\/p>\n<pre lang=\"bash\">\r\ncurl \\\r\n\t--header \"X-OpenIDM-Username: openidm-admin\" \\\r\n\t--header \"X-OpenIDM-Password: openidm-admin\" \\\r\n\t--request POST \"http:\/\/localhost:8080\/openidm\/workflow\/processinstance?_action=createProcessInstance\" \\\r\n\t--data '{ \"key\":\"osgiProcess\" }'\r\n\r\n{\"_id\":\"1010\",\"processInstanceId\":\"1010\",\"status\":\"ended\",\"businessKey\":null,\"processDefinitionId\":\"osgiProcess:1:915\"}\r\n<\/pre>\n<p>- Also check Activiti Tomcat catalina.out for osgiProcess related outputs:<\/p>\n<pre lang=\"bash\">\r\n$ pwd\r\n\/opt\/openidm\/builtFromSrc\/activiti-5.10\/apps\/apache-tomcat-6.0.32\/logs\r\n$ vi catalina.out\t\r\n\r\nscript task using expression resolver: [result:[[name:Vacation request, processDefinitionId:vacationRequest:1:21, key:vacationRequest], [name:Helpdesk process, processDefinitionId:escalationExample:1:22, key:escalationExample], [name:Review sales lead, processDefinitionId:reviewSaledLead:1:23, key:reviewSaledLead], [name:Fix system failure, processDefinitionId:fixSystemFailure:1:24, key:fixSystemFailure], [name:Expense process, processDefinitionId:adhoc_Expense_process:1:25, key:adhoc_Expense_process], [name:Osgi process, processDefinitionId:osgiProcess:1:915, key:osgiProcess]]]\r\n<\/pre>\n<p>* Alternatively, start <em>osgiProcess<\/em> from Activiti Explorer:<\/p>\n<span id=\"_8\"><h6><a href=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_ActExp_StartProc1.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_ActExp_StartProc1-300x91.jpg\" alt=\"\" title=\"OpenIDM_IntGuide_ActExp_StartProc1\" width=\"300\" height=\"91\" class=\"aligncenter size-medium wp-image-6001\" srcset=\"https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_ActExp_StartProc1-300x91.jpg 300w, https:\/\/jianmingli.com\/wp\/wp-content\/uploads\/2012\/09\/OpenIDM_IntGuide_ActExp_StartProc1.jpg 995w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/h6><\/span>\n<p>- Check Activiti Tomcat catalina.out for osgiProcess related outputs:<\/p>\n<pre lang=\"bash\">\r\nSep 18, 2012 1:07:26 PM org.restlet.engine.log.LogFilter afterHandle\r\nINFO: 2012-09-18\t13:07:26\t127.0.0.1\tkermit\t127.0.0.1\t9090\tGET\t\/openidm-workflow-remote-2.1.0-SNAPSHOT\/\t-\t200\t-0\t8\thttp:\/\/localhost:9090\tRestlet-Framework\/2.0.15\t-\r\nscript task using expression resolver: [result:[[name:Vacation request, processDefinitionId:vacationRequest:1:21, key:vacationRequest], [name:Helpdesk process, processDefinitionId:escalationExample:1:22, key:escalationExample], [name:Review sales lead, processDefinitionId:reviewSaledLead:1:23, key:reviewSaledLead], [name:Fix system failure, processDefinitionId:fixSystemFailure:1:24, key:fixSystemFailure], [name:Expense process, processDefinitionId:adhoc_Expense_process:1:25, key:adhoc_Expense_process], [name:Osgi process, processDefinitionId:osgiProcess:1:915, key:osgiProcess]]]\r\nSep 18, 2012 1:07:26 PM org.restlet.engine.log.LogFilter afterHandle\r\nINFO: 2012-09-18\t13:07:26\t127.0.0.1\tkermit\t127.0.0.1\t9090\tGET\t\/openidm-workflow-remote-2.1.0-SNAPSHOT\/\t-\t200\t-0\t15\thttp:\/\/localhost:9090\tRestlet-Framework\/2.0.15\t-\r\nscript task using resolver: [result:[[name:Vacation request, processDefinitionId:vacationRequest:1:21, key:vacationRequest], [name:Helpdesk process, processDefinitionId:escalationExample:1:22, key:escalationExample], [name:Review sales lead, processDefinitionId:reviewSaledLead:1:23, key:reviewSaledLead], [name:Fix system failure, processDefinitionId:fixSystemFailure:1:24, key:fixSystemFailure], [name:Expense process, processDefinitionId:adhoc_Expense_process:1:25, key:adhoc_Expense_process], [name:Osgi process, processDefinitionId:osgiProcess:1:915, key:osgiProcess]]]\r\n<\/pre>\n<span id=\"Local_Activiti_Integration\"><h3>Local Activiti Integration<\/h3><\/span>\n<p>* Local Activiti integration is included in the standard OpenIDM 2.1 build <strong>without<\/strong> Activiti Explorer.<br \/>\n* To access Activiti Explorer with Local Activiti Engine, see <a href=\"?p=6156\">this post<\/a>.<br \/>\n* To use Single User Store for both OpenIDM and Activiti, see <a href=\"https:\/\/jianmingli.com\/wp\/?p=6156#Configure_OpenIDM_and_Activiti_to_Share_the_Same_User_Store\">this post<\/a>.<\/p>\n<span id=\"Configure_Activiti_Engine\"><h3>Configure Activiti Engine<\/h3><\/span>\n<p>* Configured in <em>conf\/workflow.json<\/em> file:<br \/>\n- For local embedded Activiti engine:<\/p>\n<pre lang=\"bash\">\r\ncat workflow.json \r\n{\r\n    \"enabled\" : true\r\n}\r\n<\/pre>\n<p>- For remote standalonoe Activiti instance:<\/p>\n<pre lang=\"bash\">\r\n{\r\n    \"enabled\" : true,\r\n    \"location\" : \"remote\",\r\n    \"engine\" : {\r\n        \"url\" : \"http:\/\/localhost:9090\/openidm-workflow-remote-2.1.0-SNAPSHOT\/\",\r\n        \"username\" : \"kermit\",\r\n        \"password\" : \"kermit\"\r\n    },\r\n<\/pre>\n<span id=\"Define_Activiti_Workflows\"><h3>Define Activiti Workflows<\/h3><\/span>\n<p>* Define BPMN 2.0 work flow file (with text editor or BPMN 2.0 editor)<br \/>\n* Package as a <em>.bar<\/em> file<br \/>\n* Copy bar file to <em>workflow<\/em> directory<br \/>\n* Invoke workflow using a script<br \/>\n* Optionally schedule workflow <\/p>\n<span id=\"Invoking_Activiti_Workflows\"><h3>Invoking Activiti Workflows<\/h3><\/span>\n<p>* From any trigger point within OpenIDM<br \/>\n* From script files using <em>openidm.action()<\/em> function<\/p>\n<pre lang=\"javascript\">\r\n\/*\r\n * Calling 'myWorkflow' workflow\r\n *\/\r\nvar workflow = {   \r\n \"_action\" : \"myWorkflow\"\r\n};\r\n  \r\nvar params = {\r\n \"foo\" : \"bar\"\r\n};\r\n \r\nopenidm.action(\"workflow\/activiti\", workflow, params);\r\n<\/pre>\n<p>* Directly from REST interface<\/p>\n<pre lang=\"bash\">\r\ncurl --header \"X-OpenIDM-Username: openidm-admin\" \\\r\n  --header \"X-OpenIDM-Password: openidm-admin\" \\\r\n  --data '{\"foo\":\"bar\"}' \\\r\n  --request POST \"http:\/\/localhost:8080\/openidm\/workflow?_action=myWorkflow\"\r\n<\/pre>\n<span id=\"Email_Notification_Example\"><h3>Email Notification Example<\/h3><\/span>\n<p>* Create EmailNotification.bpmn file<br \/>\n* Package as .bar file<br \/>\n* Copy .bar file to workflow directory<br \/>\n* Invoke directly from REST<\/p>\n<pre lang=\"bash\">\r\ncurl \\\r\n\t--header \"X-OpenIDM-Username: openidm-admin\" \\\r\n\t--header \"X-OpenIDM-Password: openidm-admin\" \\\r\n\t--request POST \"http:\/\/localhost:8080\/openidm\/workflow\/processinstance?_action=createProcessInstance\" \\\r\n\t--data '{\"key\":\"EmailNotification\",\"fromSender\" : \"noreply@openidm\",\"toEmail\" : \"jdoe@example.com\"}'\r\n\r\n{\"_id\":\"208\",\"processInstanceId\":\"208\",\"status\":\"ended\",\"businessKey\":null,\"processDefinitionId\":\"EmailNotification:1:207\"}\r\n<\/pre>\n<span id=\"Example_Sunset_Workflow_Triggered_By_Reconciliation\"><h3>Example Sunset Workflow Triggered By Reconciliation<\/h3><\/span>\n<p>* Authoritative data source: CSV file<\/p>\n<pre lang=\"bash\">\r\n\"firstName\",\"uid\",\"lastName\",\"email\",\"employeeNumber\",password,\"sunrise\",\"sunset\",\"active\"\r\n\"Darth\",\"DDOE\",\"Doe\",\"doe@example.com\",\"123456\",\"Z29vZA==\",\"2012-06-30T00:00:00Z\",\"2012-12-23T00:00:00Z\",\"TRUE\"\r\n<\/pre>\n<p>* Target data source: XML file<\/p>\n<pre lang=\"xml\">\r\n<\/pre>\n<p>* Scenario:<br \/>\nNew user in CSV -> Kicks of reconcile process -> Found new user -> Add to XML<\/p>\n<pre lang=\"bash\">\r\n<\/pre>\n<span id=\"Sending_Email\"><h2>Sending Email<\/h2><\/span>\n<span id=\"Setup_Outbound_Email\"><h3>Setup Outbound Email<\/h3><\/span>\n<p>* Shutdown OpenIDM<br \/>\n* Copy sample email config file to <em>conf<\/em> directory:<\/p>\n<pre lang=\"bash\">\r\ncd $OPENIDM_HOME\r\ncp samples\/misc\/external.email.json conf\/\r\n<\/pre>\n<p>* Modify email config file:<\/p>\n<pre lang=\"bash\">\r\n{\r\n        \"host\" : \"smtp.example.com\",\r\n        \"port\" : \"25\",\r\n        \"username\" : \"openidm\",\r\n        \"password\" : \"secret12\",\r\n        \"mail.smtp.auth\" : \"true\",\r\n        \"mail.smtp.starttls.enable\" : \"true\"\r\n}\r\n<\/pre>\n<p>* Restart OpenIDM<br \/>\n* Check external mail is up and running<\/p>\n<pre lang=\"bash\">\r\n-> scr list\r\n...\r\n[   6] [active       ] org.forgerock.openidm.external.email\r\n...\r\n<\/pre>\n<span id=\"Send_mail_from_REST\"><h3>Send mail from REST<\/h3><\/span>\n<pre lang=\"bash\">\r\ncurl \\\r\n --header \"X-OpenIDM-Username: openidm-admin\" \\\r\n --header \"X-OpenIDM-Password: openidm-admin\" \\\r\n --request POST \"http:\/\/localhost:8080\/openidm\/external\/email?_from=openidm@example.com&_to=user@example.com&_subject=Test&_body=Test\"\r\n\r\n{\"status\":\"OK\"}\r\n<\/pre>\n<span id=\"Sending_Mail_from_Script\"><h3>Sending Mail from Script<\/h3><\/span>\n<p>* Use <em>external\/email<\/em> context:<\/p>\n<pre lang=\"bash\">\r\nvar params =  new Object();\r\nparams._from = \"openidm@example.com\";\r\nparams._to = \"admin@example.com\";\r\nparams._cc = \"wally@example.com,dilbert@example.com\";\r\nparams._subject = \"OpenIDM recon report\";\r\nparams._type = \"text\/html\";\r\nparams._body = \"<html><body><p>Recon report follows...<\/p><\/body><\/html>\";\r\n \r\nopenidm.action(\"external\/email\", params);\r\n<\/pre>\n<span id=\"Errors\"><h2>Errors<\/h2><\/span>\n<span id=\"action_method_not_implemented_on_workflow\"><h3>action method not implemented on workflow<\/h3><\/span>\n<p>* Error message:<\/p>\n<pre lang=\"bash\">\r\ncurl \\\r\n  --header \"X-OpenIDM-Username: openidm-admin\" \\\r\n  --header \"X-OpenIDM-Password: openidm-admin\" \\\r\n  --request POST \"http:\/\/localhost:8080\/openidm\/workflow?_action=osgiProcess\"\r\n\r\ncurl \\\r\n>   --header \"X-OpenIDM-Username: openidm-admin\" \\\r\n>   --header \"X-OpenIDM-Password: openidm-admin\" \\\r\n>   --request POST \"http:\/\/localhost:8080\/openidm\/workflow?_action=osgiProcess\"\r\n{\"error\":400,\"reason\":\"Bad Request\",\"detail\":\"action method not implemented on workflow\"}\r\n<\/pre>\n<p>* Reason: OpenIDM\/Activiti REST interface has changed.<\/p>\n<span id=\"References\"><h2>References<\/h2><\/span>\n<p>* <a href=\"http:\/\/openidm.forgerock.org\/doc\/integrators-guide\/index\/index.html\">OpenIDM 2.1.0 Integrator's Guide<\/a><br \/>\n* <a href=\"http:\/\/docs.forgerock.org\/en\/index.html\">ForgeRock Documentation<\/a><br \/>\n* <a href=\"https:\/\/wikis.forgerock.org\/confluence\/display\/OPENIDM\/Home\">OpenIDM Wiki<\/a><br \/>\n* <a href=\"https:\/\/lists.forgerock.org\/mailman\/listinfo\/openidm\">Forum<\/a><br \/>\n* <a href=\"http:\/\/list-archives.org\/2012\/09\/07\/openidm-forgerock-org\/enhanced-rest-interface-for-the-activiti-integration\/f\/6528265267\">Enhanced REST interface for the Activiti integration<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Architectural Overview Modular Framework * OSGi (Felix) * Servlet (Jetty) Infrastructure Modules * Scheduler (Quartz) * Script engine (JavaScript) * Audit logging * Repository &#8211; MySQL for production use &#8211; OrientDB for evaluation use &#8211; Repository API is based on &hellip; <a href=\"https:\/\/jianmingli.com\/wp\/?p=5980\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[203],"tags":[248,204],"class_list":["post-5980","post","type-post","status-publish","format-standard","hentry","category-openidm","tag-integration","tag-openidm-2"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p8cRUO-1ys","_links":{"self":[{"href":"https:\/\/jianmingli.com\/wp\/index.php?rest_route=\/wp\/v2\/posts\/5980","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jianmingli.com\/wp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jianmingli.com\/wp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jianmingli.com\/wp\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jianmingli.com\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5980"}],"version-history":[{"count":17,"href":"https:\/\/jianmingli.com\/wp\/index.php?rest_route=\/wp\/v2\/posts\/5980\/revisions"}],"predecessor-version":[{"id":6243,"href":"https:\/\/jianmingli.com\/wp\/index.php?rest_route=\/wp\/v2\/posts\/5980\/revisions\/6243"}],"wp:attachment":[{"href":"https:\/\/jianmingli.com\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5980"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jianmingli.com\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5980"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jianmingli.com\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5980"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}