Some attributes we use are IA5Strings which have a very limited character set. Add a parameter type for that so we can catch the bad type up front and give a more reasonable error message than "syntax error".

ticket 496

rob
>From d1c650311b66e822667d76f46416cc2039519f22 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Mon, 6 Dec 2010 15:09:03 -0500
Subject: [PATCH] Add new parameter type IA5Str and use this to enforce the right charset.

ticket 496
---
 install/share/60ipaconfig.ldif       |    2 +-
 ipalib/__init__.py                   |    2 +-
 ipalib/errors.py                     |   16 ++++++++++++++++
 ipalib/parameters.py                 |   19 +++++++++++++++++++
 ipalib/plugins/automount.py          |   28 ++++++++++++++--------------
 ipalib/plugins/config.py             |    8 ++++----
 ipaserver/plugins/ldap2.py           |    2 ++
 tests/test_ipalib/test_parameters.py |   23 +++++++++++++++++++++++
 8 files changed, 80 insertions(+), 20 deletions(-)

diff --git a/install/share/60ipaconfig.ldif b/install/share/60ipaconfig.ldif
index e93b55e..d7b4ebd 100644
--- a/install/share/60ipaconfig.ldif
+++ b/install/share/60ipaconfig.ldif
@@ -22,7 +22,7 @@ attributetypes: ( 2.16.840.1.113730.3.8.1.4 NAME 'ipaSearchRecordsLimit' EQUALIT
 ## ipaCustomFields - custom fields to show in the UI in addition to pre-defined ones
 attributetypes: ( 2.16.840.1.113730.3.8.1.5 NAME 'ipaCustomFields' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
 ## ipaHomesRootDir - default posix home directory root dir to use when creating new accounts
-attributetypes: ( 2.16.840.1.113730.3.8.1.6 NAME 'ipaHomesRootDir' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE)
+attributetypes: ( 2.16.840.1.113730.3.8.1.6 NAME 'ipaHomesRootDir' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE)
 ## ipaDefaultLoginShell - default posix login shell to use when creating new accounts
 attributetypes: ( 2.16.840.1.113730.3.8.1.7 NAME 'ipaDefaultLoginShell' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE)
 ## ipaDefaultPrimaryGroup - default posix primary group to assign when creating new accounts
diff --git a/ipalib/__init__.py b/ipalib/__init__.py
index 2589cf1..169b47a 100644
--- a/ipalib/__init__.py
+++ b/ipalib/__init__.py
@@ -878,7 +878,7 @@ from backend import Backend
 from frontend import Command, LocalOrRemote
 from frontend import Object, Method, Property
 from crud import Create, Retrieve, Update, Delete, Search
-from parameters import DefaultFrom, Bool, Flag, Int, Float, Bytes, Str, Password,List
+from parameters import DefaultFrom, Bool, Flag, Int, Float, Bytes, Str, IA5Str, Password,List
 from parameters import BytesEnum, StrEnum, AccessTime, File
 from errors import SkipPluginModule
 from text import _, ngettext, GettextFactory, NGettextFactory
diff --git a/ipalib/errors.py b/ipalib/errors.py
index 5b983cc..5d77bc2 100644
--- a/ipalib/errors.py
+++ b/ipalib/errors.py
@@ -1252,6 +1252,22 @@ class OnlyOneValueAllowed(ExecutionError):
     format = _('%(attr)s: Only one value allowed.')
 
 
+class InvalidSyntax(ExecutionError):
+    """
+    **4208** Raised when trying to set more than one value to single-value attributes
+
+    For example:
+
+    >> raise OnlyOneValueAllowed(attr='ipahomesrootdir')
+    Traceback (most recent call last):
+      ...
+    InvalidSyntax: ipahomesrootdir: Invalid syntax
+    """
+
+    errno = 4208
+    format = _('%(attr)s: Invalid syntax.')
+
+
 class CertificateError(ExecutionError):
     """
     **4300** Base class for Certificate execution errors (*4300 - 4399*).
diff --git a/ipalib/parameters.py b/ipalib/parameters.py
index cf4f3ba..f3b13bd 100644
--- a/ipalib/parameters.py
+++ b/ipalib/parameters.py
@@ -1278,6 +1278,25 @@ class Str(Data):
             )
 
 
+class IA5Str(Str):
+    """
+    An IA5String per RFC 4517
+    """
+
+    def __init__(self, name, *rules, **kw):
+        super(IA5Str, self).__init__(name, *rules, **kw)
+
+    def _convert_scalar(self, value, index=None):
+        if isinstance(value, basestring):
+            for i in xrange(len(value)):
+                if ord(value[i]) > 127:
+                    raise ConversionError(name=self.name, index=index,
+                        error=_('The character \'%(char)r\' is not allowed.') %
+                            dict(char=value[i],)
+                    )
+        return super(IA5Str, self)._convert_scalar(value, index)
+
+
 class Password(Str):
     """
     A parameter for passwords (stored in the ``unicode`` type).
diff --git a/ipalib/plugins/automount.py b/ipalib/plugins/automount.py
index df9b341..958b4c2 100644
--- a/ipalib/plugins/automount.py
+++ b/ipalib/plugins/automount.py
@@ -168,7 +168,7 @@ automountInformation: -ro,soft,rsize=8192,wsize=8192 nfs.example.com:/vol/arch
 """
 from ipalib import api, errors
 from ipalib import Object, Command
-from ipalib import Flag, Str
+from ipalib import Flag, Str, IA5Str
 from ipalib.plugins.baseldap import *
 from ipalib import _, ngettext
 import os
@@ -486,11 +486,11 @@ class automountmap(LDAPObject):
     default_attributes = ['automountmapname', 'description']
 
     takes_params = (
-        Str('automountmapname',
-            cli_name='map',
-            label=_('Map'),
-            doc=_('Automount map name'),
-            primary_key=True,
+        IA5Str('automountmapname',
+               cli_name='map',
+               label=_('Map'),
+               doc=_('Automount map name'),
+               primary_key=True,
         ),
         Str('description?',
             cli_name='desc',
@@ -568,15 +568,15 @@ class automountkey(LDAPObject):
     ]
 
     takes_params = (
-        Str('automountkey',
-            cli_name='key',
-            label=_('Key'),
-            doc=_('Automount key name'),
-            primary_key=True,
+        IA5Str('automountkey',
+               cli_name='key',
+               label=_('Key'),
+               doc=_('Automount key name'),
+               primary_key=True,
         ),
-        Str('automountinformation',
-            cli_name='info',
-            label=_('Mount information'),
+        IA5Str('automountinformation',
+               cli_name='info',
+               label=_('Mount information'),
         ),
         Str('description?',
             cli_name='desc',
diff --git a/ipalib/plugins/config.py b/ipalib/plugins/config.py
index 04ca332..f406233 100644
--- a/ipalib/plugins/config.py
+++ b/ipalib/plugins/config.py
@@ -64,7 +64,7 @@ Password plugin features: currently defines additional hashes that the
 """
 
 from ipalib import api
-from ipalib import Bool, Int, Str
+from ipalib import Bool, Int, Str, IA5Str
 from ipalib.plugins.baseldap import *
 from ipalib import _
 
@@ -89,7 +89,7 @@ class config(LDAPObject):
             label=_('Max username length'),
             minvalue=1,
         ),
-        Str('ipahomesrootdir?',
+        IA5Str('ipahomesrootdir?',
             cli_name='homedirectory',
             label=_('Home directory base'),
             doc=_('Default location of home directories'),
@@ -121,12 +121,12 @@ class config(LDAPObject):
             doc=_('Max. number of records to search (-1 is unlimited)'),
             minvalue=-1,
         ),
-        Str('ipausersearchfields?',
+        IA5Str('ipausersearchfields?',
             cli_name='usersearch',
             label=_('User search fields'),
             doc=_('A comma-separated list of fields to search when searching for users'),
         ),
-        Str('ipagroupsearchfields?',
+        IA5Str('ipagroupsearchfields?',
             cli_name='groupsearch',
             label='Group search fields',
             doc=_('A comma-separated list of fields to search when searching for groups'),
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index 3960600..83a7706 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -96,6 +96,8 @@ def _handle_errors(e, **kw):
         # it indicates the previous attribute was removed by another
         # update, making the oldentry stale.
         raise errors.MidairCollision()
+    except _ldap.INVALID_SYNTAX:
+        raise errors.InvalidSyntax(attr=info)
     except _ldap.OBJECT_CLASS_VIOLATION:
         raise errors.ObjectclassViolation(info=info)
     except _ldap.ADMINLIMIT_EXCEEDED:
diff --git a/tests/test_ipalib/test_parameters.py b/tests/test_ipalib/test_parameters.py
index 01cb8f7..996d9af 100644
--- a/tests/test_ipalib/test_parameters.py
+++ b/tests/test_ipalib/test_parameters.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # Authors:
 #   Jason Gerard DeRose <jder...@redhat.com>
 #
@@ -1437,3 +1438,25 @@ def test_messages():
             continue
         assert type(attr.type_error) is str
         assert attr.type_error in parameters.__messages
+
+
+class test_IA5Str(ClassChecker):
+    """
+    Test the `ipalib.parameters.IA5Str` class.
+    """
+    _cls = parameters.IA5Str
+
+    def test_convert_scalar(self):
+        """
+        Test the `ipalib.parameters.IA5Str._convert_scalar` method.
+        """
+        o = self.cls('my_str')
+        mthd = o._convert_scalar
+        for value in (u'Hello', 42, 1.2):
+            assert mthd(value) == unicode(value)
+        bad = ['Helloá']
+        for value in bad:
+            e = raises(errors.ConversionError, mthd, value)
+            assert e.name == 'my_str'
+            assert e.index is None
+            assert_equal(e.error, "The character \''\\xc3'\' is not allowed.")
-- 
1.7.2.1

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to