diff options
-rw-r--r-- | install/share/unique-attributes.ldif | 24 | ||||
-rw-r--r-- | install/updates/10-uniqueness.update | 36 | ||||
-rw-r--r-- | ipaserver/install/plugins/update_uniqueness.py | 203 |
3 files changed, 232 insertions, 31 deletions
diff --git a/install/share/unique-attributes.ldif b/install/share/unique-attributes.ldif index 0e680a0e4..ea38ac753 100644 --- a/install/share/unique-attributes.ldif +++ b/install/share/unique-attributes.ldif @@ -8,8 +8,8 @@ nsslapd-pluginPath: libattr-unique-plugin nsslapd-pluginInitfunc: NSUniqueAttr_Init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on -nsslapd-pluginarg0: krbPrincipalName -nsslapd-pluginarg1: $SUFFIX +uniqueness-attribute-name: krbPrincipalName +uniqueness-subtrees: $SUFFIX nsslapd-plugin-depends-on-type: database nsslapd-pluginId: NSUniqueAttr nsslapd-pluginVersion: 1.1.0 @@ -26,8 +26,8 @@ nsslapd-pluginPath: libattr-unique-plugin nsslapd-pluginInitfunc: NSUniqueAttr_Init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on -nsslapd-pluginarg0: krbCanonicalName -nsslapd-pluginarg1: $SUFFIX +uniqueness-attribute-name: krbCanonicalName +uniqueness-subtrees: $SUFFIX nsslapd-plugin-depends-on-type: database nsslapd-pluginId: NSUniqueAttr nsslapd-pluginVersion: 1.1.0 @@ -44,8 +44,8 @@ nsslapd-pluginPath: libattr-unique-plugin nsslapd-pluginInitfunc: NSUniqueAttr_Init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on -nsslapd-pluginarg0: cn -nsslapd-pluginarg1: cn=ng,cn=alt,$SUFFIX +uniqueness-attribute-name: cn +uniqueness-subtrees: cn=ng,cn=alt,$SUFFIX nsslapd-plugin-depends-on-type: database nsslapd-pluginId: NSUniqueAttr nsslapd-pluginVersion: 1.1.0 @@ -62,8 +62,8 @@ nsslapd-pluginPath: libattr-unique-plugin nsslapd-pluginInitfunc: NSUniqueAttr_Init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on -nsslapd-pluginarg0: ipaUniqueID -nsslapd-pluginarg1: $SUFFIX +uniqueness-attribute-name: ipaUniqueID +uniqueness-subtrees: $SUFFIX nsslapd-plugin-depends-on-type: database nsslapd-pluginId: NSUniqueAttr nsslapd-pluginVersion: 1.1.0 @@ -81,8 +81,8 @@ nsslapd-pluginPath: libattr-unique-plugin nsslapd-pluginInitfunc: NSUniqueAttr_Init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on -nsslapd-pluginarg0: cn -nsslapd-pluginarg1: cn=sudorules,cn=sudo,$SUFFIX +uniqueness-attribute-name: cn +uniqueness-subtrees: cn=sudorules,cn=sudo,$SUFFIX nsslapd-plugin-depends-on-type: database nsslapd-pluginId: NSUniqueAttr nsslapd-pluginVersion: 1.1.0 @@ -97,8 +97,8 @@ nsslapd-pluginVendor: Fedora Project #nsslapd-pluginInitfunc: NSUniqueAttr_Init #nsslapd-pluginType: preoperation #nsslapd-pluginEnabled: on -#nsslapd-pluginarg0: uid -#nsslapd-pluginarg1: cn=accounts,$SUFFIX +#uniqueness-attribute-name: uid +#uniqueness-subtrees: cn=accounts,$SUFFIX #nsslapd-plugin-depends-on-type: database #nsslapd-pluginId: NSUniqueAttr #nsslapd-pluginVersion: 1.1.0 diff --git a/install/updates/10-uniqueness.update b/install/updates/10-uniqueness.update index c9641c47f..b6e2fff6d 100644 --- a/install/updates/10-uniqueness.update +++ b/install/updates/10-uniqueness.update @@ -8,8 +8,8 @@ default:nsslapd-pluginPath: libattr-unique-plugin default:nsslapd-pluginInitfunc: NSUniqueAttr_Init default:nsslapd-pluginType: preoperation default:nsslapd-pluginEnabled: on -default:nsslapd-pluginarg0: cn -default:nsslapd-pluginarg1: cn=sudorules,cn=sudo,$SUFFIX +default:uniqueness-attribute-name: cn +default:uniqueness-subtrees: cn=sudorules,cn=sudo,$SUFFIX default:nsslapd-plugin-depends-on-type: database default:nsslapd-pluginId: NSUniqueAttr default:nsslapd-pluginVersion: 1.1.0 @@ -25,8 +25,8 @@ default:nsslapd-pluginPath: libattr-unique-plugin default:nsslapd-pluginInitfunc: NSUniqueAttr_Init default:nsslapd-pluginType: preoperation default:nsslapd-pluginEnabled: on -default:nsslapd-pluginarg0: ipaCertSubject -default:nsslapd-pluginarg1: cn=certificates,cn=ipa,cn=etc,$SUFFIX +default:uniqueness-attribute-name: ipaCertSubject +default:uniqueness-subtrees: cn=certificates,cn=ipa,cn=etc,$SUFFIX default:nsslapd-plugin-depends-on-type: database default:nsslapd-pluginId: NSUniqueAttr default:nsslapd-pluginVersion: 1.1.0 @@ -42,8 +42,8 @@ default:nsslapd-pluginPath: libattr-unique-plugin default:nsslapd-pluginInitfunc: NSUniqueAttr_Init default:nsslapd-pluginType: preoperation default:nsslapd-pluginEnabled: on -default:nsslapd-pluginarg0: ipaCertIssuerSerial -default:nsslapd-pluginarg1: cn=certificates,cn=ipa,cn=etc,$SUFFIX +default:uniqueness-attribute-name: ipaCertIssuerSerial +default:uniqueness-subtrees: cn=certificates,cn=ipa,cn=etc,$SUFFIX default:nsslapd-plugin-depends-on-type: database default:nsslapd-pluginId: NSUniqueAttr default:nsslapd-pluginVersion: 1.1.0 @@ -51,26 +51,26 @@ default:nsslapd-pluginVendor: Fedora Project # uid uniqueness scopes Active/Delete containers dn: cn=attribute uniqueness,cn=plugins,cn=config -remove:nsslapd-pluginarg1:'$SUFFIX' -add:nsslapd-pluginarg1:'cn=accounts,$SUFFIX' -add:nsslapd-pluginarg2:'cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX' +remove:uniqueness-subtrees:'$SUFFIX' +add:uniqueness-subtrees:'cn=accounts,$SUFFIX' +add:uniqueness-subtrees:'cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX' remove:nsslapd-pluginenabled:off add:nsslapd-pluginenabled:on # krbPrincipalName uniqueness scopes Active/Delete containers dn: cn=krbPrincipalName uniqueness,cn=plugins,cn=config -remove:nsslapd-pluginarg1:'$SUFFIX' -add:nsslapd-pluginarg1:'cn=accounts,$SUFFIX' -add:nsslapd-pluginarg2:'cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX' +remove:uniqueness-subtrees:'$SUFFIX' +add:uniqueness-subtrees:'cn=accounts,$SUFFIX' +add:uniqueness-subtrees:'cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX' # krbCanonicalName uniqueness scopes Active/Delete containers dn: cn=krbCanonicalName uniqueness,cn=plugins,cn=config -remove:nsslapd-pluginarg1:'$SUFFIX' -add:nsslapd-pluginarg1:'cn=accounts,$SUFFIX' -add:nsslapd-pluginarg2:'cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX' +remove:uniqueness-subtrees:'$SUFFIX' +add:uniqueness-subtrees:'cn=accounts,$SUFFIX' +add:uniqueness-subtrees:'cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX' # ipaUniqueID uniqueness scopes Active/Delete containers dn: cn=ipaUniqueID uniqueness,cn=plugins,cn=config -remove:nsslapd-pluginarg1:'$SUFFIX' -add:nsslapd-pluginarg1:'cn=accounts,$SUFFIX' -add:nsslapd-pluginarg2:'cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX' +remove:uniqueness-subtrees:'$SUFFIX' +add:uniqueness-subtrees:'cn=accounts,$SUFFIX' +add:uniqueness-subtrees:'cn=deleted users,cn=accounts,cn=provisioning,$SUFFIX' diff --git a/ipaserver/install/plugins/update_uniqueness.py b/ipaserver/install/plugins/update_uniqueness.py index a1b4638d6..8769f83a1 100644 --- a/ipaserver/install/plugins/update_uniqueness.py +++ b/ipaserver/install/plugins/update_uniqueness.py @@ -18,12 +18,213 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. from ipaserver.install.plugins import MIDDLE -from ipaserver.install.plugins.baseupdate import PostUpdate +from ipaserver.install.plugins.baseupdate import PostUpdate, PreUpdate from ipalib import api, errors from ipapython.dn import DN from ipapython.ipa_log_manager import * +class update_uniqueness_plugins_to_new_syntax(PreUpdate): + """ + Migrate uniqueness plugins to new style syntax + + * OLD: * + nsslapd-pluginarg0: uid + nsslapd-pluginarg1: dc=people,dc=example,dc=com + nsslapd-pluginarg2: dc=sales, dc=example,dc=com + + or + + nsslapd-pluginarg0: attribute=uid + nsslapd-pluginarg1: markerobjectclass=organizationalUnit + nsslapd-pluginarg2: requiredobjectclass=person + + * NEW: * + uniqueness-attribute-name: uid + uniqueness-subtrees: dc=people,dc=example,dc=com + uniqueness-subtrees: dc=sales, dc=example,dc=com + uniqueness-across-all-subtrees: on + + or + + uniqueness-attribute-name: uid + uniqueness-top-entry-oc: organizationalUnit + uniqueness-subtree-entries-oc: person + """ + + plugins_dn = DN(('cn', 'plugins'), ('cn', 'config')) + + def __remove_update(self, update, key, value): + # ldapupdate uses CSV, use '' for DN value + statement = "remove:%s:'%s'" % (key, value) + update.setdefault('updates', []).append(statement) + + def __add_update(self, update, key, value): + # ldapupdate uses CSV, use '' for DN value + statement = "add:%s:'%s'" % (key, value) + update.setdefault('updates', []).append(statement) + + def __subtree_style(self, entry): + """ + old attr -> new attr + nsslapd-pluginArg0 -> uniqueness-attribute-name + nsslapd-pluginArg1..N -> uniqueness-subtrees[1..N] + """ + update = { + 'dn': entry.dn, + 'updates': [], + } + + # nsslapd-pluginArg0 -> referint-update-delay + attribute = entry.single_value['nsslapd-pluginArg0'] + if not attribute: + raise ValueError("'nsslapd-pluginArg0' not found") + self.__remove_update(update, 'nsslapd-pluginArg0', attribute) + self.__add_update(update, 'uniqueness-attribute-name', attribute) + entry['nsslapd-pluginArg0'] = None + + # nsslapd-pluginArg1..N -> uniqueness-subtrees[1..N] + for key in entry.keys(): + if key.lower().startswith('nsslapd-pluginarg'): + subtree_dn = entry.single_value[key] + if subtree_dn: + self.__remove_update(update, key, subtree_dn) + self.__add_update(update, 'uniqueness-subtrees', subtree_dn) + + return update + + def __objectclass_style(self, entry): + """ + old attr -> new attr + nsslapd-pluginArg?[attribute] -> uniqueness-attribute-name + nsslapd-pluginArg?[markerobjectclass] -> uniqueness-top-entry-oc + nsslapd-pluginArg?[requiredobjectclass](optional) + -> uniqueness-subtree-entries-oc + nsslapd-pluginArg?[others] -> ERROR: unexpected args + + Single value attributes. + """ + + update = { + 'dn': entry.dn, + 'updates': [], + } + + attribute = None + markerobjectclass = None + requiredobjectclass = None + + for key in entry.keys(): + if key.lower().startswith('nsslapd-pluginarg'): + try: + # split argument name and value + value = entry.single_value[key] + arg_name, arg_val = value.split('=', 1) + except ValueError: + # unable to split + raise ValueError("unexpected argument %s: %s" % + (key, value)) + arg_name = arg_name.lower() + if arg_name == 'attribute': + if attribute: + raise ValueError("single value argument 'attribute' " + "is specified mutliple times") + attribute = arg_val + self.__remove_update(update, key, value) + elif arg_name == 'markerobjectclass': + if markerobjectclass: + raise ValueError("single value argument " + "'markerobjectclass' " + "is specified mutliple times") + markerobjectclass = arg_val + self.__remove_update(update, key, value) + elif arg_name == 'requiredobjectclass': + if requiredobjectclass: + raise ValueError("single value argument " + "'requiredobjectclass' " + "is specified mutliple times") + requiredobjectclass = arg_val + self.__remove_update(update, key, value) + else: + raise ValueError("unexpected argument '%s: %s'" % + (key, value)) + + if not attribute: + raise ValueError("missing required argument 'attribute'") + if not markerobjectclass: + raise ValueError("missing required argument 'markerobjectclass'") + + self.__add_update(update, 'uniqueness-attribute-name', attribute) + self.__add_update(update, 'uniqueness-top-entry-oc', markerobjectclass) + + if requiredobjectclass: + # optional argument + self.__add_update(update, 'uniqueness-subtree-entries-oc', + requiredobjectclass) + + return update + + def execute(self, **options): + ldap = self.obj.backend + + old_style_plugin_search_filter = ( + "(&" + "(objectclass=nsSlapdPlugin)" + "(nsslapd-pluginId=NSUniqueAttr)" + "(nsslapd-pluginPath=libattr-unique-plugin)" + "(nsslapd-pluginarg0=*)" # only entries with old configuration + ")" + ) + + try: + entries, truncated = ldap.find_entries( + filter=old_style_plugin_search_filter, + base_dn=self.plugins_dn, + ) + except errors.NotFound: + root_logger.debug("No uniqueness plugin entries with old style " + "configuration found") + return False, False, [] + + update_list = [] + new_attributes = [ + 'uniqueness-subtree-entries-oc', + 'uniqueness-top-entry-oc', + 'uniqueness-attribute-name', + 'uniqueness-subtrees', + 'uniqueness-across-all-subtrees', + ] + + for entry in entries: + # test for mixed configuration + if any(attr in entry for attr in new_attributes): + root_logger.critical("Mixed old and new style configuration " + "for plugin %s. Plugin will not work. " + "Skipping plugin migration, please fix it " + "manually", + entry.dn) + continue + root_logger.debug("Configuration of plugin %s will be migrated " + "to new style", entry.dn) + try: + # detect which configuration was used + arg0 = entry.get('nsslapd-pluginarg0') + if '=' in arg0: + update = self.__objectclass_style(entry) + else: + update = self.__subtree_style(entry) + except ValueError as e: + root_logger.error("Unable to migrate configuration of " + "plugin %s (%s)", + entry.dn, e) + + update_list.append({entry.dn: update}) + + return False, True, update_list + +api.register(update_uniqueness_plugins_to_new_syntax) + + class update_uid_uniqueness(PostUpdate): """ Create plugin configuration to ensure uid uniqueness |