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):
    <validate value here>

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 <abokovoy@redhat.com>
Signed-off-by: Peter Keresztes Schmidt <carbenium@outlook.com>
Reviewed-By: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
This commit is contained in:
Alexander Bokovoy
2020-06-09 10:26:33 +03:00
committed by Rob Crittenden
parent afcb06006c
commit 172e4b9770

View File

@@ -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: