diff --git a/src/main/java/net/tirasa/connid/bundles/ldap/LdapConfiguration.java b/src/main/java/net/tirasa/connid/bundles/ldap/LdapConfiguration.java index 82b06bd..6769a3a 100644 --- a/src/main/java/net/tirasa/connid/bundles/ldap/LdapConfiguration.java +++ b/src/main/java/net/tirasa/connid/bundles/ldap/LdapConfiguration.java @@ -23,6 +23,7 @@ */ package net.tirasa.connid.bundles.ldap; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -38,6 +39,8 @@ import net.tirasa.connid.bundles.ldap.commons.ObjectClassMappingConfig; import net.tirasa.connid.bundles.ldap.schema.LdapSchemaMapping; import net.tirasa.connid.bundles.ldap.search.DefaultSearchStrategy; +import net.tirasa.connid.bundles.ldap.sync.LdapSyncStrategy; +import net.tirasa.connid.bundles.ldap.sync.sunds.SunDSChangeLogSyncStrategy; import org.identityconnectors.common.CollectionUtil; import org.identityconnectors.common.EqualsHashCodeBuilder; import org.identityconnectors.common.StringUtil; @@ -213,6 +216,10 @@ public enum SearchScope { private String dnAttribute = "entryDN"; + private String syncStrategy = SunDSChangeLogSyncStrategy.class.getName(); + + private Class syncStrategyClass = null; + /** * The SearchScope for user objects */ @@ -348,6 +355,9 @@ public void validate() { checkNotBlank(passwordDecryptionKey, "decryptionKey.notBlank"); checkNotBlank(passwordDecryptionInitializationVector, "decryptionInitializationVector.notBlank"); } + + checkNotBlank(syncStrategy, "syncStrategy.notBlank"); + checkLdapSyncStrategy(); } private void checkNotBlank(String value, String errorMessage) { @@ -372,8 +382,22 @@ public void access(byte[] clearBytes) { } } + @SuppressWarnings("unchecked") + private void checkLdapSyncStrategy() { + try { + Class clazz = Class.forName(syncStrategy); + if (LdapSyncStrategy.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) { + syncStrategyClass = (Class) clazz; + } else { + failValidation("syncStrategy.classNotSyncStrategy"); + } + } catch (ClassNotFoundException e) { + failValidation("syncStrategy.classNotFound"); + } + } + private void checkNotEmpty(Collection collection, String errorMessage) { - if (collection.size() < 1) { + if (collection.isEmpty()) { failValidation(errorMessage); } } @@ -523,7 +547,7 @@ public void setPasswordAttribute(String passwordAttribute) { helpMessageKey = "accountObjectClasses.help") public String[] getAccountObjectClasses() { List ldapClasses = accountConfig.getLdapClasses(); - return ldapClasses.toArray(new String[ldapClasses.size()]); + return ldapClasses.toArray(new String[0]); } public void setAccountObjectClasses(String... accountObjectClasses) { @@ -535,7 +559,7 @@ public void setAccountObjectClasses(String... accountObjectClasses) { helpMessageKey = "accountUserNameAttributes.help") public String[] getAccountUserNameAttributes() { List shortNameLdapAttributes = accountConfig.getShortNameLdapAttributes(); - return shortNameLdapAttributes.toArray(new String[shortNameLdapAttributes.size()]); + return shortNameLdapAttributes.toArray(new String[0]); } public void setAccountUserNameAttributes(String... accountUserNameAttributes) { @@ -569,7 +593,7 @@ public void setAccountSearchFilter(String accountSearchFilter) { helpMessageKey = "groupObjectClasses.help") public String[] getGroupObjectClasses() { List ldapClasses = groupConfig.getLdapClasses(); - return ldapClasses.toArray(new String[ldapClasses.size()]); + return ldapClasses.toArray(new String[0]); } public void setGroupObjectClasses(String... groupObjectClasses) { @@ -581,7 +605,7 @@ public void setGroupObjectClasses(String... groupObjectClasses) { helpMessageKey = "groupNameAttributes.help") public String[] getGroupNameAttributes() { List shortNameLdapAttributes = groupConfig.getShortNameLdapAttributes(); - return shortNameLdapAttributes.toArray(new String[shortNameLdapAttributes.size()]); + return shortNameLdapAttributes.toArray(new String[0]); } public void setGroupNameAttributes(String... groupNameAttributes) { @@ -648,7 +672,7 @@ public void setAddPrincipalToNewGroups(boolean addPrincipalToNewGroups) { helpMessageKey = "anyObjectClasses.help") public String[] getAnyObjectClasses() { List ldapClasses = anyObjectConfig.getLdapClasses(); - return ldapClasses.toArray(new String[ldapClasses.size()]); + return ldapClasses.toArray(new String[0]); } public void setAnyObjectClasses(String... anyObjectClasses) { @@ -660,7 +684,7 @@ public void setAnyObjectClasses(String... anyObjectClasses) { helpMessageKey = "anyObjectNameAttributes.help") public String[] getAnyObjectNameAttributes() { List shortNameLdapAttributes = anyObjectConfig.getShortNameLdapAttributes(); - return shortNameLdapAttributes.toArray(new String[shortNameLdapAttributes.size()]); + return shortNameLdapAttributes.toArray(new String[0]); } public void setAnyObjectNameAttributes(String... anyObjectNameAttributes) { @@ -909,8 +933,7 @@ public GuardedByteArray getPasswordDecryptionInitializationVector() { public void setPasswordDecryptionInitializationVector(GuardedByteArray passwordDecryptionInitializationVector) { this.passwordDecryptionInitializationVector = passwordDecryptionInitializationVector != null - ? passwordDecryptionInitializationVector. - copy() : null; + ? passwordDecryptionInitializationVector.copy() : null; } @ConfigurationProperty(order = 44, @@ -979,10 +1002,25 @@ public void setConnectTimeout(long connectTimeout) { this.connectTimeout = connectTimeout; } + @ConfigurationProperty(order = 50, + displayMessageKey = "syncStrategy.display", + helpMessageKey = "syncStrategy.help") + public String getSyncStrategy() { + return syncStrategy; + } + + public void setSyncStrategy(String syncStrategy) { + this.syncStrategy = syncStrategy; + } + + public Class getSyncStrategyClass() { + return syncStrategyClass; + } + // Getters and setters for configuration properties end here. public List getBaseContextsAsLdapNames() { if (baseContextsAsLdapNames == null) { - List result = new ArrayList(baseContexts.length); + List result = new ArrayList<>(baseContexts.length); try { for (String baseContext : baseContexts) { result.add(new LdapName(baseContext)); @@ -998,7 +1036,7 @@ public List getBaseContextsAsLdapNames() { public List getBaseContextsToSynchronizeAsLdapNames() { if (baseContextsToSynchronizeAsLdapNames == null) { String[] source = LdapUtil.nullAsEmpty(baseContextsToSynchronize); - List result = new ArrayList(source.length); + List result = new ArrayList<>(source.length); try { for (String each : source) { result.add(new LdapName(each)); @@ -1014,7 +1052,7 @@ public List getBaseContextsToSynchronizeAsLdapNames() { public Set getModifiersNamesToFilterOutAsLdapNames() { if (modifiersNamesToFilterOutAsLdapNames == null) { String[] source = LdapUtil.nullAsEmpty(modifiersNamesToFilterOut); - Set result = new HashSet(source.length); + Set result = new HashSet<>(source.length); try { for (String each : source) { result.add(new LdapName(each)); @@ -1028,7 +1066,7 @@ public Set getModifiersNamesToFilterOutAsLdapNames() { } public Map getObjectClassMappingConfigs() { - Map result = new HashMap(); + Map result = new HashMap<>(); result.put(accountConfig.getObjectClass(), accountConfig); result.put(groupConfig.getObjectClass(), groupConfig); result.put(anyObjectConfig.getObjectClass(), anyObjectConfig); @@ -1102,8 +1140,7 @@ public boolean equals(Object obj) { if (this == that) { return true; } - return this.createHashCodeBuilder().equals(that. - createHashCodeBuilder()); + return this.createHashCodeBuilder().equals(that.createHashCodeBuilder()); } return false; } diff --git a/src/main/java/net/tirasa/connid/bundles/ldap/LdapConnector.java b/src/main/java/net/tirasa/connid/bundles/ldap/LdapConnector.java index 6444a16..304e1e4 100644 --- a/src/main/java/net/tirasa/connid/bundles/ldap/LdapConnector.java +++ b/src/main/java/net/tirasa/connid/bundles/ldap/LdapConnector.java @@ -30,7 +30,9 @@ import net.tirasa.connid.bundles.ldap.search.LdapFilter; import net.tirasa.connid.bundles.ldap.search.LdapFilterTranslator; import net.tirasa.connid.bundles.ldap.search.LdapSearch; +import net.tirasa.connid.bundles.ldap.sync.LdapSyncStrategy; import net.tirasa.connid.bundles.ldap.sync.sunds.SunDSChangeLogSyncStrategy; +import org.identityconnectors.common.logging.Log; import org.identityconnectors.common.security.GuardedString; import org.identityconnectors.framework.common.objects.Attribute; import org.identityconnectors.framework.common.objects.AttributeDelta; @@ -63,6 +65,8 @@ public class LdapConnector implements AuthenticateOp, ResolveUsernameOp, CreateOp, UpdateOp, UpdateDeltaOp, UpdateAttributeValuesOp, DeleteOp, SyncOp { + private static final Log LOG = Log.getLog(LdapConnector.class); + /** * The configuration for this connector instance. */ @@ -73,6 +77,8 @@ public class LdapConnector implements */ private LdapConnection conn; + private LdapSyncStrategy syncStrategy; + @Override public Configuration getConfiguration() { return config; @@ -82,6 +88,15 @@ public Configuration getConfiguration() { public void init(Configuration cfg) { config = (LdapConfiguration) cfg; conn = new LdapConnection(config); + + Class syncStrategyClass = config.getSyncStrategyClass(); + try { + syncStrategy = syncStrategyClass.getConstructor(LdapConnection.class).newInstance(conn); + } catch (Exception e) { + LOG.error(e, "Could not instantiate the configured {0} implementation, reverting to {1}", + LdapSyncStrategy.class.getName(), SunDSChangeLogSyncStrategy.class.getName()); + syncStrategy = new SunDSChangeLogSyncStrategy(conn); + } } @Override @@ -192,9 +207,8 @@ public Uid removeAttributeValues( } @Override - public SyncToken getLatestSyncToken( - final ObjectClass oclass) { - return new SunDSChangeLogSyncStrategy(conn, oclass).getLatestSyncToken(); + public SyncToken getLatestSyncToken(final ObjectClass oclass) { + return syncStrategy.getLatestSyncToken(oclass); } @Override @@ -203,6 +217,6 @@ public void sync( final SyncToken token, final SyncResultsHandler handler, final OperationOptions options) { - new SunDSChangeLogSyncStrategy(conn, oclass).sync(token, handler, options); + syncStrategy.sync(token, handler, options, oclass); } } diff --git a/src/main/java/net/tirasa/connid/bundles/ldap/sync/LdapSyncStrategy.java b/src/main/java/net/tirasa/connid/bundles/ldap/sync/LdapSyncStrategy.java index 8dd37aa..d7da72a 100644 --- a/src/main/java/net/tirasa/connid/bundles/ldap/sync/LdapSyncStrategy.java +++ b/src/main/java/net/tirasa/connid/bundles/ldap/sync/LdapSyncStrategy.java @@ -1,18 +1,18 @@ -/* +/* * ==================== * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * + * * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. - * + * * The contents of this file are subject to the terms of the Common Development * and Distribution License("CDDL") (the "License"). You may not use this file * except in compliance with the License. - * + * * You can obtain a copy of the License at * http://opensource.org/licenses/cddl1.php * See the License for the specific language governing permissions and limitations * under the License. - * + * * When distributing the Covered Code, include this CDDL Header Notice in each file * and include the License file at http://opensource.org/licenses/cddl1.php. * If applicable, add the following below this CDDL Header, with the fields @@ -23,13 +23,14 @@ */ package net.tirasa.connid.bundles.ldap.sync; +import org.identityconnectors.framework.common.objects.ObjectClass; import org.identityconnectors.framework.common.objects.OperationOptions; import org.identityconnectors.framework.common.objects.SyncResultsHandler; import org.identityconnectors.framework.common.objects.SyncToken; public interface LdapSyncStrategy { - void sync(SyncToken token, SyncResultsHandler handler, OperationOptions options); + void sync(SyncToken token, SyncResultsHandler handler, OperationOptions options, ObjectClass oclass); - SyncToken getLatestSyncToken(); + SyncToken getLatestSyncToken(ObjectClass oclass); } diff --git a/src/main/java/net/tirasa/connid/bundles/ldap/sync/sunds/SunDSChangeLogSyncStrategy.java b/src/main/java/net/tirasa/connid/bundles/ldap/sync/sunds/SunDSChangeLogSyncStrategy.java index 66d8eda..42b1a36 100644 --- a/src/main/java/net/tirasa/connid/bundles/ldap/sync/sunds/SunDSChangeLogSyncStrategy.java +++ b/src/main/java/net/tirasa/connid/bundles/ldap/sync/sunds/SunDSChangeLogSyncStrategy.java @@ -97,8 +97,6 @@ public class SunDSChangeLogSyncStrategy implements LdapSyncStrategy { private final LdapConnection conn; - private final ObjectClass oclass; - private ChangeLogAttributes changeLogAttrs; private Set oclassesToSync; @@ -118,13 +116,12 @@ public class SunDSChangeLogSyncStrategy implements LdapSyncStrategy { LDAP_DN_ATTRIBUTES.add("cn"); } - public SunDSChangeLogSyncStrategy(LdapConnection conn, ObjectClass oclass) { + public SunDSChangeLogSyncStrategy(LdapConnection conn) { this.conn = conn; - this.oclass = oclass; } @Override - public SyncToken getLatestSyncToken() { + public SyncToken getLatestSyncToken(ObjectClass oclass) { return new SyncToken(getChangeLogAttributes().getLastChangeNumber()); } @@ -132,8 +129,8 @@ public SyncToken getLatestSyncToken() { public void sync( final SyncToken token, final SyncResultsHandler handler, - final OperationOptions options) { - + final OperationOptions options, + final ObjectClass oclass) { String context = getChangeLogAttributes().getChangeLogContext(); final String changeNumberAttr = getChangeNumberAttribute(); SearchControls controls = LdapInternalSearch.createDefaultSearchControls(); @@ -174,7 +171,7 @@ public void sync( currentChangeNumber[0] = changeNumber; } - final SyncDelta delta = createSyncDelta(entry, changeNumber, options.getAttributesToGet()); + final SyncDelta delta = createSyncDelta(entry, changeNumber, options.getAttributesToGet(), oclass); if (delta != null) { return handler.handle(delta); @@ -194,7 +191,8 @@ public void sync( private SyncDelta createSyncDelta( final LdapEntry changeLogEntry, final int changeNumber, - final String[] attrsToGetOption) throws InvalidNameException { + final String[] attrsToGetOption, + ObjectClass oclass) throws InvalidNameException { LOG.ok("Attempting to create sync delta for log entry {0}", changeNumber); @@ -298,10 +296,9 @@ private SyncDelta createSyncDelta( // If objectClass is not in the list of attributes to get, prepare to remove it later. boolean removeObjectClass = attrsToGet.add("objectClass"); - LdapFilter filter = LdapFilter.forEntryDN(newTargetDN).withNativeFilter(getModifiedEntrySearchFilter()); + LdapFilter filter = LdapFilter.forEntryDN(newTargetDN).withNativeFilter(getModifiedEntrySearchFilter(oclass)); - ConnectorObject object = LdapSearches.findObject(conn, oclass, filter, - attrsToGet.toArray(new String[attrsToGet.size()])); + ConnectorObject object = LdapSearches.findObject(conn, oclass, filter, attrsToGet.toArray(new String[0])); if (object == null) { LOG.ok("Skipping entry because the modified entry is missing, " @@ -452,7 +449,7 @@ private SyncDeltaType getSyncDeltaType(final String changeType) { return SyncDeltaType.CREATE_OR_UPDATE; } - private String getModifiedEntrySearchFilter() { + private String getModifiedEntrySearchFilter(ObjectClass oclass) { if (oclass.equals(ObjectClass.ACCOUNT)) { return conn.getConfiguration().getAccountSynchronizationFilter(); } @@ -609,10 +606,8 @@ ChangeLogAttributes getChangeLogAttributes() { Attributes attrs = conn.getInitialContext().getAttributes("", new String[] { "changeLog", "firstChangeNumber", "lastChangeNumber" }); String changeLog = getStringAttrValue(attrs, "changeLog"); - String firstChangeNumber = getStringAttrValue(attrs, - "firstChangeNumber"); - String lastChangeNumber = getStringAttrValue(attrs, - "lastChangeNumber"); + String firstChangeNumber = getStringAttrValue(attrs, "firstChangeNumber"); + String lastChangeNumber = getStringAttrValue(attrs, "lastChangeNumber"); if (changeLog == null || firstChangeNumber == null | lastChangeNumber == null) { String error = "Unable to locate the replication change log.\n" + "From the admin console please verify that the " diff --git a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages.properties b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages.properties index 6d6d5f0..8d7e4f7 100644 --- a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages.properties +++ b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages.properties @@ -116,6 +116,8 @@ connectTimeout.display=Connection Timeout (Milliseconds) connectTimeout.help=Time to wait when opening new server connections. Value of 0 means the TCP network timeout will be used, which may be several minutes. Value less than 0 means there is no limit. readTimeout.display=Read Timeout (Milliseconds) readTimeout.help=Time to wait for a response to be received. If there is no response within the specified time period, the read attempt will be aborted. Value 0 or less than 0 means there is no limit. +syncStrategy.display=Sync strategy class +syncStrategy.help=A class implementing LdapSyncStrategy to be used for sync operations # Configuration properties validation. host.notBlank=The host cannot be blank @@ -158,6 +160,10 @@ groupSearchScope.invalidScope=The group search scope was invalid, it must be one anyObjectSearchScope.notBlank=The any object search scope cannot be blank anyObjectSearchScope.invalidScope=The any object search scope was invalid, it must be one of 'object', 'onelevel' or 'subtree' +syncStrategy.notBlank=The sync strategy cannot be blank +syncStrategy.classNotFound=The specified class cannot be found +syncStrategy.classNotSyncStrategy=The specified class does not implement LdapSyncStrategy + entryNotFound=Entry "{0}" not found readingPasswordsNotSupported=Returning passwords from a search operation is not supported @@ -174,4 +180,4 @@ gidAttribute.display=Uid Attribute for groups gidAttribute.help=The name of the LDAP attribute which is mapped to the Uid attribute for groups. Default is "entryUUID". gidAttribute.notBlank=The attribute to map to Gid cannot be blank addPrincipalToNewGroups.display=Automatically add the configured principal as first member of a new group -addPrincipalToNewGroups.help=When enabled, the configured principal is added as first member of a new group. Default is "false". +addPrincipalToNewGroups.help=When enabled, the configured principal is added as first member of a new group. Default is "false". \ No newline at end of file diff --git a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_de.properties b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_de.properties index 90e8c3e..f573b84 100644 --- a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_de.properties +++ b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_de.properties @@ -88,6 +88,8 @@ passwordDecryptionInitializationVector.display=Initialisierungsvektor zur Passwo passwordDecryptionInitializationVector.help=Der Initialisierungsvektor, der beim Ausf\u00fchren einer Passwortsynchronisation verwendet wird, um Passw\u00f6rter zu entschl\u00fcsseln. retrievePasswordsWithSearch.display=Retrieve passwords with search retrievePasswordsWithSearch.help=Whether to retrieve user passwords when searching. The default is "false". +syncStrategy.display=Sync strategy class +syncStrategy.help=A class implementing LdapSyncStrategy to be used for sync operations statusManagementClass.display=Status management class statusManagementClass.help=Class to be used to manage enabled/disabled status. If no class is specified then identity status management won't be possible. @@ -141,6 +143,10 @@ groupSearchScope.invalidScope=The group search scope was invalid, it must be one anyObjectSearchScope.notBlank=The any object search scope cannot be blank anyObjectSearchScope.invalidScope=The any object search scope was invalid, it must be one of 'object', 'onelevel' or 'subtree' +syncStrategy.notBlank=The sync strategy cannot be blank +syncStrategy.classNotFound=The specified class cannot be found +syncStrategy.classNotSyncStrategy=The specified class does not implement LdapSyncStrategy + entryNotFound=Eintrag "{0}" nicht gefunden readingPasswordsNotSupported=Die Wiedergabe von Passw\u00f6rtern \u00fcber einen Suchvorgang wird nicht unterst\u00fctzt diff --git a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_es.properties b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_es.properties index 743107e..f245235 100644 --- a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_es.properties +++ b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_es.properties @@ -88,6 +88,8 @@ passwordDecryptionInitializationVector.display=Vector de inicializaci\u00f3n de passwordDecryptionInitializationVector.help=El vector de inicializaci\u00f3n que se usa para descifrar las contrase\u00f1as al realizar sincronizaci\u00f3n de contrase\u00f1as. retrievePasswordsWithSearch.display=Retrieve passwords with search retrievePasswordsWithSearch.help=Whether to retrieve user passwords when searching. The default is "false". +syncStrategy.display=Sync strategy class +syncStrategy.help=A class implementing LdapSyncStrategy to be used for sync operations # Configuration properties validation. host.notBlank=El host no puede quedar en blanco. @@ -138,6 +140,10 @@ groupSearchScope.invalidScope=The group search scope was invalid, it must be one anyObjectSearchScope.notBlank=The any object search scope cannot be blank anyObjectSearchScope.invalidScope=The any object search scope was invalid, it must be one of 'object', 'onelevel' or 'subtree' +syncStrategy.notBlank=The sync strategy cannot be blank +syncStrategy.classNotFound=The specified class cannot be found +syncStrategy.classNotSyncStrategy=The specified class does not implement LdapSyncStrategy + entryNotFound=Entrada "{0}" no encontrada readingPasswordsNotSupported=Una operaci\u00f3n de b\u00fasqueda no puede devolver contrase\u00f1as diff --git a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_fr.properties b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_fr.properties index a1ccfba..27f2c0e 100644 --- a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_fr.properties +++ b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_fr.properties @@ -88,6 +88,8 @@ passwordDecryptionInitializationVector.display=Vecteur d\u2019initialisation du passwordDecryptionInitializationVector.help=Vecteur d\u2019initialisation utilis\u00e9 pour d\u00e9chiffrer les mots de passe lors de la synchronisation de ces derniers. retrievePasswordsWithSearch.display=Retrieve passwords with search retrievePasswordsWithSearch.help=Whether to retrieve user passwords when searching. The default is "false". +syncStrategy.display=Sync strategy class +syncStrategy.help=A class implementing LdapSyncStrategy to be used for sync operations # Configuration properties validation. host.notBlank=L\u2019h\u00f4te doit \u00eatre sp\u00e9cifi\u00e9. @@ -138,6 +140,10 @@ groupSearchScope.invalidScope=The group search scope was invalid, it must be one anyObjectSearchScope.notBlank=The any object search scope cannot be blank anyObjectSearchScope.invalidScope=The any object search scope was invalid, it must be one of 'object', 'onelevel' or 'subtree' +syncStrategy.notBlank=The sync strategy cannot be blank +syncStrategy.classNotFound=The specified class cannot be found +syncStrategy.classNotSyncStrategy=The specified class does not implement LdapSyncStrategy + entryNotFound=L\u2019entr\u00e9e \u2019{0}\u2019 est introuvable. readingPasswordsNotSupported=Le renvoi de mots de passe \u00e0 partir d\u2019une op\u00e9ration de recherche n\u2019est pas pris en charge. diff --git a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_it.properties b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_it.properties index 531f548..d21beda 100644 --- a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_it.properties +++ b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_it.properties @@ -88,6 +88,8 @@ passwordDecryptionInitializationVector.display=Vettore di inizializzazione decri passwordDecryptionInitializationVector.help=Il vettore di inizializzazione da usare per decrittare le password durante la loro sincronizzazione. retrievePasswordsWithSearch.display=Lettura password in ricerca retrievePasswordsWithSearch.help=Se l\u2019opzione \u00e8 vera, il connettore recuperer\u00e0 i valori delle password durante la ricerca; l\u2019impostazione predefinita \u00c3\u00a8 falsa. +syncStrategy.display=Sync strategy class +syncStrategy.help=A class implementing LdapSyncStrategy to be used for sync operations # Configuration properties validation. host.notBlank=L\u2019host non pu\u00f2 essere vuoto @@ -138,6 +140,10 @@ groupSearchScope.invalidScope=The group search scope was invalid, it must be one anyObjectSearchScope.notBlank=The any object search scope cannot be blank anyObjectSearchScope.invalidScope=The any object search scope was invalid, it must be one of 'object', 'onelevel' or 'subtree' +syncStrategy.notBlank=The sync strategy cannot be blank +syncStrategy.classNotFound=The specified class cannot be found +syncStrategy.classNotSyncStrategy=The specified class does not implement LdapSyncStrategy + entryNotFound=Voce "{0}" non trovata readingPasswordsNotSupported=Non \u00e8 possibile restituire le password in un\u2019operazione di ricerca diff --git a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_ja.properties b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_ja.properties index 8d69a09..fd654db 100644 --- a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_ja.properties +++ b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_ja.properties @@ -88,6 +88,8 @@ passwordDecryptionInitializationVector.display=\u30d1\u30b9\u30ef\u30fc\u30c9\u5 passwordDecryptionInitializationVector.help=\u30d1\u30b9\u30ef\u30fc\u30c9\u540c\u671f\u3092\u5b9f\u884c\u3059\u308b\u3068\u304d\u306b\u3001\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5fa9\u53f7\u5316\u3059\u308b\u305f\u3081\u306e\u521d\u671f\u5316\u30d9\u30af\u30c8\u30eb\u3002 retrievePasswordsWithSearch.display=Retrieve passwords with search retrievePasswordsWithSearch.help=Whether to retrieve user passwords when searching. The default is "false". +syncStrategy.display=Sync strategy class +syncStrategy.help=A class implementing LdapSyncStrategy to be used for sync operations # Configuration properties validation. host.notBlank=\u30db\u30b9\u30c8\u306f\u7a7a\u306b\u3067\u304d\u307e\u305b\u3093 @@ -138,6 +140,10 @@ groupSearchScope.invalidScope=The group search scope was invalid, it must be one anyObjectSearchScope.notBlank=The any object search scope cannot be blank anyObjectSearchScope.invalidScope=The any object search scope was invalid, it must be one of 'object', 'onelevel' or 'subtree' +syncStrategy.notBlank=The sync strategy cannot be blank +syncStrategy.classNotFound=The specified class cannot be found +syncStrategy.classNotSyncStrategy=The specified class does not implement LdapSyncStrategy + entryNotFound=\u30a8\u30f3\u30c8\u30ea "{0}" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 readingPasswordsNotSupported=\u691c\u7d22\u51e6\u7406\u304b\u3089\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u8fd4\u3059\u64cd\u4f5c\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093 diff --git a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_ko.properties b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_ko.properties index 58e42ed..15812fc 100644 --- a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_ko.properties +++ b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_ko.properties @@ -88,6 +88,8 @@ passwordDecryptionInitializationVector.display=\ube44\ubc00\ubc88\ud638 \ud574\u passwordDecryptionInitializationVector.help=\ube44\ubc00\ubc88\ud638 \ub3d9\uae30\ud654\ub97c \uc218\ud589\ud560 \ub54c \ube44\ubc00\ubc88\ud638\ub97c \ud574\ub3c5\ud558\ub294 \ub370 \uc0ac\uc6a9\ud560 \ucd08\uae30\ud654 \ubca1\ud130\uc785\ub2c8\ub2e4. retrievePasswordsWithSearch.display=Retrieve passwords with search retrievePasswordsWithSearch.help=Whether to retrieve user passwords when searching. The default is "false". +syncStrategy.display=Sync strategy class +syncStrategy.help=A class implementing LdapSyncStrategy to be used for sync operations # Configuration properties validation. host.notBlank=\ud638\uc2a4\ud2b8\ub294 \ube44\uc6cc \ub458 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. @@ -138,6 +140,10 @@ groupSearchScope.invalidScope=The group search scope was invalid, it must be one anyObjectSearchScope.notBlank=The any object search scope cannot be blank anyObjectSearchScope.invalidScope=The any object search scope was invalid, it must be one of 'object', 'onelevel' or 'subtree' +syncStrategy.notBlank=The sync strategy cannot be blank +syncStrategy.classNotFound=The specified class cannot be found +syncStrategy.classNotSyncStrategy=The specified class does not implement LdapSyncStrategy + entryNotFound="{0}" \ud56d\ubaa9\uc744 \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. readingPasswordsNotSupported=\uac80\uc0c9 \uc791\uc5c5\uc5d0\uc11c \ube44\ubc00\ubc88\ud638\ub294 \ubc18\ud658\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4. diff --git a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_pt.properties b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_pt.properties index 52e51c8..229b47c 100644 --- a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_pt.properties +++ b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_pt.properties @@ -88,6 +88,8 @@ passwordDecryptionInitializationVector.display=Vetor de inicializa\u00e7\u00e3o passwordDecryptionInitializationVector.help=O vetor de inicializa\u00e7\u00e3o com o qual descriptografar senhas durante a sincroniza\u00e7\u00e3o de senhas. retrievePasswordsWithSearch.display=Retrieve passwords with search retrievePasswordsWithSearch.help=Whether to retrieve user passwords when searching. The default is "false". +syncStrategy.display=Sync strategy class +syncStrategy.help=A class implementing LdapSyncStrategy to be used for sync operations # Configuration properties validation. host.notBlank=O host n\u00e3o pode ficar em branco @@ -138,6 +140,10 @@ groupSearchScope.invalidScope=The group search scope was invalid, it must be one anyObjectSearchScope.notBlank=The any object search scope cannot be blank anyObjectSearchScope.invalidScope=The any object search scope was invalid, it must be one of 'object', 'onelevel' or 'subtree' +syncStrategy.notBlank=The sync strategy cannot be blank +syncStrategy.classNotFound=The specified class cannot be found +syncStrategy.classNotSyncStrategy=The specified class does not implement LdapSyncStrategy + entryNotFound=A entrada "{0}" n\u00e3o foi encontrada readingPasswordsNotSupported=N\u00e3o existe suporte para o retorno de senhas de uma opera\u00e7\u00e3o de pesquisa diff --git a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_zh.properties b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_zh.properties index d24bb36..a72702d 100644 --- a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_zh.properties +++ b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_zh.properties @@ -88,6 +88,8 @@ passwordDecryptionInitializationVector.display=\u5bc6\u7801\u89e3\u5bc6\u521d\u5 passwordDecryptionInitializationVector.help=\u5728\u6267\u884c\u5bc6\u7801\u540c\u6b65\u65f6\u7528\u4e8e\u5bf9\u5bc6\u7801\u8fdb\u884c\u89e3\u5bc6\u7684\u521d\u59cb\u5316\u5411\u91cf\u3002 retrievePasswordsWithSearch.display=Retrieve passwords with search retrievePasswordsWithSearch.help=Whether to retrieve user passwords when searching. The default is "false". +syncStrategy.display=Sync strategy class +syncStrategy.help=A class implementing LdapSyncStrategy to be used for sync operations # Configuration properties validation. host.notBlank=\u4e3b\u673a\u4e0d\u80fd\u4e3a\u7a7a @@ -138,6 +140,10 @@ groupSearchScope.invalidScope=The group search scope was invalid, it must be one anyObjectSearchScope.notBlank=The any object search scope cannot be blank anyObjectSearchScope.invalidScope=The any object search scope was invalid, it must be one of 'object', 'onelevel' or 'subtree' +syncStrategy.notBlank=The sync strategy cannot be blank +syncStrategy.classNotFound=The specified class cannot be found +syncStrategy.classNotSyncStrategy=The specified class does not implement LdapSyncStrategy + entryNotFound=\u627e\u4e0d\u5230\u6761\u76ee\u201c{0}\u201d readingPasswordsNotSupported=\u4e0d\u652f\u6301\u4ece\u641c\u7d22\u64cd\u4f5c\u8fd4\u56de\u5bc6\u7801 diff --git a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_zh_TW.properties b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_zh_TW.properties index e951738..dd8f677 100644 --- a/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_zh_TW.properties +++ b/src/main/resources/net/tirasa/connid/bundles/ldap/Messages_zh_TW.properties @@ -103,6 +103,8 @@ passwordDecryptionInitializationVector.display=\u5bc6\u78bc\u89e3\u5bc6\u521d\u5 passwordDecryptionInitializationVector.help=\u57f7\u884c\u5bc6\u78bc\u540c\u6b65\u6642\uff0c\u7528\u4ee5\u89e3\u5bc6\u5bc6\u78bc\u7684\u521d\u59cb\u5316\u5411\u91cf\u3002 retrievePasswordsWithSearch.display=Retrieve passwords with search retrievePasswordsWithSearch.help=Whether to retrieve user passwords when searching. The default is "false". +syncStrategy.display=Sync strategy class +syncStrategy.help=A class implementing LdapSyncStrategy to be used for sync operations # Configuration properties validation. host.notBlank=\u4e3b\u6a5f\u4e0d\u53ef\u70ba\u7a7a\u767d @@ -145,6 +147,10 @@ groupSearchScope.invalidScope=The group search scope was invalid, it must be one anyObjectSearchScope.notBlank=The any object search scope cannot be blank anyObjectSearchScope.invalidScope=The any object search scope was invalid, it must be one of 'object', 'onelevel' or 'subtree' +syncStrategy.notBlank=The sync strategy cannot be blank +syncStrategy.classNotFound=The specified class cannot be found +syncStrategy.classNotSyncStrategy=The specified class does not implement LdapSyncStrategy + entryNotFound=\u627e\u4e0d\u5230\u9805\u76ee\u300c{0}\u300d readingPasswordsNotSupported=\u4e0d\u652f\u63f4\u5f9e\u641c\u5c0b\u4f5c\u696d\u50b3\u56de\u5bc6\u78bc diff --git a/src/test/java/net/tirasa/connid/bundles/ldap/LdapConfigurationTests.java b/src/test/java/net/tirasa/connid/bundles/ldap/LdapConfigurationTests.java index 060e6df..7f9692c 100644 --- a/src/test/java/net/tirasa/connid/bundles/ldap/LdapConfigurationTests.java +++ b/src/test/java/net/tirasa/connid/bundles/ldap/LdapConfigurationTests.java @@ -355,6 +355,7 @@ public void defaultValues() { assertEquals(OperationOptions.SCOPE_SUBTREE, config.getGroupSearchScope()); assertEquals(OperationOptions.SCOPE_SUBTREE, config.getAnyObjectSearchScope()); assertNull(config.getAnyObjectSearchFilter()); + assertEquals("net.tirasa.connid.bundles.ldap.sync.sunds.SunDSChangeLogSyncStrategy", config.getSyncStrategy()); } @Test @@ -423,6 +424,42 @@ public void anyObjectSearchScopeValid() { assertDoesNotThrow(() -> config.setAnyObjectSearchScope("subtree")); } + @Test + public void syncStrategyNotNull() { + config.setSyncStrategy((String) null); + assertThrows(ConfigurationException.class, () -> config.validate()); + } + + @Test + public void syncStrategyNotBlank() { + config.setSyncStrategy(""); + assertThrows(ConfigurationException.class, () -> config.validate()); + } + + @Test + public void syncStrategyClassDoesNotExist() { + config.setSyncStrategy("net.tirasa.connid.bundles.ldap.sync.LdapSyncStrategyThatDoesNotExist"); + assertThrows(ConfigurationException.class, () -> config.validate()); + } + + @Test + public void syncStrategyClassIsNotSyncStrategy() { + config.setSyncStrategy("net.tirasa.connid.bundles.ldap.modify.LdapCreate"); + assertThrows(ConfigurationException.class, () -> config.validate()); + } + + @Test + public void syncStrategyClassIsNotInterface() { + config.setSyncStrategy("net.tirasa.connid.bundles.ldap.sync.LdapSyncStrategy"); + assertThrows(ConfigurationException.class, () -> config.validate()); + } + + @Test + public void syncStrategyValid() { + config.setSyncStrategy("net.tirasa.connid.bundles.ldap.sync.sunds.SunDSChangeLogSyncStrategy"); + assertDoesNotThrow(() -> config.validate()); + } + private static void assertCanValidate(LdapConfiguration config) { try { config.validate();