DNSNameParam parameter

New param type for domain names

Part of ticket:
IPA should allow internationalized domain names
https://fedorahosted.org/freeipa/ticket/3169

Reviewed-By: Jan Cholasta <jcholast@redhat.com>
This commit is contained in:
Martin Basti
2014-03-27 14:36:39 +01:00
committed by Martin Kosek
parent 9c7b0ad156
commit 64d8da21c6
3 changed files with 72 additions and 1 deletions

View File

@@ -886,7 +886,8 @@ from frontend import Command, LocalOrRemote, Updater, Advice
from frontend import Object, Method
from crud import Create, Retrieve, Update, Delete, Search
from parameters import DefaultFrom, Bool, Flag, Int, Decimal, Bytes, Str, IA5Str, Password, DNParam, DeprecatedParam
from parameters import BytesEnum, StrEnum, IntEnum, AccessTime, File, DateTime
from parameters import (BytesEnum, StrEnum, IntEnum, AccessTime, File,
DateTime, DNSNameParam)
from errors import SkipPluginModule
from text import _, ngettext, GettextFactory, NGettextFactory

View File

@@ -114,6 +114,9 @@ from constants import TYPE_ERROR, CALLABLE_ERROR, LDAP_GENERALIZED_TIME_FORMAT
from text import Gettext, FixMe
from util import json_serialize
from ipapython.dn import DN
from ipapython.dnsutil import DNSName
import dns.name
import encodings.idna
def _is_null(value):
return not value and value != 0 # NOTE: False == 0
@@ -1919,3 +1922,69 @@ def create_param(spec):
TYPE_ERROR % ('spec', (str, Param), spec, type(spec))
)
return Str(spec)
class DNSNameParam(Param):
"""
Domain name parameter type.
:only_absolute a domain name has to be absolute
(makes it absolute from unicode input)
:only_relative a domain name has to be relative
"""
type = DNSName
type_error = _('must be DNS name')
kwargs = Param.kwargs + (
('only_absolute', bool, False),
('only_relative', bool, False),
)
def __init__(self, name, *rules, **kw):
super(DNSNameParam, self).__init__(name, *rules, **kw)
if self.only_absolute and self.only_relative:
raise ValueError('%s: cannot be both absolute and relative' %
self.nice)
def _convert_scalar(self, value, index=None):
if isinstance(value, unicode):
error = None
try:
domain_name = DNSName(value)
except dns.name.BadEscape:
error = _('invalid escape code in domain name')
except dns.name.EmptyLabel:
error = _('empty DNS label')
except dns.name.NameTooLong:
error = _('domain name cannot be longer than 255 characters')
except dns.name.LabelTooLong:
error = _('DNS label cannot be longer than 63 characters')
except dns.exception.SyntaxError:
error = _('invalid domain name')
#compare if IDN normalized and original domain match
#there is N:1 mapping between unicode and IDNA names
#user should use normalized names to avoid mistakes
normalized_domain_name = encodings.idna.nameprep(value)
if value != normalized_domain_name:
error = _("domain name '%(domain)s' and normalized domain name"
" '%(normalized)s' do not match. Please use only"
" normalized domains") % {'domain': value,
'normalized': normalized_domain_name}
if error:
raise ConversionError(name=self.get_param_name(), index=index,
error=error)
value = domain_name
if self.only_absolute and not value.is_absolute():
value = value.make_absolute()
return super(DNSNameParam, self)._convert_scalar(value, index)
def _rule_only_absolute(self, _, value):
if self.only_absolute and not value.is_absolute():
return _('must be absolute')
def _rule_only_relative(self, _, value):
if self.only_relative and value.is_absolute():
return _('must be relative')

View File

@@ -87,6 +87,7 @@ class IPATypeChecker(TypeChecker):
'ipalib.parameters.Number': ['minvalue', 'maxvalue'],
'ipalib.parameters.Decimal': ['precision', 'exponential',
'numberclass'],
'ipalib.parameters.DNSNameParam': ['only_absolute', 'only_relative'],
'ipalib.plugable.API': NAMESPACE_ATTRS + LOGGING_ATTRS,
'ipalib.plugable.Plugin': ['api', 'env'] + NAMESPACE_ATTRS +
LOGGING_ATTRS,