You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/04/04 09:10:09 UTC

[2/2] syncope git commit: [SYNCOPE-1292] Implementation provided

[SYNCOPE-1292] Implementation provided


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/f171ed2a
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/f171ed2a
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/f171ed2a

Branch: refs/heads/master
Commit: f171ed2aeb6de42a5f0f2430d073fe2d9fb0af16
Parents: a346bbf
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Wed Apr 4 10:29:29 2018 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Wed Apr 4 11:09:59 2018 +0200

----------------------------------------------------------------------
 .../test/resources/domains/MasterContent.xml    |   2 +-
 .../core/provisioning/api/MappingManager.java   |   2 +-
 .../provisioning/java/MappingManagerImpl.java   |  27 +++--
 .../AbstractPropagationTaskExecutor.java        |  71 ++++++------
 .../pushpull/AbstractPullResultHandler.java     |   6 +-
 .../pushpull/AbstractPushResultHandler.java     |  27 +++--
 .../pushpull/DefaultRealmPullResultHandler.java |   6 +-
 .../pushpull/DefaultRealmPushResultHandler.java |  31 +++---
 .../pushpull/LDAPMembershipPullActions.java     |   2 +-
 .../java/pushpull/PullJobDelegate.java          |   4 +-
 .../provisioning/java/pushpull/PullUtils.java   | 107 +++++++++++--------
 11 files changed, 162 insertions(+), 123 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 855894f..3243cf2 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -711,7 +711,7 @@ under the License.
                 location="${connid.location}"
                 connectorName="net.tirasa.connid.bundles.ldap.LdapConnector"
                 version="${connid.ldap.version}" 
-                jsonConf='[{"schema":{"name":"synchronizePasswords","displayName":"Enable Password Synchronization","helpMessage":"If true, the connector will synchronize passwords. The Password Capture Plugin needs to be installed for password synchronization to work.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"maintainLdapGroupMembership","displayName":"Maintain LDAP Group Membership","helpMessage":"When enabled and a user is renamed or deleted, update any LDAP groups to which the user belongs to reflect the new name. Otherwise, the LDAP resource must maintain referential integrity with respect to group membership.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["true"]},{"schema":{"name":"host","displayName":"Host","helpMessage":"The name or IP address of the host where the LDAP server is running.","type":"jav
 a.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["localhost"]},{"schema":{"name":"passwordHashAlgorithm","displayName":"Password Hash Algorithm","helpMessage":"Indicates the algorithm that the Identity system should use to hash the password. Currently supported values are SSHA, SHA, SSHA1, and SHA1. A blank value indicates that the system will not hash passwords. This will cause cleartext passwords to be stored in LDAP unless the LDAP server performs the hash (Netscape Directory Server and iPlanet Directory Server do).","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["SHA"]},{"schema":{"name":"port","displayName":"TCP Port","helpMessage":"TCP/IP port number used to communicate with the LDAP server.","type":"int","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[1389]},{"schema":{"name":"vlvSo
 rtAttribute","displayName":"VLV Sort Attribute","helpMessage":"Specify the sort attribute to use for VLV indexes on the resource.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"statusManagementClass","displayName":"Status management class ","helpMessage":"Class to be used to manage enabled/disabled status. If no class is specified then identity status management wont be possible.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["net.tirasa.connid.bundles.ldap.commons.AttributeStatusManagement"]},{"schema":{"name":"accountObjectClasses","displayName":"Account Object Classes","helpMessage":"The object class or classes that will be used when creating new user objects in the LDAP tree. When entering more than one object class, each entry should be on its own line; do not use commas or semi-colons to separate m
 ultiple object classes. Some object classes may require that you specify all object classes in the class hierarchy.","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["inetOrgPerson"]},{"schema":{"name":"accountUserNameAttributes","displayName":"Account User Name Attributes","helpMessage":"Attribute or attributes which holds the account user name. They will be used when authenticating to find the LDAP entry for the user name to authenticate.","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["uid"]},{"schema":{"name":"baseContextsToSynchronize","displayName":"Base Contexts to Synchronize","helpMessage":"One or more starting points in the LDAP tree that will be used to determine if a change should be synchronized. The base contexts attribute will be used to synchronize a change if this property is not set.","type":"[Ljava.lang.S
 tring;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["ou=people,o=isp","ou=groups,o=isp"]},{"schema":{"name":"accountSynchronizationFilter","displayName":"LDAP Filter for Accounts to Synchronize","helpMessage":"An optional LDAP filter for the objects to synchronize. Because the change log is for all objects, this filter updates only objects that match the specified filter. If you specify a filter, an object will be synchronized only if it matches the filter and includes a synchronized object class.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"removeLogEntryObjectClassFromFilter","displayName":"Remove Log Entry Object Class from Filter","helpMessage":"If this property is set (the default), the filter used to fetch change log entries does not contain the \"changeLogEntry\" object class, expecting that there are no entries of oth
 er object types in the change log.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"passwordDecryptionKey","displayName":"Password Decryption Key","helpMessage":"The key to decrypt passwords with when performing password synchronization.","type":"org.identityconnectors.common.security.GuardedByteArray","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"readSchema","displayName":"Read Schema","helpMessage":"If true, the connector will read the schema from the server. If false, the connector will provide a default schema based on the object classes in the configuration. This property must be true in order to use extended object classes.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["true"]},{"schema":{"name":"ssl","displayName":"SSL","helpMessage":
 "Select the check box to connect to the LDAP server using SSL.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"passwordAttributeToSynchronize","displayName":"Password Attribute to Synchronize","helpMessage":"The name of the password attribute to synchronize when performing password synchronization.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"accountSearchFilter","displayName":"LDAP Filter for Retrieving Accounts","helpMessage":"An optional LDAP filter to control which accounts are returned from the LDAP resource. If no filter is specified, only accounts that include all specified object classes are returned.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["uid=*"]},{"schema":{"name":"passwordDecryptionIni
 tializationVector","displayName":"Password Decryption Initialization Vector","helpMessage":"The initialization vector to decrypt passwords with when performing password synchronization.","type":"org.identityconnectors.common.security.GuardedByteArray","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"groupMemberAttribute","displayName":"Group Member Attribute","helpMessage":"The name of the group attribute that will be updated with the distinguished name of the user when the user is added to the group.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"failover","displayName":"Failover Servers","helpMessage":"List all servers that should be used for failover in case the preferred server fails. If the preferred server fails, JNDI will connect to the next available server in the list. List all servers in the form of \
 "ldap://ldap.example.com:389/\", which follows the standard LDAP v3 URLs described in RFC 2255. Only the host and port parts of the URL are relevant in this setting.","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"modifiersNamesToFilterOut","displayName":"Filter Out Changes By","helpMessage":"The names (DNs) of directory administrators to filter from the changes. Changes with the attribute \"modifiersName\" that match entries in this list will be filtered out. The standard value is the administrator name used by this adapter, to prevent loops. Entries should be of the format \"cn=Directory Manager\".","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"groupNameAttributes","displayName":"Group Name Attributes","helpMessage":"Attribute or attributes which holds the group name.","type"
 :"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["cn"]},{"schema":{"name":"uidAttribute","displayName":"Uid Attribute","helpMessage":"The name of the LDAP attribute which is mapped to the Uid attribute.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":true,"values":["cn"]},{"schema":{"name":"respectResourcePasswordPolicyChangeAfterReset","displayName":"Respect Resource Password Policy Change-After-Reset","helpMessage":"When this resource is specified in a Login Module (i.e., this resource is a pass-through authentication target) and the resource password policy is configured for change-after-reset, a user whose resource account password has been administratively reset will be required to change that password after successfully authenticating.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,
 "values":["false"]},{"schema":{"name":"filterWithOrInsteadOfAnd","displayName":"Filter with Or Instead of And","helpMessage":"Normally the the filter used to fetch change log entries is an and-based filter retrieving an interval of change entries. If this property is set, the filter will or together the required change numbers instead.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"principal","displayName":"Principal","helpMessage":"The distinguished name with which to authenticate to the LDAP server.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["uid=admin,ou=system"]},{"schema":{"name":"changeLogBlockSize","displayName":"Change Log Block Size","helpMessage":"The number of change log entries to fetch per query.","type":"int","required":true,"order":0,"confidential":false,"defaultValues":null},"overridabl
 e":false,"values":[100]},{"schema":{"name":"baseContexts","displayName":"Base Contexts","helpMessage":"One or more starting points in the LDAP tree that will be used when searching the tree. Searches are performed when discovering users from the LDAP server or when looking for the groups of which a user is a member.","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":true,"values":["ou=people,o=isp","ou=groups,o=isp"]},{"schema":{"name":"passwordAttribute","displayName":"Password Attribute","helpMessage":"The name of the LDAP attribute which holds the password. When changing an user password, the new password is set to this attribute.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["userpassword"]},{"schema":{"name":"changeNumberAttribute","displayName":"Change Number Attribute","helpMessage":"The name of the change number attribute in the chan
 ge log entry.","type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["changeNumber"]},{"schema":{"name":"objectClassesToSynchronize","displayName":"Object Classes to Synchronize","helpMessage":"The object classes to synchronize. The change log is for all objects; this filters updates to just the listed object classes. You should not list the superclasses of an object class unless you intend to synchronize objects with any of the superclass values. For example, if only \"inetOrgPerson\" objects should be synchronized, but the superclasses of \"inetOrgPerson\" (\"person\", \"organizationalperson\" and \"top\") should be filtered out, then list only \"inetOrgPerson\" here. All objects in LDAP are subclassed from \"top\". For this reason, you should never list \"top\", otherwise no object would be filtered.","type":"[Ljava.lang.String;","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable
 ":false,"values":["inetOrgPerson","groupOfUniqueNames"]},{"schema":{"name":"credentials","displayName":"Password","helpMessage":"Password for the principal.","type":"org.identityconnectors.common.security.GuardedString","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["secret"]},{"schema":{"name":"attributesToSynchronize","displayName":"Attributes to Synchronize","helpMessage":"The names of the attributes to synchronize. This ignores updates from the change log if they do not update any of the named attributes. For example, if only \"department\" is listed, then only changes that affect \"department\" will be processed. All other updates are ignored. If blank (the default), then all changes are processed.","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"maintainPosixGroupMembership","displayName":"Maintain POSIX Group Membership","
 helpMessage":"When enabled and a user is renamed or deleted, update any POSIX groups to which the user belongs to reflect the new name. Otherwise, the LDAP resource must maintain referential integrity with respect to group membership.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]}]'/>
+                jsonConf='[{"schema":{"name":"synchronizePasswords","displayName":"Enable Password Synchronization","helpMessage":"If true, the connector will synchronize passwords. The Password Capture Plugin needs to be installed for password synchronization to work.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"maintainLdapGroupMembership","displayName":"Maintain LDAP Group Membership","helpMessage":"When enabled and a user is renamed or deleted, update any LDAP groups to which the user belongs to reflect the new name. Otherwise, the LDAP resource must maintain referential integrity with respect to group membership.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["true"]},{"schema":{"name":"host","displayName":"Host","helpMessage":"The name or IP address of the host where the LDAP server is running.","type":"jav
 a.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["localhost"]},{"schema":{"name":"passwordHashAlgorithm","displayName":"Password Hash Algorithm","helpMessage":"Indicates the algorithm that the Identity system should use to hash the password. Currently supported values are SSHA, SHA, SSHA1, and SHA1. A blank value indicates that the system will not hash passwords. This will cause cleartext passwords to be stored in LDAP unless the LDAP server performs the hash (Netscape Directory Server and iPlanet Directory Server do).","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["SHA"]},{"schema":{"name":"port","displayName":"TCP Port","helpMessage":"TCP/IP port number used to communicate with the LDAP server.","type":"int","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[1389]},{"schema":{"name":"vlvSo
 rtAttribute","displayName":"VLV Sort Attribute","helpMessage":"Specify the sort attribute to use for VLV indexes on the resource.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"statusManagementClass","displayName":"Status management class ","helpMessage":"Class to be used to manage enabled/disabled status. If no class is specified then identity status management wont be possible.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["net.tirasa.connid.bundles.ldap.commons.AttributeStatusManagement"]},{"schema":{"name":"accountObjectClasses","displayName":"Account Object Classes","helpMessage":"The object class or classes that will be used when creating new user objects in the LDAP tree. When entering more than one object class, each entry should be on its own line; do not use commas or semi-colons to separate m
 ultiple object classes. Some object classes may require that you specify all object classes in the class hierarchy.","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["inetOrgPerson"]},{"schema":{"name":"accountUserNameAttributes","displayName":"Account User Name Attributes","helpMessage":"Attribute or attributes which holds the account user name. They will be used when authenticating to find the LDAP entry for the user name to authenticate.","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["uid"]},{"schema":{"name":"baseContextsToSynchronize","displayName":"Base Contexts to Synchronize","helpMessage":"One or more starting points in the LDAP tree that will be used to determine if a change should be synchronized. The base contexts attribute will be used to synchronize a change if this property is not set.","type":"[Ljava.lang.S
 tring;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["ou=people,o=isp","ou=groups,o=isp"]},{"schema":{"name":"accountSynchronizationFilter","displayName":"LDAP Filter for Accounts to Synchronize","helpMessage":"An optional LDAP filter for the objects to synchronize. Because the change log is for all objects, this filter updates only objects that match the specified filter. If you specify a filter, an object will be synchronized only if it matches the filter and includes a synchronized object class.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"removeLogEntryObjectClassFromFilter","displayName":"Remove Log Entry Object Class from Filter","helpMessage":"If this property is set (the default), the filter used to fetch change log entries does not contain the \"changeLogEntry\" object class, expecting that there are no entries of oth
 er object types in the change log.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"passwordDecryptionKey","displayName":"Password Decryption Key","helpMessage":"The key to decrypt passwords with when performing password synchronization.","type":"org.identityconnectors.common.security.GuardedByteArray","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"readSchema","displayName":"Read Schema","helpMessage":"If true, the connector will read the schema from the server. If false, the connector will provide a default schema based on the object classes in the configuration. This property must be true in order to use extended object classes.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["true"]},{"schema":{"name":"ssl","displayName":"SSL","helpMessage":
 "Select the check box to connect to the LDAP server using SSL.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"passwordAttributeToSynchronize","displayName":"Password Attribute to Synchronize","helpMessage":"The name of the password attribute to synchronize when performing password synchronization.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"accountSearchFilter","displayName":"LDAP Filter for Retrieving Accounts","helpMessage":"An optional LDAP filter to control which accounts are returned from the LDAP resource. If no filter is specified, only accounts that include all specified object classes are returned.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["uid=*"]},{"schema":{"name":"passwordDecryptionIni
 tializationVector","displayName":"Password Decryption Initialization Vector","helpMessage":"The initialization vector to decrypt passwords with when performing password synchronization.","type":"org.identityconnectors.common.security.GuardedByteArray","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"groupMemberAttribute","displayName":"Group Member Attribute","helpMessage":"The name of the group attribute that will be updated with the distinguished name of the user when the user is added to the group.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"failover","displayName":"Failover Servers","helpMessage":"List all servers that should be used for failover in case the preferred server fails. If the preferred server fails, JNDI will connect to the next available server in the list. List all servers in the form of \
 "ldap://ldap.example.com:389/\", which follows the standard LDAP v3 URLs described in RFC 2255. Only the host and port parts of the URL are relevant in this setting.","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"modifiersNamesToFilterOut","displayName":"Filter Out Changes By","helpMessage":"The names (DNs) of directory administrators to filter from the changes. Changes with the attribute \"modifiersName\" that match entries in this list will be filtered out. The standard value is the administrator name used by this adapter, to prevent loops. Entries should be of the format \"cn=Directory Manager\".","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"groupNameAttributes","displayName":"Group Name Attributes","helpMessage":"Attribute or attributes which holds the group name.","type"
 :"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["cn"]},{"schema":{"name":"uidAttribute","displayName":"Uid Attribute","helpMessage":"The name of the LDAP attribute which is mapped to the Uid attribute.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":true,"values":["cn"]},{"schema":{"name":"gidAttribute","displayName":"Uid Attribute for groups","helpMessage":"The name of the LDAP attribute which is mapped to the Uid attribute for groups.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":true,"values":["cn"]},{"schema":{"name":"respectResourcePasswordPolicyChangeAfterReset","displayName":"Respect Resource Password Policy Change-After-Reset","helpMessage":"When this resource is specified in a Login Module (i.e., this resource is a pass-through authentication target) and the resource passwor
 d policy is configured for change-after-reset, a user whose resource account password has been administratively reset will be required to change that password after successfully authenticating.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"filterWithOrInsteadOfAnd","displayName":"Filter with Or Instead of And","helpMessage":"Normally the the filter used to fetch change log entries is an and-based filter retrieving an interval of change entries. If this property is set, the filter will or together the required change numbers instead.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"principal","displayName":"Principal","helpMessage":"The distinguished name with which to authenticate to the LDAP server.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValue
 s":null},"overridable":false,"values":["uid=admin,ou=system"]},{"schema":{"name":"changeLogBlockSize","displayName":"Change Log Block Size","helpMessage":"The number of change log entries to fetch per query.","type":"int","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[100]},{"schema":{"name":"baseContexts","displayName":"Base Contexts","helpMessage":"One or more starting points in the LDAP tree that will be used when searching the tree. Searches are performed when discovering users from the LDAP server or when looking for the groups of which a user is a member.","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":true,"values":["ou=people,o=isp","ou=groups,o=isp"]},{"schema":{"name":"passwordAttribute","displayName":"Password Attribute","helpMessage":"The name of the LDAP attribute which holds the password. When changing an user password, the new password is set to this a
 ttribute.","type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["userpassword"]},{"schema":{"name":"changeNumberAttribute","displayName":"Change Number Attribute","helpMessage":"The name of the change number attribute in the change log entry.","type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["changeNumber"]},{"schema":{"name":"objectClassesToSynchronize","displayName":"Object Classes to Synchronize","helpMessage":"The object classes to synchronize. The change log is for all objects; this filters updates to just the listed object classes. You should not list the superclasses of an object class unless you intend to synchronize objects with any of the superclass values. For example, if only \"inetOrgPerson\" objects should be synchronized, but the superclasses of \"inetOrgPerson\" (\"person\", \"organizationalperson\" and \"top\") should b
 e filtered out, then list only \"inetOrgPerson\" here. All objects in LDAP are subclassed from \"top\". For this reason, you should never list \"top\", otherwise no object would be filtered.","type":"[Ljava.lang.String;","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["inetOrgPerson","groupOfUniqueNames"]},{"schema":{"name":"credentials","displayName":"Password","helpMessage":"Password for the principal.","type":"org.identityconnectors.common.security.GuardedString","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["secret"]},{"schema":{"name":"attributesToSynchronize","displayName":"Attributes to Synchronize","helpMessage":"The names of the attributes to synchronize. This ignores updates from the change log if they do not update any of the named attributes. For example, if only \"department\" is listed, then only changes that affect \"department\" will be processed. All other update
 s are ignored. If blank (the default), then all changes are processed.","type":"[Ljava.lang.String;","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"maintainPosixGroupMembership","displayName":"Maintain POSIX Group Membership","helpMessage":"When enabled and a user is renamed or deleted, update any POSIX groups to which the user belongs to reflect the new name. Otherwise, the LDAP resource must maintain referential integrity with respect to group membership.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]}]'/>
   <ConnInstance_capabilities connInstance_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" capability="CREATE"/>
   <ConnInstance_capabilities connInstance_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" capability="UPDATE"/>
   <ConnInstance_capabilities connInstance_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" capability="DELETE"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
index a2e5c8e..e5d23a9 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
@@ -51,7 +51,7 @@ public interface MappingManager {
      * @param orgUnit orgUnit information
      * @return connObjectKey internal value
      */
-    String getConnObjectKeyValue(Realm realm, OrgUnit orgUnit);
+    Optional<String> getConnObjectKeyValue(Realm realm, OrgUnit orgUnit);
 
     /**
      * Get attribute values for the given {@link Item} and any object.

http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index aced103..70a8647 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -282,14 +282,15 @@ public class MappingManagerImpl implements MappingManager {
             }
         }
 
-        Attribute connObjectKeyExtAttr =
-                AttributeUtil.find(orgUnit.getConnObjectKeyItem().get().getExtAttrName(), attributes);
-        if (connObjectKeyExtAttr != null) {
-            attributes.remove(connObjectKeyExtAttr);
-            attributes.add(
-                    AttributeBuilder.build(orgUnit.getConnObjectKeyItem().get().getExtAttrName(), connObjectKey));
+        Optional<? extends OrgUnitItem> connObjectKeyItem = orgUnit.getConnObjectKeyItem();
+        if (connObjectKeyItem.isPresent()) {
+            Attribute connObjectKeyExtAttr = AttributeUtil.find(connObjectKeyItem.get().getExtAttrName(), attributes);
+            if (connObjectKeyExtAttr != null) {
+                attributes.remove(connObjectKeyExtAttr);
+                attributes.add(AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKey));
+            }
+            attributes.add(MappingUtils.evaluateNAME(realm, orgUnit, connObjectKey));
         }
-        attributes.add(MappingUtils.evaluateNAME(realm, orgUnit, connObjectKey));
 
         return Pair.of(connObjectKey, attributes);
     }
@@ -619,8 +620,12 @@ public class MappingManagerImpl implements MappingManager {
     }
 
     private String getGroupOwnerValue(final Provision provision, final Any<?> any) {
-        Pair<String, Attribute> preparedAttr =
-                prepareAttr(provision, MappingUtils.getConnObjectKeyItem(provision).get(), any, null);
+        Optional<MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
+
+        Pair<String, Attribute> preparedAttr = null;
+        if (connObjectKeyItem.isPresent()) {
+            preparedAttr = prepareAttr(provision, connObjectKeyItem.get(), any, null);
+        }
 
         return preparedAttr == null
                 ? null
@@ -649,10 +654,10 @@ public class MappingManagerImpl implements MappingManager {
 
     @Transactional(readOnly = true)
     @Override
-    public String getConnObjectKeyValue(final Realm realm, final OrgUnit orgUnit) {
+    public Optional<String> getConnObjectKeyValue(final Realm realm, final OrgUnit orgUnit) {
         OrgUnitItem orgUnitItem = orgUnit.getConnObjectKeyItem().get();
 
-        return getIntValue(realm, orgUnitItem);
+        return Optional.ofNullable(orgUnitItem == null ? null : getIntValue(realm, orgUnitItem));
     }
 
     @Transactional(readOnly = true)

http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
index 3e12970..4a43019 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
@@ -26,6 +26,7 @@ import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.concurrent.atomic.AtomicReference;
@@ -58,6 +59,7 @@ import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
+import org.apache.syncope.core.persistence.api.entity.resource.OrgUnitItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.task.TaskUtilsFactory;
 import org.apache.syncope.core.provisioning.api.AuditManager;
@@ -598,30 +600,32 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
                 map(schema -> schema.asLinkingMappingItem()).collect(Collectors.toSet());
 
         ConnectorObject obj = null;
-        try {
-            obj = connector.getObject(
-                    new ObjectClass(task.getObjectClassName()),
-                    AttributeBuilder.build(
-                            MappingUtils.getConnObjectKeyItem(provision).get().getExtAttrName(), connObjectKey),
-                    MappingUtils.buildOperationOptions(new IteratorChain<>(
-                            MappingUtils.getPropagationItems(provision.getMapping().getItems()).iterator(),
-                            linkingMappingItems.iterator())));
-
-            for (MappingItem item : linkingMappingItems) {
-                Attribute attr = obj.getAttributeByName(item.getExtAttrName());
-                if (attr == null) {
-                    virAttrCache.expire(task.getAnyType(), task.getEntityKey(), item.getIntAttrName());
-                } else {
-                    VirAttrCacheValue cacheValue = new VirAttrCacheValue();
-                    cacheValue.setValues(attr.getValue());
-                    virAttrCache.put(task.getAnyType(), task.getEntityKey(), item.getIntAttrName(), cacheValue);
+        Optional<MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
+        if (connObjectKeyItem.isPresent()) {
+            try {
+                obj = connector.getObject(
+                        new ObjectClass(task.getObjectClassName()),
+                        AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKey),
+                        MappingUtils.buildOperationOptions(new IteratorChain<>(
+                                MappingUtils.getPropagationItems(provision.getMapping().getItems()).iterator(),
+                                linkingMappingItems.iterator())));
+
+                for (MappingItem item : linkingMappingItems) {
+                    Attribute attr = obj.getAttributeByName(item.getExtAttrName());
+                    if (attr == null) {
+                        virAttrCache.expire(task.getAnyType(), task.getEntityKey(), item.getIntAttrName());
+                    } else {
+                        VirAttrCacheValue cacheValue = new VirAttrCacheValue();
+                        cacheValue.setValues(attr.getValue());
+                        virAttrCache.put(task.getAnyType(), task.getEntityKey(), item.getIntAttrName(), cacheValue);
+                    }
                 }
+            } catch (TimeoutException toe) {
+                LOG.debug("Request timeout", toe);
+                throw toe;
+            } catch (RuntimeException ignore) {
+                LOG.debug("While resolving {}", connObjectKey, ignore);
             }
-        } catch (TimeoutException toe) {
-            LOG.debug("Request timeout", toe);
-            throw toe;
-        } catch (RuntimeException ignore) {
-            LOG.debug("While resolving {}", connObjectKey, ignore);
         }
 
         return obj;
@@ -647,16 +651,19 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
                 : task.getOldConnObjectKey();
 
         ConnectorObject obj = null;
-        try {
-            obj = connector.getObject(new ObjectClass(task.getObjectClassName()),
-                    AttributeBuilder.build(orgUnit.getConnObjectKeyItem().get().getExtAttrName(), connObjectKey),
-                    MappingUtils.buildOperationOptions(
-                            MappingUtils.getPropagationItems(orgUnit.getItems()).iterator()));
-        } catch (TimeoutException toe) {
-            LOG.debug("Request timeout", toe);
-            throw toe;
-        } catch (RuntimeException ignore) {
-            LOG.debug("While resolving {}", connObjectKey, ignore);
+        Optional<? extends OrgUnitItem> connObjectKeyItem = orgUnit.getConnObjectKeyItem();
+        if (connObjectKeyItem.isPresent()) {
+            try {
+                obj = connector.getObject(new ObjectClass(task.getObjectClassName()),
+                        AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKey),
+                        MappingUtils.buildOperationOptions(
+                                MappingUtils.getPropagationItems(orgUnit.getItems()).iterator()));
+            } catch (TimeoutException toe) {
+                LOG.debug("Request timeout", toe);
+                throw toe;
+            } catch (RuntimeException ignore) {
+                LOG.debug("While resolving {}", connObjectKey, ignore);
+            }
         }
 
         return obj;

http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
index a748562..5efe18c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
@@ -795,12 +795,8 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
         LOG.debug("Transformed {} for {} as {}",
                 processed.getDeltaType(), processed.getUid().getUidValue(), processed.getObject().getObjectClass());
 
-        String uid = processed.getPreviousUid() == null
-                ? processed.getUid().getUidValue()
-                : processed.getPreviousUid().getUidValue();
-
         try {
-            List<String> anyKeys = pullUtils.findExisting(uid, processed.getObject(), provision, anyUtils);
+            List<String> anyKeys = pullUtils.match(processed.getObject(), provision, anyUtils);
             LOG.debug("Match(es) found for {} as {}: {}",
                     processed.getUid().getUidValue(), processed.getObject().getObjectClass(), anyKeys);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
index cfbd325..5f74388 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
@@ -266,11 +266,16 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         Optional<MappingItem> connObjectKey = MappingUtils.getConnObjectKeyItem(provision.get());
         Optional<String> connObjecKeyValue = mappingManager.getConnObjectKeyValue(any, provision.get());
 
-        ConnectorObject beforeObj = getRemoteObject(
-                provision.get().getObjectClass(),
-                connObjectKey.get().getExtAttrName(),
-                connObjecKeyValue.get(),
-                provision.get().getMapping().getItems().iterator());
+        ConnectorObject beforeObj = null;
+        if (connObjectKey.isPresent() && connObjecKeyValue.isPresent()) {
+            beforeObj = getRemoteObject(
+                    provision.get().getObjectClass(),
+                    connObjectKey.get().getExtAttrName(),
+                    connObjecKeyValue.get(),
+                    provision.get().getMapping().getItems().iterator());
+        } else {
+            LOG.debug("ConnObjectKeyItem {} or its value {} are null", connObjectKey, connObjecKeyValue);
+        }
 
         Boolean status = profile.getTask().isSyncStatus() ? enabled : null;
 
@@ -435,11 +440,13 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
                     result.setStatus(ProvisioningReport.Status.SUCCESS);
                 }
                 resultStatus = AuditElements.Result.SUCCESS;
-                output = getRemoteObject(
-                        provision.get().getObjectClass(),
-                        connObjectKey.get().getExtAttrName(),
-                        connObjecKeyValue.get(),
-                        provision.get().getMapping().getItems().iterator());
+                if (connObjectKey.isPresent() && connObjecKeyValue.isPresent()) {
+                    output = getRemoteObject(
+                            provision.get().getObjectClass(),
+                            connObjectKey.get().getExtAttrName(),
+                            connObjecKeyValue.get(),
+                            provision.get().getMapping().getItems().iterator());
+                }
             } catch (IgnoreProvisionException e) {
                 throw e;
             } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java
index 6ff95fc..b1dcf3d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java
@@ -679,11 +679,7 @@ public class DefaultRealmPullResultHandler
         LOG.debug("Transformed {} for {} as {}",
                 processed.getDeltaType(), processed.getUid().getUidValue(), processed.getObject().getObjectClass());
 
-        String uid = processed.getPreviousUid() == null
-                ? processed.getUid().getUidValue()
-                : processed.getPreviousUid().getUidValue();
-
-        List<String> keys = pullUtils.findExisting(uid, processed.getObject(), orgUnit);
+        List<String> keys = pullUtils.match(processed.getObject(), orgUnit);
         LOG.debug("Match found for {} as {}: {}",
                 processed.getUid().getUidValue(), processed.getObject().getObjectClass(), keys);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPushResultHandler.java
index 1040461..434d275 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPushResultHandler.java
@@ -197,13 +197,18 @@ public class DefaultRealmPushResultHandler
         // Try to read remote object BEFORE any actual operation
         OrgUnit orgUnit = profile.getTask().getResource().getOrgUnit();
         Optional<? extends OrgUnitItem> connObjectKey = orgUnit.getConnObjectKeyItem();
-        String connObjecKeyValue = mappingManager.getConnObjectKeyValue(realm, orgUnit);
-
-        ConnectorObject beforeObj = getRemoteObject(
-                orgUnit.getObjectClass(),
-                connObjectKey.get().getExtAttrName(),
-                connObjecKeyValue,
-                orgUnit.getItems().iterator());
+        Optional<String> connObjecKeyValue = mappingManager.getConnObjectKeyValue(realm, orgUnit);
+
+        ConnectorObject beforeObj = null;
+        if (connObjectKey.isPresent() && connObjecKeyValue.isPresent()) {
+            beforeObj = getRemoteObject(
+                    orgUnit.getObjectClass(),
+                    connObjectKey.get().getExtAttrName(),
+                    connObjecKeyValue.get(),
+                    orgUnit.getItems().iterator());
+        } else {
+            LOG.debug("OrgUnitItem {} or its value {} are null", connObjectKey, connObjecKeyValue);
+        }
 
         if (profile.isDryRun()) {
             if (beforeObj == null) {
@@ -373,11 +378,13 @@ public class DefaultRealmPushResultHandler
                     result.setStatus(ProvisioningReport.Status.SUCCESS);
                 }
                 resultStatus = AuditElements.Result.SUCCESS;
-                output = getRemoteObject(
-                        orgUnit.getObjectClass(),
-                        connObjectKey.get().getExtAttrName(),
-                        connObjecKeyValue,
-                        orgUnit.getItems().iterator());
+                if (connObjectKey.isPresent() && connObjecKeyValue.isPresent()) {
+                    output = getRemoteObject(
+                            orgUnit.getObjectClass(),
+                            connObjectKey.get().getExtAttrName(),
+                            connObjecKeyValue.get(),
+                            orgUnit.getItems().iterator());
+                }
             } catch (IgnoreProvisionException e) {
                 throw e;
             } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
index 55f72f5..fd66d1f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
@@ -173,7 +173,7 @@ public class LDAPMembershipPullActions extends SchedulingPullActions {
     public void afterAll(final ProvisioningProfile<?, ?> profile) throws JobExecutionException {
         Map<String, Set<String>> resolvedMemberships = new HashMap<>();
         this.memberships.forEach((name, memb) -> {
-            Optional<String> userKey = pullUtils.findMatchingAnyKey(
+            Optional<String> userKey = pullUtils.match(
                     anyTypeDAO.findUser(),
                     name,
                     profile.getTask().getResource(),

http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
index 0f44bb5..9edfd6b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
@@ -141,7 +141,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
                 group.setGroupOwner(null);
                 group.setUserOwner(null);
             } else {
-                Optional<String> userKey = pullUtils.findMatchingAnyKey(
+                Optional<String> userKey = pullUtils.match(
                         anyTypeDAO.findUser(),
                         entry.getValue(),
                         ghandler.getProfile().getTask().getResource(),
@@ -150,7 +150,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
                 if (userKey.isPresent()) {
                     group.setUserOwner(userDAO.find(userKey.get()));
                 } else {
-                    Optional<String> groupKey = pullUtils.findMatchingAnyKey(
+                    Optional<String> groupKey = pullUtils.match(
                             anyTypeDAO.findGroup(),
                             entry.getValue(),
                             ghandler.getProfile().getTask().getResource(),

http://git-wip-us.apache.org/repos/asf/syncope/blob/f171ed2a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
index 49667db..77ca4e1 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
@@ -115,7 +115,7 @@ public class PullUtils {
     @Autowired
     private IntAttrNameParser intAttrNameParser;
 
-    public Optional<String> findMatchingAnyKey(
+    public Optional<String> match(
             final AnyType anyType,
             final String name,
             final ExternalResource resource,
@@ -146,7 +146,7 @@ public class PullUtils {
 
             ConnectorObject connObj = found.iterator().next();
             try {
-                List<String> anyKeys = findExisting(connObj.getUid().getUidValue(), connObj, provision.get(), anyUtils);
+                List<String> anyKeys = match(connObj, provision.get(), anyUtils);
                 if (anyKeys.isEmpty()) {
                     LOG.debug("No matching {} found for {}, aborting", anyUtils.getAnyTypeKind(), connObj);
                 } else {
@@ -172,19 +172,29 @@ public class PullUtils {
                         : groupDAO;
     }
 
-    private List<String> findByConnObjectKeyItem(
-            final String uid, final Provision provision, final AnyUtils anyUtils) {
+    private List<String> findByConnObjectKey(
+            final ConnectorObject connObj, final Provision provision, final AnyUtils anyUtils) {
+
+        String connObjectKey = null;
 
         Optional<MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
+        if (connObjectKeyItem.isPresent()) {
+            Attribute connObjectKeyAttr = connObj.getAttributeByName(connObjectKeyItem.get().getExtAttrName());
+            if (connObjectKeyAttr != null) {
+                connObjectKey = AttributeUtil.getStringValue(connObjectKeyAttr);
+            }
+        }
+        if (connObjectKey == null) {
+            return Collections.emptyList();
+        }
 
-        String transfUid = uid;
         for (ItemTransformer transformer : MappingUtils.getItemTransformers(connObjectKeyItem.get())) {
             List<Object> output = transformer.beforePull(
                     connObjectKeyItem.get(),
                     null,
-                    Collections.<Object>singletonList(transfUid));
+                    Collections.<Object>singletonList(connObjectKey));
             if (output != null && !output.isEmpty()) {
-                transfUid = output.get(0).toString();
+                connObjectKey = output.get(0).toString();
             }
         }
 
@@ -203,25 +213,25 @@ public class PullUtils {
         if (intAttrName.getField() != null) {
             switch (intAttrName.getField()) {
                 case "key":
-                    Any<?> any = getAnyDAO(provision.getAnyType().getKind()).find(transfUid);
+                    Any<?> any = getAnyDAO(provision.getAnyType().getKind()).find(connObjectKey);
                     if (any != null) {
                         result.add(any.getKey());
                     }
                     break;
 
                 case "username":
-                    User user = userDAO.findByUsername(transfUid);
+                    User user = userDAO.findByUsername(connObjectKey);
                     if (user != null) {
                         result.add(user.getKey());
                     }
                     break;
 
                 case "name":
-                    Group group = groupDAO.findByName(transfUid);
+                    Group group = groupDAO.findByName(connObjectKey);
                     if (group != null) {
                         result.add(group.getKey());
                     }
-                    AnyObject anyObject = anyObjectDAO.findByName(transfUid);
+                    AnyObject anyObject = anyObjectDAO.findByName(connObjectKey);
                     if (anyObject != null) {
                         result.add(anyObject.getKey());
                     }
@@ -236,29 +246,25 @@ public class PullUtils {
 
                     PlainSchema schema = plainSchemaDAO.find(intAttrName.getSchemaName());
                     if (schema == null) {
-                        value.setStringValue(transfUid);
+                        value.setStringValue(connObjectKey);
                     } else {
                         try {
-                            value.parseValue(schema, transfUid);
+                            value.parseValue(schema, connObjectKey);
                         } catch (ParsingValidationException e) {
-                            LOG.error("While parsing provided __UID__ {}", transfUid, e);
-                            value.setStringValue(transfUid);
+                            LOG.error("While parsing provided __UID__ {}", value, e);
+                            value.setStringValue(connObjectKey);
                         }
                     }
 
-                    List<? extends Any<?>> anys = getAnyDAO(provision.getAnyType().getKind()).
-                            findByPlainAttrValue(intAttrName.getSchemaName(), value);
-                    anys.forEach(any -> {
-                        result.add(any.getKey());
-                    });
+                    result.addAll(getAnyDAO(provision.getAnyType().getKind()).
+                            findByPlainAttrValue(intAttrName.getSchemaName(), value).stream().
+                            map(Entity::getKey).collect(Collectors.toList()));
                     break;
 
                 case DERIVED:
-                    anys = getAnyDAO(provision.getAnyType().getKind()).
-                            findByDerAttrValue(intAttrName.getSchemaName(), transfUid);
-                    anys.forEach(any -> {
-                        result.add(any.getKey());
-                    });
+                    result.addAll(getAnyDAO(provision.getAnyType().getKind()).
+                            findByDerAttrValue(intAttrName.getSchemaName(), connObjectKey).stream().
+                            map(Entity::getKey).collect(Collectors.toList()));
                     break;
 
                 default:
@@ -279,16 +285,14 @@ public class PullUtils {
     }
 
     /**
-     * Find any objects based on mapped uid value (or previous uid value, if updated).
+     * Finds internal entities based on external attributes and mapping.
      *
-     * @param uid for finding by connObjectKey
-     * @param connObj for finding by attribute value
-     * @param provision external resource
-     * @param anyUtils any util
-     * @return list of matching users / groups
+     * @param connObj external attributes
+     * @param provision mapping
+     * @param anyUtils any utils
+     * @return list of matching users' / groups' / any objects' keys
      */
-    public List<String> findExisting(
-            final String uid,
+    public List<String> match(
             final ConnectorObject connObj,
             final Provision provision,
             final AnyUtils anyUtils) {
@@ -309,27 +313,44 @@ public class PullUtils {
         try {
             return rule.isPresent()
                     ? findByCorrelationRule(connObj, provision, rule.get(), anyUtils.getAnyTypeKind())
-                    : findByConnObjectKeyItem(uid, provision, anyUtils);
+                    : findByConnObjectKey(connObj, provision, anyUtils);
         } catch (RuntimeException e) {
+            LOG.error("Could not match {} with any existing {}", connObj, provision.getAnyType(), e);
             return Collections.<String>emptyList();
         }
     }
 
-    public List<String> findExisting(
-            final String uid,
+    /**
+     * Finds internal realms based on external attributes and mapping.
+     *
+     * @param connObj external attributes
+     * @param orgUnit mapping
+     * @return list of matching realms' keys.
+     */
+    public List<String> match(
             final ConnectorObject connObj,
             final OrgUnit orgUnit) {
 
+        String connObjectKey = null;
+
         Optional<? extends OrgUnitItem> connObjectKeyItem = orgUnit.getConnObjectKeyItem();
+        if (connObjectKeyItem != null) {
+            Attribute connObjectKeyAttr = connObj.getAttributeByName(connObjectKeyItem.get().getExtAttrName());
+            if (connObjectKeyAttr != null) {
+                connObjectKey = AttributeUtil.getStringValue(connObjectKeyAttr);
+            }
+        }
+        if (connObjectKey == null) {
+            return Collections.emptyList();
+        }
 
-        String transfUid = uid;
         for (ItemTransformer transformer : MappingUtils.getItemTransformers(connObjectKeyItem.get())) {
             List<Object> output = transformer.beforePull(
                     connObjectKeyItem.get(),
                     null,
-                    Collections.<Object>singletonList(transfUid));
+                    Collections.<Object>singletonList(connObjectKey));
             if (output != null && !output.isEmpty()) {
-                transfUid = output.get(0).toString();
+                connObjectKey = output.get(0).toString();
             }
         }
 
@@ -338,19 +359,19 @@ public class PullUtils {
         Realm realm;
         switch (connObjectKeyItem.get().getIntAttrName()) {
             case "key":
-                realm = realmDAO.find(transfUid);
+                realm = realmDAO.find(connObjectKey);
                 if (realm != null) {
                     result.add(realm.getKey());
                 }
                 break;
 
             case "name":
-                result.addAll(realmDAO.findByName(transfUid).stream().
-                        map(r -> r.getKey()).collect(Collectors.toList()));
+                result.addAll(realmDAO.findByName(connObjectKey).stream().
+                        map(Entity::getKey).collect(Collectors.toList()));
                 break;
 
             case "fullpath":
-                realm = realmDAO.findByFullPath(transfUid);
+                realm = realmDAO.findByFullPath(connObjectKey);
                 if (realm != null) {
                     result.add(realm.getKey());
                 }