We had originally decided to provide defaults on the server side so that
they could be part of a global config for the admin. However, on further
reflection, only certain defaults really make sense given the
limitations of Google Authenticator. Similarly, other defaults may be
token specific.

Attempting to handle defaults on the server side also makes both the UI
and the generated documentation unclear.

NOTE: this patch changes an existing API. VERSION says that we should
bump the major version in this case. But we haven't actually released
this API yet. Please advise.
>From a9b125fb6a9c666ef34d52ea6ffcc62b4110c8b4 Mon Sep 17 00:00:00 2001
From: Nathaniel McCallum <npmccal...@redhat.com>
Date: Thu, 20 Feb 2014 13:21:32 -0500
Subject: [PATCH] Rework how otptoken defaults are handled

We had originally decided to provide defaults on the server side so that they
could be part of a global config for the admin. However, on further reflection,
only certain defaults really make sense given the limitations of Google
Authenticator. Similarly, other defaults may be token specific.

Attempting to handle defaults on the server side also makes both the UI and
the generated documentation unclear.
---
 API.txt                    | 46 ++++++++++++++++----------------
 ipalib/plugins/otptoken.py | 65 +++++++++++++++++++++++-----------------------
 2 files changed, 56 insertions(+), 55 deletions(-)

diff --git a/API.txt b/API.txt
index 504a60ff31686cfa828c3a8f17debd6dad3bb60d..9898da918b3f61d39648baa77d7fe5d8306c2375 100644
--- a/API.txt
+++ b/API.txt
@@ -2221,34 +2221,34 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Output('value', <type 'unicode'>, None)
 command: otptoken_add
 args: 1,21,3
-arg: Str('ipatokenuniqueid', attribute=True, cli_name='id', multivalue=False, primary_key=True, required=False)
+arg: Str('ipatokenuniqueid', attribute=True, autofill=True, cli_name='id', multivalue=False, primary_key=True, required=False)
 option: Str('addattr*', cli_name='addattr', exclude='webui')
 option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
 option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=False)
 option: Bool('ipatokendisabled', attribute=True, cli_name='disabled', multivalue=False, required=False)
-option: Int('ipatokenhotpcounter', attribute=True, cli_name='counter', minvalue=0, multivalue=False, required=False)
-option: Str('ipatokenmodel', attribute=True, cli_name='model', multivalue=False, required=False)
+option: Int('ipatokenhotpcounter', attribute=True, autofill=True, cli_name='counter', default=0, minvalue=0, multivalue=False, required=False)
+option: Str('ipatokenmodel', attribute=True, autofill=True, cli_name='model', multivalue=False, required=False)
 option: Str('ipatokennotafter', attribute=True, cli_name='not_after', multivalue=False, required=False)
 option: Str('ipatokennotbefore', attribute=True, cli_name='not_before', multivalue=False, required=False)
-option: StrEnum('ipatokenotpalgorithm', attribute=True, cli_name='algo', multivalue=False, required=False, values=(u'sha1', u'sha256', u'sha384', u'sha512'))
-option: IntEnum('ipatokenotpdigits', attribute=True, cli_name='digits', multivalue=False, required=False, values=(6, 8))
-option: OTPTokenKey('ipatokenotpkey', attribute=True, cli_name='key', multivalue=False, required=False)
+option: StrEnum('ipatokenotpalgorithm', attribute=True, autofill=True, cli_name='algo', default=u'sha1', multivalue=False, required=False, values=(u'sha1', u'sha256', u'sha384', u'sha512'))
+option: IntEnum('ipatokenotpdigits', attribute=True, autofill=True, cli_name='digits', default=6, multivalue=False, required=False, values=(6, 8))
+option: OTPTokenKey('ipatokenotpkey', attribute=True, autofill=True, cli_name='key', multivalue=False, required=False)
 option: Str('ipatokenowner', attribute=True, cli_name='owner', multivalue=False, required=False)
-option: Str('ipatokenserial', attribute=True, cli_name='serial', multivalue=False, required=False)
-option: Int('ipatokentotpclockoffset', attribute=True, cli_name='offset', multivalue=False, required=False)
-option: Int('ipatokentotptimestep', attribute=True, cli_name='interval', minvalue=5, multivalue=False, required=False)
-option: Str('ipatokenvendor', attribute=True, cli_name='vendor', multivalue=False, required=False)
+option: Str('ipatokenserial', attribute=True, autofill=True, cli_name='serial', multivalue=False, required=False)
+option: Int('ipatokentotpclockoffset', attribute=True, autofill=True, cli_name='offset', default=0, multivalue=False, required=False)
+option: Int('ipatokentotptimestep', attribute=True, autofill=True, cli_name='interval', default=30, minvalue=5, multivalue=False, required=False)
+option: Str('ipatokenvendor', attribute=True, autofill=True, cli_name='vendor', default=u'FreeIPA', multivalue=False, required=False)
 option: Flag('qrcode?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Str('setattr*', cli_name='setattr', exclude='webui')
-option: StrEnum('type', attribute=False, cli_name='type', multivalue=False, required=False, values=(u'totp', u'hotp'))
+option: StrEnum('type', attribute=False, autofill=True, cli_name='type', default=u'totp', multivalue=False, required=False, values=(u'totp', u'hotp'))
 option: Str('version?', exclude='webui')
 output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Output('value', <type 'unicode'>, None)
 command: otptoken_del
 args: 1,2,3
-arg: Str('ipatokenuniqueid', attribute=True, cli_name='id', multivalue=True, primary_key=True, query=True, required=True)
+arg: Str('ipatokenuniqueid', attribute=True, autofill=True, cli_name='id', multivalue=True, primary_key=True, query=True, required=True)
 option: Flag('continue', autofill=True, cli_name='continue', default=False)
 option: Str('version?', exclude='webui')
 output: Output('result', <type 'dict'>, None)
@@ -2260,23 +2260,23 @@ arg: Str('criteria?', noextrawhitespace=False)
 option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
 option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, query=True, required=False)
 option: Bool('ipatokendisabled', attribute=True, autofill=False, cli_name='disabled', multivalue=False, query=True, required=False)
-option: Int('ipatokenhotpcounter', attribute=True, autofill=False, cli_name='counter', minvalue=0, multivalue=False, query=True, required=False)
+option: Int('ipatokenhotpcounter', attribute=True, autofill=False, cli_name='counter', default=0, minvalue=0, multivalue=False, query=True, required=False)
 option: Str('ipatokenmodel', attribute=True, autofill=False, cli_name='model', multivalue=False, query=True, required=False)
 option: Str('ipatokennotafter', attribute=True, autofill=False, cli_name='not_after', multivalue=False, query=True, required=False)
 option: Str('ipatokennotbefore', attribute=True, autofill=False, cli_name='not_before', multivalue=False, query=True, required=False)
-option: StrEnum('ipatokenotpalgorithm', attribute=True, autofill=False, cli_name='algo', multivalue=False, query=True, required=False, values=(u'sha1', u'sha256', u'sha384', u'sha512'))
-option: IntEnum('ipatokenotpdigits', attribute=True, autofill=False, cli_name='digits', multivalue=False, query=True, required=False, values=(6, 8))
+option: StrEnum('ipatokenotpalgorithm', attribute=True, autofill=False, cli_name='algo', default=u'sha1', multivalue=False, query=True, required=False, values=(u'sha1', u'sha256', u'sha384', u'sha512'))
+option: IntEnum('ipatokenotpdigits', attribute=True, autofill=False, cli_name='digits', default=6, multivalue=False, query=True, required=False, values=(6, 8))
 option: Str('ipatokenowner', attribute=True, autofill=False, cli_name='owner', multivalue=False, query=True, required=False)
 option: Str('ipatokenserial', attribute=True, autofill=False, cli_name='serial', multivalue=False, query=True, required=False)
-option: Int('ipatokentotpclockoffset', attribute=True, autofill=False, cli_name='offset', multivalue=False, query=True, required=False)
-option: Int('ipatokentotptimestep', attribute=True, autofill=False, cli_name='interval', minvalue=5, multivalue=False, query=True, required=False)
+option: Int('ipatokentotpclockoffset', attribute=True, autofill=False, cli_name='offset', default=0, multivalue=False, query=True, required=False)
+option: Int('ipatokentotptimestep', attribute=True, autofill=False, cli_name='interval', default=30, minvalue=5, multivalue=False, query=True, required=False)
 option: Str('ipatokenuniqueid', attribute=True, autofill=False, cli_name='id', multivalue=False, primary_key=True, query=True, required=False)
-option: Str('ipatokenvendor', attribute=True, autofill=False, cli_name='vendor', multivalue=False, query=True, required=False)
+option: Str('ipatokenvendor', attribute=True, autofill=False, cli_name='vendor', default=u'FreeIPA', multivalue=False, query=True, required=False)
 option: Flag('pkey_only?', autofill=True, default=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Int('sizelimit?', autofill=False, minvalue=0)
 option: Int('timelimit?', autofill=False, minvalue=0)
-option: StrEnum('type', attribute=False, autofill=False, cli_name='type', multivalue=False, query=True, required=False, values=(u'totp', u'hotp'))
+option: StrEnum('type', attribute=False, autofill=False, cli_name='type', default=u'totp', multivalue=False, query=True, required=False, values=(u'totp', u'hotp'))
 option: Str('version?', exclude='webui')
 output: Output('count', <type 'int'>, None)
 output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None))
@@ -2284,7 +2284,7 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Output('truncated', <type 'bool'>, None)
 command: otptoken_mod
 args: 1,16,3
-arg: Str('ipatokenuniqueid', attribute=True, cli_name='id', multivalue=False, primary_key=True, query=True, required=True)
+arg: Str('ipatokenuniqueid', attribute=True, autofill=True, cli_name='id', multivalue=False, primary_key=True, query=True, required=True)
 option: Str('addattr*', cli_name='addattr', exclude='webui')
 option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
 option: Str('delattr*', cli_name='delattr', exclude='webui')
@@ -2295,9 +2295,9 @@ option: Str('ipatokennotafter', attribute=True, autofill=False, cli_name='not_af
 option: Str('ipatokennotbefore', attribute=True, autofill=False, cli_name='not_before', multivalue=False, required=False)
 option: Str('ipatokenowner', attribute=True, autofill=False, cli_name='owner', multivalue=False, required=False)
 option: Str('ipatokenserial', attribute=True, autofill=False, cli_name='serial', multivalue=False, required=False)
-option: Str('ipatokenvendor', attribute=True, autofill=False, cli_name='vendor', multivalue=False, required=False)
+option: Str('ipatokenvendor', attribute=True, autofill=False, cli_name='vendor', default=u'FreeIPA', multivalue=False, required=False)
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
-option: Str('rename', cli_name='rename', multivalue=False, primary_key=True, required=False)
+option: Str('rename', autofill=True, cli_name='rename', multivalue=False, primary_key=True, required=False)
 option: Flag('rights', autofill=True, default=False)
 option: Str('setattr*', cli_name='setattr', exclude='webui')
 option: Str('version?', exclude='webui')
@@ -2306,7 +2306,7 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Output('value', <type 'unicode'>, None)
 command: otptoken_show
 args: 1,4,3
-arg: Str('ipatokenuniqueid', attribute=True, cli_name='id', multivalue=False, primary_key=True, query=True, required=True)
+arg: Str('ipatokenuniqueid', attribute=True, autofill=True, cli_name='id', multivalue=False, primary_key=True, query=True, required=True)
 option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
 option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
 option: Flag('rights', autofill=True, default=False)
diff --git a/ipalib/plugins/otptoken.py b/ipalib/plugins/otptoken.py
index 8e76ada907c161ffc6a7e83c02d41daa5849e515..92853dec3048fd98f98f4113ef8b5874f2500919 100644
--- a/ipalib/plugins/otptoken.py
+++ b/ipalib/plugins/otptoken.py
@@ -53,7 +53,10 @@ EXAMPLES:
 
 register = Registry()
 
-TOKEN_TYPES = (u'totp', u'hotp')
+TOKEN_TYPES = {
+    u'totp': ['ipatokentotpclockoffset', 'ipatokentotptimestep'],
+    u'hotp': ['ipatokenhotpcounter']
+}
 
 # NOTE: For maximum compatibility, KEY_LENGTH % 5 == 0
 KEY_LENGTH = 10
@@ -117,12 +120,16 @@ class otptoken(LDAPObject):
         Str('ipatokenuniqueid',
             cli_name='id',
             label=_('Unique ID'),
+            default_from=lambda: unicode(uuid.uuid4()),
+            autofill=True,
             primary_key=True,
             flags=('optional_create'),
         ),
         StrEnum('type?',
             label=_('Type'),
-            values=TOKEN_TYPES,
+            default=u'totp',
+            autofill=True,
+            values=tuple(TOKEN_TYPES.keys()),
             flags=('virtual_attribute', 'no_update'),
         ),
         Str('description?',
@@ -148,23 +155,33 @@ class otptoken(LDAPObject):
         Str('ipatokenvendor?',
             cli_name='vendor',
             label=_('Vendor'),
+            default=u'FreeIPA',
+            autofill=True,
         ),
         Str('ipatokenmodel?',
             cli_name='model',
             label=_('Model'),
+            default_from=lambda type: type,
+            autofill=True,
         ),
         Str('ipatokenserial?',
             cli_name='serial',
             label=_('Serial'),
+            default_from=lambda id: id,
+            autofill=True,
         ),
         OTPTokenKey('ipatokenotpkey?',
             cli_name='key',
             label=_('Key'),
+            default_from=lambda: "".join(random.SystemRandom().sample(map(chr, range(256)), 10)),
+            autofill=True,
             flags=('no_display', 'no_update', 'no_search'),
         ),
         StrEnum('ipatokenotpalgorithm?',
             cli_name='algo',
             label=_('Algorithm'),
+            default=u'sha1',
+            autofill=True,
             flags=('no_update'),
             values=(u'sha1', u'sha256', u'sha384', u'sha512'),
         ),
@@ -172,22 +189,30 @@ class otptoken(LDAPObject):
             cli_name='digits',
             label=_('Display length'),
             values=(6, 8),
+            default=6,
+            autofill=True,
             flags=('no_update'),
         ),
         Int('ipatokentotpclockoffset?',
             cli_name='offset',
             label=_('Clock offset'),
+            default=0,
+            autofill=True,
             flags=('no_update'),
         ),
         Int('ipatokentotptimestep?',
             cli_name='interval',
             label=_('Clock interval'),
+            default=30,
+            autofill=True,
             minvalue=5,
             flags=('no_update'),
         ),
         Int('ipatokenhotpcounter?',
             cli_name='counter',
             label=_('Counter'),
+            default=0,
+            autofill=True,
             minvalue=0,
             flags=('no_update'),
         ),
@@ -208,37 +233,13 @@ class otptoken_add(LDAPCreate):
     )
 
     def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
-        # These are values we always want to write to LDAP. So if they are
-        # specified as a value that evaluates to False (i.e. None), delete them
-        # and fill in the defaults below.
-        for attr in ('ipatokentotpclockoffset', 'ipatokentotptimestep',
-                     'ipatokenotpalgorithm', 'ipatokenotpdigits',
-                     'ipatokenotpkey'):
-            if attr in entry_attrs and not entry_attrs[attr]:
-                del entry_attrs[attr]
-
-        # Set defaults. This needs to happen on the server side because we may
-        # have global configurable defaults in the near future.
-        options.setdefault('type', TOKEN_TYPES[0])
-        if entry_attrs.get('ipatokenuniqueid', None) is None:
-            entry_attrs['ipatokenuniqueid'] = str(uuid.uuid4())
-            dn = DN("ipatokenuniqueid=%s" % entry_attrs['ipatokenuniqueid'], dn)
-        entry_attrs.setdefault('ipatokenvendor', u'FreeIPA')
-        entry_attrs.setdefault('ipatokenmodel', options['type'])
-        entry_attrs.setdefault('ipatokenserial', entry_attrs['ipatokenuniqueid'])
-        entry_attrs.setdefault('ipatokenotpalgorithm', u'sha1')
-        entry_attrs.setdefault('ipatokenotpdigits', 6)
-        entry_attrs.setdefault('ipatokenotpkey',
-            "".join(map(chr, random.SystemRandom().sample(range(255), KEY_LENGTH))))
-
         # Set the object class and defaults for specific token types
-        if options['type'] == 'totp':
-            entry_attrs['objectclass'] = otptoken.object_class + ['ipatokentotp']
-            entry_attrs.setdefault('ipatokentotpclockoffset', 0)
-            entry_attrs.setdefault('ipatokentotptimestep', 30)
-        elif options['type'] == 'hotp':
-            entry_attrs['objectclass'] = otptoken.object_class + ['ipatokenhotp']
-            entry_attrs.setdefault('ipatokenhotpcounter', 0)
+        entry_attrs['objectclass'] = otptoken.object_class + ['ipatoken' + options['type']]
+        for ttype, tattrs in TOKEN_TYPES.items():
+            if ttype != options['type']:
+                for tattr in tattrs:
+                    if tattr in entry_attrs:
+                        del entry_attrs[tattr]
 
         # Resolve the user's dn
         _normalize_owner(self.api.Object.user, entry_attrs)
-- 
1.8.5.3

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

Reply via email to