diff options
author | Martin Basti <mbasti@redhat.com> | 2015-05-05 15:12:12 +0200 |
---|---|---|
committer | Jan Cholasta <jcholast@redhat.com> | 2015-05-11 16:08:01 +0000 |
commit | 520bbd001b68bc51a79c2b4a9684fb1c12a582cd (patch) | |
tree | 648060489458b69a3851f2cc509f786fb6b7e990 /ipaserver/install/ldapupdate.py | |
parent | 5783d0c832a430f0f3b1a9b5ba083cda934d3397 (diff) | |
download | freeipa-520bbd001b68bc51a79c2b4a9684fb1c12a582cd.tar.gz freeipa-520bbd001b68bc51a79c2b4a9684fb1c12a582cd.tar.xz freeipa-520bbd001b68bc51a79c2b4a9684fb1c12a582cd.zip |
Server Upgrade: Allow base64 encoded values
This patch allows to use base64 encoded values in update files.
Double colon ('::') must be used as separator between attribute name
and base64 encoded value.
add:attr::<base64-value>
replace:attr::<old-base64-value>::<new-base64-value>
https://fedorahosted.org/freeipa/ticket/4984
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Diffstat (limited to 'ipaserver/install/ldapupdate.py')
-rw-r--r-- | ipaserver/install/ldapupdate.py | 138 |
1 files changed, 109 insertions, 29 deletions
diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py index 58d3e72d4..2ea890efc 100644 --- a/ipaserver/install/ldapupdate.py +++ b/ipaserver/install/ldapupdate.py @@ -22,6 +22,7 @@ # TODO # save undo files? +import base64 import sys import uuid import platform @@ -106,9 +107,31 @@ def safe_output(attr, values): return ['XXXXXXX'] * len(values) else: return 'XXXXXXXX' - else: + + if values is None: + return + + is_list = type(values) in (tuple, list) + + if is_list and None in values: return values + if not is_list: + values = [values] + + try: + all(v.decode('ascii') for v in values) + except UnicodeDecodeError: + try: + values = [base64.b64encode(v) for v in values] + except TypeError: + pass + + if not is_list: + values = values[0] + return values + + class LDAPUpdate: action_keywords = ["default", "add", "remove", "only", "onlyifexist", "deleteentry", "replace", "addifnew", "addifexist"] @@ -136,18 +159,28 @@ class LDAPUpdate: all_updates = [ { 'dn': 'cn=config,dc=example,dc=com', - 'default': ['attr1':default1'], - 'updates': ['action:attr1:value1', - 'action:attr2:value2] + 'default': [ + dict(attr='attr1', value='default1'), + ], + 'updates': [ + dict(action='action', attr='attr1', value='value1'), + dict(action='replace', attr='attr2', value=['old', 'new']), + ] }, { 'dn': 'cn=bob,ou=people,dc=example,dc=com', - 'default': ['attr3':default3'], - 'updates': ['action:attr3:value3', - 'action:attr4:value4], + 'default': [ + dict(attr='attr3', value='default3'), + ], + 'updates': [ + dict(action='action', attr='attr3', value='value3'), + dict(action='action', attr='attr4', value='value4'), + } } ] + Please notice the replace action requires two values in list + The default and update lists are "dispositions" Plugins: @@ -181,11 +214,15 @@ class LDAPUpdate: Generates this list which contain the update dictionary: [ - dict( + { 'dn': 'cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com', - 'updates': ['replace:krbPwdLockoutDuration:10::600', - 'replace:krbPwdMaxFailure:3::6'] - ) + 'updates': [ + dict(action='replace', attr='krbPwdLockoutDuration', + value=['10','600']), + dict(action='replace', attr='krbPwdMaxFailure', + value=['3','6']), + ] + } ] Here is another example showing how a default entry is configured: @@ -198,13 +235,14 @@ class LDAPUpdate: This generates: [ - dict( + { 'dn': 'cn=Managed Entries,cn=etc,dc=example,dc=com', - 'default': ['objectClass:nsContainer', - 'objectClass:top', - 'cn:Managed Entries' - ] - ) + 'default': [ + dict(attr='objectClass', value='nsContainer'), + dict(attr='objectClass', value='top'), + dict(attr='cn', value='Managed Entries'), + ] + } ] Note that the variable substitution in both examples has been completed. @@ -348,13 +386,52 @@ class LDAPUpdate: raise BadSyntax, "Bad formatting on line %s:%d: %s" % (data_source_name, lcount, logical_line) attr = items[1].strip() - value = items[2].strip() + # do not strip here, we need detect '::' due to base64 encoded + # values, strip may result into fake detection + value = items[2] + + # detect base64 encoding + # value which start with ':' are base64 encoded + # decode it as a binary value + if value.startswith(':'): + value = value[1:] + binary = True + else: + binary = False + value = value.strip() + + if action == 'replace': + try: + value = value.split('::', 1) + except ValueError: + raise BadSyntax( + "Bad syntax in replace on line %s:%d: %s, needs to " + "be in the format old::new in %s" % ( + data_source_name, lcount, logical_line, value) + ) + else: + value = [value] + + if binary: + for i, v in enumerate(value): + try: + value[i] = base64.b64decode(v) + except TypeError as e: + raise BadSyntax( + "Base64 encoded value %s on line %s:%d: %s is " + "incorrect (%s)" % (v, data_source_name, + lcount, logical_line, e) + ) + + if action != 'replace': + value = value[0] if action == "default": - new_value = attr + ":" + value + new_value = {'attr': attr, 'value': value} disposition = "default" else: - new_value = action + ":" + attr + ":" + value + new_value = {'action': action, "attr": attr, + 'value': value} disposition = "updates" disposition_list = update.setdefault(disposition, []) @@ -520,7 +597,9 @@ class LDAPUpdate: for item in default: # We already do syntax-parsing so this is safe - (attr, value) = item.split(':',1) + attr = item['attr'] + value = item['value'] + e = entry.get(attr) if e: # multi-valued attribute @@ -558,8 +637,11 @@ class LDAPUpdate: only = {} for update in updates: # We already do syntax-parsing so this is safe - (action, attr, update_value) = update.split(':', 2) - entry_values = entry.get(attr, []) + action = update['action'] + attr = update['attr'] + update_value = update['value'] + + entry_values = entry.raw.get(attr, []) if action == 'remove': self.debug("remove: '%s' from %s, current value %s", safe_output(attr, update_value), attr, safe_output(attr,entry_values)) try: @@ -620,11 +702,9 @@ class LDAPUpdate: # skip this update type, it occurs in __delete_entries() return None elif action == 'replace': - # value has the format "old::new" - try: - (old, new) = update_value.split('::', 1) - except ValueError: - raise BadSyntax, "bad syntax in replace, needs to be in the format old::new in %s" % update_value + # replace values were store as list + old, new = update_value + try: entry_values.remove(old) except ValueError: @@ -642,7 +722,7 @@ class LDAPUpdate: if message: self.debug("%s", message) self.debug("dn: %s", e.dn) - for a, value in e.items(): + for a, value in e.raw.items(): self.debug('%s:', a) for l in value: self.debug("\t%s", safe_output(a, l)) |