From f2b3e88d5a052a42d6ccdf7ffcf1a2ea6e6a1921 Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman <rjeffman@redhat.com> Date: Thu, 25 Nov 2021 18:01:02 -0300 Subject: [PATCH] ipaservice: code refactor. This PR refactors ipaservice to reduce the number of variables (in favor of a 'struct') and to group member management code so that it can be leveraged, and not partially duplicated, between the states and actions. Altough this code is less direct that the previous one, it will reduce the number fo changes to be made if changes to member management is required. --- plugins/modules/ipaservice.py | 443 +++++++++------------------------- 1 file changed, 112 insertions(+), 331 deletions(-) diff --git a/plugins/modules/ipaservice.py b/plugins/modules/ipaservice.py index 9eb87548..e5edd83e 100644 --- a/plugins/modules/ipaservice.py +++ b/plugins/modules/ipaservice.py @@ -289,10 +289,7 @@ def gen_args_smb(netbiosname, ok_as_delegate, ok_to_auth_as_delegate): return _args -def check_parameters(module, state, action, names, parameters): - if not isinstance(parameters, dict): - raise AssertionError("parameters is not a dict") - +def check_parameters(module, state, action, names): # invalid parameters for everything but state 'present', action 'service'. invalid = ['pac_type', 'auth_ind', 'skip_host_check', 'force', 'requires_pre_auth', 'ok_as_delegate', @@ -314,8 +311,8 @@ def check_parameters(module, state, action, names, parameters): invalid = ['delete_continue'] if ( - not parameters.get('smb', False) - and parameters.get('netbiosname') + not module.params_get('smb') + and module.params_get('netbiosname') ): module.fail_json( msg="Argument 'netbiosname' can not be used without " @@ -437,23 +434,6 @@ def main(): host = ansible_module.params_get("host") - allow_create_keytab_user = ansible_module.params_get( - "allow_create_keytab_user") - allow_create_keytab_group = ansible_module.params_get( - "allow_create_keytab_group") - allow_create_keytab_host = ansible_module.params_get( - "allow_create_keytab_host") - allow_create_keytab_hostgroup = ansible_module.params_get( - "allow_create_keytab_hostgroup") - - allow_retrieve_keytab_user = ansible_module.params_get( - "allow_retrieve_keytab_user") - allow_retrieve_keytab_group = ansible_module.params_get( - "allow_retrieve_keytab_group") - allow_retrieve_keytab_host = ansible_module.params_get( - "allow_retrieve_keytab_host") - allow_retrieve_keytab_hostgroup = ansible_module.params_get( - "allow_retrieve_keytab_hostgroup") delete_continue = ansible_module.params_get("delete_continue") # action @@ -462,7 +442,7 @@ def main(): state = ansible_module.params_get("state") # check parameters - check_parameters(ansible_module, state, action, names, vars()) + check_parameters(ansible_module, state, action, names) # Init @@ -479,11 +459,26 @@ def main(): msg="Skipping host check is not supported by your IPA version") commands = [] + keytab_members = ["user", "group", "host", "hostgroup"] for name in names: res_find = find_service(ansible_module, name) res_principals = [] + keytab = { + "retrieve": { + "allow": {k: [] for k in keytab_members}, + "disallow": {k: [] for k in keytab_members}, + }, + "create": { + "allow": {k: [] for k in keytab_members}, + "disallow": {k: [] for k in keytab_members}, + }, + } + certificate_add, certificate_del = [], [] + host_add, host_del = [], [] + principal_add, principal_del = [], [] + if principal and res_find: # When comparing principals to the existing ones, # the REALM is needded, and are added here for those @@ -534,37 +529,8 @@ def main(): if res_find is None: commands.append([name, 'service_add', args]) - - certificate_add = certificate or [] - certificate_del = [] - host_add = host or [] - host_del = [] - principal_add = principal or [] - principal_del = [] - allow_create_keytab_user_add = \ - allow_create_keytab_user or [] - allow_create_keytab_user_del = [] - allow_create_keytab_group_add = \ - allow_create_keytab_group or [] - allow_create_keytab_group_del = [] - allow_create_keytab_host_add = \ - allow_create_keytab_host or [] - allow_create_keytab_host_del = [] - allow_create_keytab_hostgroup_add = \ - allow_create_keytab_hostgroup or [] - allow_create_keytab_hostgroup_del = [] - allow_retrieve_keytab_user_add = \ - allow_retrieve_keytab_user or [] - allow_retrieve_keytab_user_del = [] - allow_retrieve_keytab_group_add = \ - allow_retrieve_keytab_group or [] - allow_retrieve_keytab_group_del = [] - allow_retrieve_keytab_host_add = \ - allow_retrieve_keytab_host or [] - allow_retrieve_keytab_host_del = [] - allow_retrieve_keytab_hostgroup_add = \ - allow_retrieve_keytab_hostgroup or [] - allow_retrieve_keytab_hostgroup_del = [] + # Use an empty res_find to manage members + res_find = {} else: for remove in ['skip_host_check', 'force']: @@ -584,68 +550,15 @@ def main(): res_find): commands.append([name, "service_mod", args]) - certificate_add, certificate_del = gen_add_del_lists( - certificate, res_find.get("usercertificate")) - - host_add, host_del = gen_add_del_lists( - host, res_find.get('managedby_host', [])) + # Manage members + certificate_add, certificate_del = gen_add_del_lists( + certificate, res_find.get("usercertificate")) - principal_add, principal_del = \ - gen_add_del_lists(principal, res_principals) + host_add, host_del = gen_add_del_lists( + host, res_find.get('managedby_host')) - (allow_create_keytab_user_add, - allow_create_keytab_user_del) = \ - gen_add_del_lists( - allow_create_keytab_user, res_find.get( - 'ipaallowedtoperform_write_keys_user', - [])) - (allow_retrieve_keytab_user_add, - allow_retrieve_keytab_user_del) = \ - gen_add_del_lists( - allow_retrieve_keytab_user, res_find.get( - 'ipaallowedtoperform_read_keys_user', - [])) - (allow_create_keytab_group_add, - allow_create_keytab_group_del) = \ - gen_add_del_lists( - allow_create_keytab_group, res_find.get( - 'ipaallowedtoperform_write_keys_group', - [])) - (allow_retrieve_keytab_group_add, - allow_retrieve_keytab_group_del) = \ - gen_add_del_lists( - allow_retrieve_keytab_group, - res_find.get( - 'ipaallowedtoperform_read_keys_group', - [])) - (allow_create_keytab_host_add, - allow_create_keytab_host_del) = \ - gen_add_del_lists( - allow_create_keytab_host, - res_find.get( - 'ipaallowedtoperform_write_keys_host', - [])) - (allow_retrieve_keytab_host_add, - allow_retrieve_keytab_host_del) = \ - gen_add_del_lists( - allow_retrieve_keytab_host, - res_find.get( - 'ipaallowedtoperform_read_keys_host', - [])) - (allow_create_keytab_hostgroup_add, - allow_create_keytab_hostgroup_del) = \ - gen_add_del_lists( - allow_create_keytab_hostgroup, - res_find.get( - 'ipaallowedtoperform_write_keys_hostgroup', - [])) - (allow_retrieve_keytab_hostgroup_add, - allow_retrieve_keytab_hostgroup_del) = \ - gen_add_del_lists( - allow_retrieve_keytab_hostgroup, - res_find.get( - 'ipaallowedtoperform_read_keys_hostgroup', - [])) + principal_add, principal_del = gen_add_del_lists( + principal, res_principals) elif action == "member": if res_find is None: @@ -653,137 +566,31 @@ def main(): certificate_add = gen_add_list( certificate, res_find.get("usercertificate")) - certificate_del = [] + host_add = gen_add_list( - host, res_find.get("managedby_host")) - host_del = [] + host, res_find.get('managedby_host')) + principal_add = gen_add_list(principal, res_principals) - principal_del = [] - - allow_create_keytab_user_add = gen_add_list( - allow_create_keytab_user, - res_find.get("ipaallowedtoperform_write_keys_user") - ) - - allow_create_keytab_user_del = [] - allow_create_keytab_group_add = gen_add_list( - allow_create_keytab_group, - res_find.get("ipaallowedtoperform_write_keys_group") - ) - allow_create_keytab_group_del = [] - allow_create_keytab_host_add = gen_add_list( - allow_create_keytab_host, - res_find.get("ipaallowedtoperform_write_keys_host") - ) - allow_create_keytab_host_del = [] - allow_create_keytab_hostgroup_add = gen_add_list( - allow_create_keytab_hostgroup, - res_find.get( - "ipaallowedtoperform_write_keys_hostgroup") - ) - allow_create_keytab_hostgroup_del = [] - allow_retrieve_keytab_user_add = gen_add_list( - allow_retrieve_keytab_user, - res_find.get("ipaallowedtoperform_read_keys_user") - ) - allow_retrieve_keytab_user_del = [] - allow_retrieve_keytab_group_add = gen_add_list( - allow_retrieve_keytab_group, - res_find.get("ipaallowedtoperform_read_keys_group") - ) - allow_retrieve_keytab_group_del = [] - allow_retrieve_keytab_host_add = gen_add_list( - allow_retrieve_keytab_host, - res_find.get("ipaallowedtoperform_read_keys_host") - ) - allow_retrieve_keytab_host_del = [] - allow_retrieve_keytab_hostgroup_add = gen_add_list( - allow_retrieve_keytab_hostgroup, - res_find.get("ipaallowedtoperform_read_keys_hostgroup") - ) - allow_retrieve_keytab_hostgroup_del = [] - - if principal_add: - commands.append([name, "service_add_principal", - {"krbprincipalname": principal_add}]) - if principal_del: - commands.append([name, "service_remove_principal", - {"krbprincipalname": principal_del}]) - - for _certificate in certificate_add: - commands.append([name, "service_add_cert", - { - "usercertificate": - _certificate, - }]) - # Remove certificates - for _certificate in certificate_del: - commands.append([name, "service_remove_cert", - { - "usercertificate": - _certificate, - }]) - - # Add hosts. - if host is not None and len(host) > 0 and len(host_add) > 0: - commands.append([name, "service_add_host", - {"host": host_add}]) - # Remove hosts - if host is not None and len(host) > 0 and len(host_del) > 0: - commands.append([name, "service_remove_host", - {"host": host_del}]) - - # Allow create keytab - if len(allow_create_keytab_user_add) > 0 or \ - len(allow_create_keytab_group_add) > 0 or \ - len(allow_create_keytab_host_add) > 0 or \ - len(allow_create_keytab_hostgroup_add) > 0: - commands.append( - [name, "service_allow_create_keytab", - {'user': allow_create_keytab_user_add, - 'group': allow_create_keytab_group_add, - 'host': allow_create_keytab_host_add, - 'hostgroup': allow_create_keytab_hostgroup_add - }]) - - # Disallow create keytab - if len(allow_create_keytab_user_del) > 0 or \ - len(allow_create_keytab_group_del) > 0 or \ - len(allow_create_keytab_host_del) > 0 or \ - len(allow_create_keytab_hostgroup_del) > 0: - commands.append( - [name, "service_disallow_create_keytab", - {'user': allow_create_keytab_user_del, - 'group': allow_create_keytab_group_del, - 'host': allow_create_keytab_host_del, - 'hostgroup': allow_create_keytab_hostgroup_del - }]) - - # Allow retrieve keytab - if len(allow_retrieve_keytab_user_add) > 0 or \ - len(allow_retrieve_keytab_group_add) > 0 or \ - len(allow_retrieve_keytab_host_add) > 0 or \ - len(allow_retrieve_keytab_hostgroup_add) > 0: - commands.append( - [name, "service_allow_retrieve_keytab", - {'user': allow_retrieve_keytab_user_add, - 'group': allow_retrieve_keytab_group_add, - 'host': allow_retrieve_keytab_host_add, - 'hostgroup': allow_retrieve_keytab_hostgroup_add - }]) - - # Disllow retrieve keytab - if len(allow_retrieve_keytab_user_del) > 0 or \ - len(allow_retrieve_keytab_group_del) > 0 or \ - len(allow_retrieve_keytab_host_del) > 0 or \ - len(allow_retrieve_keytab_hostgroup_del) > 0: - commands.append( - [name, "service_disallow_retrieve_keytab", - {'user': allow_retrieve_keytab_user_del, - 'group': allow_retrieve_keytab_group_del, - 'host': allow_retrieve_keytab_host_del, - 'hostgroup': allow_retrieve_keytab_hostgroup_del - }]) + + # get keytab management lists for any 'action'. + for perm in ["create", "retrieve"]: + oper = "write" if perm == "create" else "read" + for key in ["user", "group", "host", "hostgroup"]: + add_list, del_list = ( + gen_add_del_lists( + ansible_module.params_get( + "allow_%s_keytab_%s" % (perm, key) + ), + res_find.get( + 'ipaallowedtoperform_%s_keys_%s' + % (oper, key) + ) + ) + ) + keytab[perm]["allow"][key] = add_list + # Only remove members if action is 'service' + if action == "service": + keytab[perm]["disallow"][key] = del_list elif state == "absent": if action == "service": @@ -795,97 +602,30 @@ def main(): if res_find is None: ansible_module.fail_json(msg="No service '%s'" % name) - # Remove principals principal_del = gen_intersection_list( principal, res_principals) - if principal_del: - commands.append([name, "service_remove_principal", - {"krbprincipalname": principal_del}]) - - # Remove certificates - if certificate is not None: - existing = res_find.get('usercertificate', []) - for _certificate in certificate: - if _certificate in existing: - commands.append([name, "service_remove_cert", - { - "usercertificate": - _certificate, - }]) - - # Add hosts - host = gen_intersection_list( + + certificate_del = gen_intersection_list( + certificate, res_find.get("usercertificate")) + + host_del = gen_intersection_list( host, res_find.get("managedby_host")) - if host is not None: - commands.append( - [name, "service_remove_host", {"host": host}]) - - allow_create_keytab_user_del = gen_intersection_list( - allow_create_keytab_user, - res_find.get("ipaallowedtoperform_write_keys_user") - ) - allow_create_keytab_group_del = gen_intersection_list( - allow_create_keytab_group, - res_find.get("ipaallowedtoperform_write_keys_group") - ) - allow_create_keytab_host_del = gen_intersection_list( - allow_create_keytab_host, - res_find.get("ipaallowedtoperform_write_keys_host") - ) - allow_create_keytab_hostgroup_del = gen_intersection_list( - allow_create_keytab_hostgroup, - res_find.get( - "ipaallowedtoperform_write_keys_hostgroup") - ) - - # Allow create keytab - if any([ - allow_create_keytab_user_del, - allow_create_keytab_group_del, - allow_create_keytab_host_del, - allow_create_keytab_hostgroup_del - ]): - commands.append( - [name, "service_disallow_create_keytab", - {'user': allow_create_keytab_user_del, - 'group': allow_create_keytab_group_del, - 'host': allow_create_keytab_host_del, - 'hostgroup': allow_create_keytab_hostgroup_del - }]) - - allow_retrieve_keytab_user_del = gen_intersection_list( - allow_retrieve_keytab_user, - res_find.get("ipaallowedtoperform_read_keys_user") - ) - allow_retrieve_keytab_group_del = gen_intersection_list( - allow_retrieve_keytab_group, - res_find.get("ipaallowedtoperform_read_keys_group") - ) - allow_retrieve_keytab_host_del = gen_intersection_list( - allow_retrieve_keytab_host, - res_find.get("ipaallowedtoperform_read_keys_host") - ) - allow_retrieve_keytab_hostgroup_del = \ - gen_intersection_list( - allow_retrieve_keytab_hostgroup, - res_find.get( - "ipaallowedtoperform_read_keys_hostgroup") - ) - # Allow retriev keytab - if any([ - allow_retrieve_keytab_user_del, - allow_retrieve_keytab_group_del, - allow_retrieve_keytab_host_del, - allow_retrieve_keytab_hostgroup_del - ]): - commands.append( - [name, "service_disallow_retrieve_keytab", - {'user': allow_retrieve_keytab_user, - 'group': allow_retrieve_keytab_group, - 'host': allow_retrieve_keytab_host, - 'hostgroup': allow_retrieve_keytab_hostgroup - }]) + for perm in ["create", "retrieve"]: + oper = "write" if perm == "create" else "read" + for key in ["user", "group", "host", "hostgroup"]: + res_param = ( + 'ipaallowedtoperform_%s_keys_%s' + % (oper, key) + ) + module_params = ansible_module.params_get( + "allow_%s_keytab_%s" % (perm, key) + ) + existing = res_find.get(res_param) + del_list = ( + gen_intersection_list(module_params, existing) + ) + keytab[perm]["disallow"][key] = del_list elif state == "disabled": if action == "service": @@ -898,9 +638,50 @@ def main(): ansible_module.fail_json( msg="Invalid action '%s' for state '%s'" % (action, state)) + # Members are not managed when disabling service. + # Continue with next 'name'. + continue else: ansible_module.fail_json(msg="Unkown state '%s'" % state) + # Manage members + if principal_add: + commands.append([name, "service_add_principal", + {"krbprincipalname": principal_add}]) + if principal_del: + commands.append([name, "service_remove_principal", + {"krbprincipalname": principal_del}]) + + if certificate_add: + commands.append([name, "service_add_cert", + {"usercertificate": certificate_add}]) + if certificate_del: + commands.append([name, "service_remove_cert", + {"usercertificate": certificate_del}]) + + if host_add: + commands.append([name, "service_add_host", + {"host": host_add}]) + if host_del: + commands.append([name, "service_remove_host", + {"host": host_del}]) + + # manage keytab permissions. + for perm in ["create", "retrieve"]: + for mode in ["allow", "disallow"]: + for key in ["user", "group", "host", "hostgroup"]: + if keytab[perm][mode][key]: + commands.append([ + name, + "service_%s_%s_keytab" % (mode, perm), + keytab[perm][mode] + ]) + break + + # Check mode exit + if ansible_module.check_mode: + ansible_module.exit_json(changed=len(commands) > 0, **exit_args) + # Execute commands changed = ansible_module.execute_ipa_commands( commands, fail_on_member_errors=True) -- GitLab