Repository: syncope
Updated Branches:
  refs/heads/2_0_X 888fcc107 -> 385b062f8
  refs/heads/master a346bbf6a -> f171ed2ae


[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/385b062f
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/385b062f
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/385b062f

Branch: refs/heads/2_0_X
Commit: 385b062f8da6c49537e3b97faf538758e0b77915
Parents: 888fcc1
Author: Francesco Chicchiriccò <ilgro...@apache.org>
Authored: Wed Apr 4 10:29:29 2018 +0200
Committer: Francesco Chicchiriccò <ilgro...@apache.org>
Committed: Wed Apr 4 10:29:29 2018 +0200

----------------------------------------------------------------------
 .../test/resources/domains/MasterContent.xml    |   2 +-
 .../provisioning/java/MappingManagerImpl.java   |  24 ++--
 .../AbstractPropagationTaskExecutor.java        |  71 ++++++-----
 .../pushpull/AbstractPullResultHandler.java     |   6 +-
 .../pushpull/AbstractPushResultHandler.java     |  27 ++--
 .../pushpull/DefaultRealmPullResultHandler.java |   6 +-
 .../pushpull/DefaultRealmPushResultHandler.java |  27 ++--
 .../pushpull/LDAPMembershipPullActions.java     |   2 +-
 .../java/pushpull/PullJobDelegate.java          |   4 +-
 .../provisioning/java/pushpull/PullUtils.java   | 125 +++++++++++--------
 10 files changed, 165 insertions(+), 129 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/385b062f/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 f6c4b90..437596c 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -692,7 +692,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/385b062f/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 713646f..33b9535 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
@@ -274,13 +274,15 @@ public class MappingManagerImpl implements MappingManager 
{
             }
         }
 
-        Attribute connObjectKeyExtAttr =
-                
AttributeUtil.find(orgUnit.getConnObjectKeyItem().getExtAttrName(), attributes);
-        if (connObjectKeyExtAttr != null) {
-            attributes.remove(connObjectKeyExtAttr);
-            
attributes.add(AttributeBuilder.build(orgUnit.getConnObjectKeyItem().getExtAttrName(),
 connObjectKey));
+        OrgUnitItem connObjectKeyItem = orgUnit.getConnObjectKeyItem();
+        if (connObjectKeyItem != null) {
+            Attribute connObjectKeyExtAttr = 
AttributeUtil.find(connObjectKeyItem.getExtAttrName(), attributes);
+            if (connObjectKeyExtAttr != null) {
+                attributes.remove(connObjectKeyExtAttr);
+                
attributes.add(AttributeBuilder.build(connObjectKeyItem.getExtAttrName(), 
connObjectKey));
+            }
+            attributes.add(MappingUtils.evaluateNAME(realm, orgUnit, 
connObjectKey));
         }
-        attributes.add(MappingUtils.evaluateNAME(realm, orgUnit, 
connObjectKey));
 
         return Pair.of(connObjectKey, attributes);
     }
@@ -592,8 +594,12 @@ public class MappingManagerImpl implements MappingManager {
     }
 
     private String getGroupOwnerValue(final Provision provision, final Any<?> 
any) {
-        Pair<String, Attribute> preparedAttr =
-                prepareAttr(provision, 
MappingUtils.getConnObjectKeyItem(provision), any, null);
+        MappingItem connObjectKeyItem = 
MappingUtils.getConnObjectKeyItem(provision);
+
+        Pair<String, Attribute> preparedAttr = null;
+        if (connObjectKeyItem != null) {
+            preparedAttr = prepareAttr(provision, connObjectKeyItem, any, 
null);
+        }
 
         return preparedAttr == null
                 ? null
@@ -625,7 +631,7 @@ public class MappingManagerImpl implements MappingManager {
     public String getConnObjectKeyValue(final Realm realm, final OrgUnit 
orgUnit) {
         OrgUnitItem orgUnitItem = orgUnit.getConnObjectKeyItem();
 
-        return getIntValue(realm, orgUnitItem);
+        return orgUnitItem == null ? null : getIntValue(realm, orgUnitItem);
     }
 
     @Transactional(readOnly = true)

http://git-wip-us.apache.org/repos/asf/syncope/blob/385b062f/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 3357335..33255bb 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
@@ -60,6 +60,7 @@ import 
org.apache.syncope.core.persistence.api.entity.VirSchema;
 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;
@@ -629,30 +630,33 @@ public abstract class AbstractPropagationTaskExecutor 
implements PropagationTask
         }
 
         ConnectorObject obj = null;
-        try {
-            obj = connector.getObject(
-                    new ObjectClass(task.getObjectClassName()),
-                    AttributeBuilder.build(
-                            
MappingUtils.getConnObjectKeyItem(provision).getExtAttrName(), connObjectKey),
-                    
MappingUtils.buildOperationOptions(IteratorUtils.chainedIterator(
-                            
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);
+        MappingItem connObjectKeyItem = 
MappingUtils.getConnObjectKeyItem(provision);
+        if (connObjectKeyItem != null) {
+            try {
+                obj = connector.getObject(
+                        new ObjectClass(task.getObjectClassName()),
+                        AttributeBuilder.build(
+                                connObjectKeyItem.getExtAttrName(), 
connObjectKey),
+                        
MappingUtils.buildOperationOptions(IteratorUtils.chainedIterator(
+                                
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;
@@ -678,16 +682,19 @@ public abstract class AbstractPropagationTaskExecutor 
implements PropagationTask
                 : task.getOldConnObjectKey();
 
         ConnectorObject obj = null;
-        try {
-            obj = connector.getObject(new 
ObjectClass(task.getObjectClassName()),
-                    
AttributeBuilder.build(orgUnit.getConnObjectKeyItem().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);
+        OrgUnitItem connObjectKeyItem = orgUnit.getConnObjectKeyItem();
+        if (connObjectKeyItem != null) {
+            try {
+                obj = connector.getObject(new 
ObjectClass(task.getObjectClassName()),
+                        
AttributeBuilder.build(connObjectKeyItem.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/385b062f/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 9991330..25d63ee 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
@@ -745,12 +745,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/385b062f/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 6b03c1d..7133e3a 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
@@ -265,11 +265,16 @@ public abstract class AbstractPushResultHandler extends 
AbstractSyncopeResultHan
         MappingItem connObjectKey = 
MappingUtils.getConnObjectKeyItem(provision);
         String connObjecKeyValue = mappingManager.getConnObjectKeyValue(any, 
provision);
 
-        ConnectorObject beforeObj = getRemoteObject(
-                provision.getObjectClass(),
-                connObjectKey.getExtAttrName(),
-                connObjecKeyValue,
-                provision.getMapping().getItems().iterator());
+        ConnectorObject beforeObj = null;
+        if (connObjectKey == null || connObjecKeyValue == null) {
+            LOG.debug("ConnObjectKeyItem {} or its value {} are null", 
connObjectKey, connObjecKeyValue);
+        } else {
+            beforeObj = getRemoteObject(
+                    provision.getObjectClass(),
+                    connObjectKey.getExtAttrName(),
+                    connObjecKeyValue,
+                    provision.getMapping().getItems().iterator());
+        }
 
         Boolean status = profile.getTask().isSyncStatus() ? enabled : null;
 
@@ -434,11 +439,13 @@ public abstract class AbstractPushResultHandler extends 
AbstractSyncopeResultHan
                     result.setStatus(ProvisioningReport.Status.SUCCESS);
                 }
                 resultStatus = AuditElements.Result.SUCCESS;
-                output = getRemoteObject(
-                        provision.getObjectClass(),
-                        connObjectKey.getExtAttrName(),
-                        connObjecKeyValue,
-                        provision.getMapping().getItems().iterator());
+                if (connObjectKey != null && connObjecKeyValue != null) {
+                    output = getRemoteObject(
+                            provision.getObjectClass(),
+                            connObjectKey.getExtAttrName(),
+                            connObjecKeyValue,
+                            provision.getMapping().getItems().iterator());
+                }
             } catch (IgnoreProvisionException e) {
                 throw e;
             } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/385b062f/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/385b062f/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 03fea98..54b56c9 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
@@ -198,11 +198,16 @@ public class DefaultRealmPushResultHandler
         OrgUnitItem connObjectKey = orgUnit.getConnObjectKeyItem();
         String connObjecKeyValue = mappingManager.getConnObjectKeyValue(realm, 
orgUnit);
 
-        ConnectorObject beforeObj = getRemoteObject(
-                orgUnit.getObjectClass(),
-                connObjectKey.getExtAttrName(),
-                connObjecKeyValue,
-                orgUnit.getItems().iterator());
+        ConnectorObject beforeObj = null;
+        if (connObjectKey == null || connObjecKeyValue == null) {
+            LOG.debug("OrgUnitItem {} or its value {} are null", 
connObjectKey, connObjecKeyValue);
+        } else {
+            beforeObj = getRemoteObject(
+                    orgUnit.getObjectClass(),
+                    connObjectKey.getExtAttrName(),
+                    connObjecKeyValue,
+                    orgUnit.getItems().iterator());
+        }
 
         if (profile.isDryRun()) {
             if (beforeObj == null) {
@@ -372,11 +377,13 @@ public class DefaultRealmPushResultHandler
                     result.setStatus(ProvisioningReport.Status.SUCCESS);
                 }
                 resultStatus = AuditElements.Result.SUCCESS;
-                output = getRemoteObject(
-                        orgUnit.getObjectClass(),
-                        connObjectKey.getExtAttrName(),
-                        connObjecKeyValue,
-                        orgUnit.getItems().iterator());
+                if (connObjectKey != null && connObjecKeyValue != null) {
+                    output = getRemoteObject(
+                            orgUnit.getObjectClass(),
+                            connObjectKey.getExtAttrName(),
+                            connObjecKeyValue,
+                            orgUnit.getItems().iterator());
+                }
             } catch (IgnoreProvisionException e) {
                 throw e;
             } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/385b062f/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 98ce3b9..02ac42c 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
@@ -178,7 +178,7 @@ public class LDAPMembershipPullActions extends 
SchedulingPullActions {
     public void afterAll(final ProvisioningProfile<?, ?> profile) throws 
JobExecutionException {
         Map<String, Set<String>> resolvedMemberships = new HashMap<>();
         for (Map.Entry<String, Set<String>> entry : 
this.memberships.entrySet()) {
-            String userKey = pullUtils.findMatchingAnyKey(
+            String userKey = pullUtils.match(
                     anyTypeDAO.findUser(),
                     entry.getKey(),
                     profile.getTask().getResource(),

http://git-wip-us.apache.org/repos/asf/syncope/blob/385b062f/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 6f9eedf..feffeba 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
@@ -142,14 +142,14 @@ public class PullJobDelegate extends 
AbstractProvisioningJobDelegate<PullTask> i
                 group.setGroupOwner(null);
                 group.setUserOwner(null);
             } else {
-                String userKey = pullUtils.findMatchingAnyKey(
+                String userKey = pullUtils.match(
                         anyTypeDAO.findUser(),
                         entry.getValue(),
                         ghandler.getProfile().getTask().getResource(),
                         ghandler.getProfile().getConnector());
 
                 if (userKey == null) {
-                    String groupKey = pullUtils.findMatchingAnyKey(
+                    String groupKey = pullUtils.match(
                             anyTypeDAO.findGroup(),
                             entry.getValue(),
                             ghandler.getProfile().getTask().getResource(),

http://git-wip-us.apache.org/repos/asf/syncope/blob/385b062f/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 2f00978..46b6a22 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
@@ -116,7 +116,7 @@ public class PullUtils {
     @Autowired
     private IntAttrNameParser intAttrNameParser;
 
-    public String findMatchingAnyKey(
+    public String match(
             final AnyType anyType,
             final String name,
             final ExternalResource resource,
@@ -152,7 +152,7 @@ public class PullUtils {
 
             ConnectorObject connObj = found.iterator().next();
             try {
-                List<String> anyKeys = 
findExisting(connObj.getUid().getUidValue(), connObj, provision, anyUtils);
+                List<String> anyKeys = match(connObj, provision, anyUtils);
                 if (anyKeys.isEmpty()) {
                     LOG.debug("No matching {} found for {}, aborting", 
anyUtils.getAnyTypeKind(), connObj);
                 } else {
@@ -178,19 +178,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;
 
         MappingItem connObjectKeyItem = 
MappingUtils.getConnObjectKeyItem(provision);
+        if (connObjectKeyItem != null) {
+            Attribute connObjectKeyAttr = 
connObj.getAttributeByName(connObjectKeyItem.getExtAttrName());
+            if (connObjectKeyAttr != null) {
+                connObjectKey = 
AttributeUtil.getStringValue(connObjectKeyAttr);
+            }
+        }
+        if (connObjectKey == null) {
+            return Collections.emptyList();
+        }
 
-        String transfUid = uid;
         for (ItemTransformer transformer : 
MappingUtils.getItemTransformers(connObjectKeyItem)) {
             List<Object> output = transformer.beforePull(
                     connObjectKeyItem,
                     null,
-                    Collections.<Object>singletonList(transfUid));
+                    Collections.<Object>singletonList(connObjectKey));
             if (output != null && !output.isEmpty()) {
-                transfUid = output.get(0).toString();
+                connObjectKey = output.get(0).toString();
             }
         }
 
@@ -207,25 +217,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());
                     }
@@ -240,13 +250,13 @@ 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);
                         }
                     }
 
@@ -259,7 +269,7 @@ public class PullUtils {
 
                 case DERIVED:
                     anys = getAnyDAO(provision.getAnyType().getKind()).
-                            findByDerAttrValue(intAttrName.getSchemaName(), 
transfUid);
+                            findByDerAttrValue(intAttrName.getSchemaName(), 
connObjectKey);
                     for (Any<?> any : anys) {
                         result.add(any.getKey());
                     }
@@ -283,37 +293,15 @@ public class PullUtils {
         return result;
     }
 
-    private PullCorrelationRule getCorrelationRule(final Provision provision, 
final PullPolicySpec policySpec) {
-        PullCorrelationRule result = null;
-
-        String pullCorrelationRule = 
policySpec.getCorrelationRules().get(provision.getAnyType().getKey());
-        if (StringUtils.isNotBlank(pullCorrelationRule)) {
-            if (pullCorrelationRule.charAt(0) == '[') {
-                result = new PlainAttrsPullCorrelationRule(
-                        POJOHelper.deserialize(pullCorrelationRule, 
String[].class), provision);
-            } else {
-                try {
-                    result = (PullCorrelationRule) 
Class.forName(pullCorrelationRule).newInstance();
-                } catch (Exception e) {
-                    LOG.error("Failure instantiating correlation rule class 
'{}'", pullCorrelationRule, e);
-                }
-            }
-        }
-
-        return result;
-    }
-
     /**
-     * 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) {
@@ -325,33 +313,62 @@ public class PullUtils {
 
         PullCorrelationRule pullRule = null;
         if (pullPolicySpec != null) {
-            pullRule = getCorrelationRule(provision, pullPolicySpec);
+            String pullCorrelationRule = 
pullPolicySpec.getCorrelationRules().get(provision.getAnyType().getKey());
+            if (StringUtils.isNotBlank(pullCorrelationRule)) {
+                if (pullCorrelationRule.charAt(0) == '[') {
+                    pullRule = new PlainAttrsPullCorrelationRule(
+                            POJOHelper.deserialize(pullCorrelationRule, 
String[].class), provision);
+                } else {
+                    try {
+                        pullRule = (PullCorrelationRule) 
Class.forName(pullCorrelationRule).newInstance();
+                    } catch (ClassNotFoundException | IllegalAccessException | 
InstantiationException e) {
+                        LOG.error("Failure instantiating correlation rule 
class '{}'", pullCorrelationRule, e);
+                    }
+                }
+            }
         }
 
         try {
             return pullRule == null
-                    ? findByConnObjectKeyItem(uid, provision, anyUtils)
+                    ? findByConnObjectKey(connObj, provision, anyUtils)
                     : findByCorrelationRule(connObj, pullRule, 
anyUtils.getAnyTypeKind());
         } 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;
+
         OrgUnitItem connObjectKeyItem = orgUnit.getConnObjectKeyItem();
+        if (connObjectKeyItem != null) {
+            Attribute connObjectKeyAttr = 
connObj.getAttributeByName(connObjectKeyItem.getExtAttrName());
+            if (connObjectKeyAttr != null) {
+                connObjectKey = 
AttributeUtil.getStringValue(connObjectKeyAttr);
+            }
+        }
+        if (connObjectKey == null) {
+            return Collections.emptyList();
+        }
 
-        String transfUid = uid;
         for (ItemTransformer transformer : 
MappingUtils.getItemTransformers(connObjectKeyItem)) {
             List<Object> output = transformer.beforePull(
                     connObjectKeyItem,
                     null,
-                    Collections.<Object>singletonList(transfUid));
+                    Collections.<Object>singletonList(connObjectKey));
             if (output != null && !output.isEmpty()) {
-                transfUid = output.get(0).toString();
+                connObjectKey = output.get(0).toString();
             }
         }
 
@@ -360,18 +377,18 @@ public class PullUtils {
         Realm realm;
         switch (connObjectKeyItem.getIntAttrName()) {
             case "key":
-                realm = realmDAO.find(transfUid);
+                realm = realmDAO.find(connObjectKey);
                 if (realm != null) {
                     result.add(realm.getKey());
                 }
                 break;
 
             case "name":
-                CollectionUtils.collect(realmDAO.findByName(transfUid), 
EntityUtils.keyTransformer(), result);
+                CollectionUtils.collect(realmDAO.findByName(connObjectKey), 
EntityUtils.keyTransformer(), result);
                 break;
 
             case "fullpath":
-                realm = realmDAO.findByFullPath(transfUid);
+                realm = realmDAO.findByFullPath(connObjectKey);
                 if (realm != null) {
                     result.add(realm.getKey());
                 }

Reply via email to