From 172e4b977048af7cdb244b52aec08a024749962e Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Tue, 9 Jun 2020 10:26:33 +0300 Subject: [PATCH] baseldap: refactor validator support in add_external_pre_callback baseldap.py:add_external_pre_callback() allows to redefine validators used to validate member names. Originally this was done to allow hostname validation and reused default validators associated with other parameter types. Provide extension of the validator callbacks to allow fine grained validation strategy. This is helpful in case we want to apply an alternative validation strategy in case default validator fails. New validators can be added to 'member_validator' registry in a similar way to how API objects are registered: from .baseldap import member_validator @member_validator(membertype='foo') def my_new_validator(ldap, dn, keys, options, value): Arguments passed to the validator are arguments passed to the add_external_pre_callback() augmented with the value to validate. Fixes: https://pagure.io/freeipa/issue/3226 Signed-off-by: Alexander Bokovoy Signed-off-by: Peter Keresztes Schmidt Reviewed-By: Christian Heimes Reviewed-By: Rob Crittenden Reviewed-By: Florence Blanc-Renaud --- ipaserver/plugins/baseldap.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/ipaserver/plugins/baseldap.py b/ipaserver/plugins/baseldap.py index c246c0c9a..d711c1ee3 100644 --- a/ipaserver/plugins/baseldap.py +++ b/ipaserver/plugins/baseldap.py @@ -36,6 +36,7 @@ from ipalib.text import _ from ipalib.util import json_serialize, validate_hostname from ipalib.capabilities import client_has_capability from ipalib.messages import add_message, SearchResultTruncated +from ipalib.plugable import Registry from ipapython.dn import DN, RDN from ipapython.version import API_VERSION @@ -331,6 +332,18 @@ external_host_param = Str('externalhost*', validate_externalhost, flags=['no_option'], ) +# Registry to store member validators called through add_external_pre_callback +# Each validator should be defined as foo(ldap, dn, keys, options, value) +# where (ldap, dn, keys, options) are part of the signature for the +# add_external_pre_callback() +member_validator = Registry() + + +# validate hostname with allowed underscore characters, non-fqdn +# hostnames are allowed +@member_validator(membertype='host') +def validate_host(ldap, dn, keys, options, hostname): + validate_hostname(hostname, check_fqdn=False, allow_underscore=True) def add_external_pre_callback(membertype, ldap, dn, keys, options): """ @@ -342,24 +355,24 @@ def add_external_pre_callback(membertype, ldap, dn, keys, options): """ assert isinstance(dn, DN) - # validate hostname with allowed underscore characters, non-fqdn - # hostnames are allowed - def validate_host(hostname): - validate_hostname(hostname, check_fqdn=False, allow_underscore=True) if options.get(membertype): - if membertype == 'host': - validator = validate_host - else: + validator = None + for cb in member_validator: + if 'membertype' in cb and cb['membertype'] == membertype: + validator = cb['plugin'] + if validator is None: param = api.Object[membertype].primary_key - def validator(value): + def generic_validator(ldap, dn, keys, options, value): value = param(value) param.validate(value) + validator = generic_validator + for value in options[membertype]: try: - validator(value) + validator(ldap, dn, keys, options, value) except errors.ValidationError as e: raise errors.ValidationError(name=membertype, error=e.error) except ValueError as e: