Blame plugins/modules/ipaprivilege.py

Packit Service ee01e6
#!/usr/bin/python
Packit Service a166ed
# -*- coding: utf-8 -*-
Packit Service a166ed
Packit Service a166ed
# Authors:
Packit Service a166ed
#   Rafael Guterres Jeffman <rjeffman@redhat.com>
Packit Service a166ed
#
Packit Service a166ed
# Copyright (C) 2020 Red Hat
Packit Service a166ed
# see file 'COPYING' for use and warranty information
Packit Service a166ed
#
Packit Service a166ed
# This program is free software; you can redistribute it and/or modify
Packit Service a166ed
# it under the terms of the GNU General Public License as published by
Packit Service a166ed
# the Free Software Foundation, either version 3 of the License, or
Packit Service a166ed
# (at your option) any later version.
Packit Service a166ed
#
Packit Service a166ed
# This program is distributed in the hope that it will be useful,
Packit Service a166ed
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a166ed
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a166ed
# GNU General Public License for more details.
Packit Service a166ed
#
Packit Service a166ed
# You should have received a copy of the GNU General Public License
Packit Service a166ed
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service a166ed
Packit Service a166ed
"""ansible-freeipa module to manage FreeIPA privileges."""
Packit Service a166ed
Packit Service a166ed
Packit Service a166ed
ANSIBLE_METADATA = {
Packit Service a166ed
    "metadata_version": "1.0",
Packit Service a166ed
    "supported_by": "community",
Packit Service a166ed
    "status": ["preview"],
Packit Service a166ed
}
Packit Service a166ed
Packit Service a166ed
DOCUMENTATION = """
Packit Service a166ed
---
Packit Service a166ed
module: ipaprivilege
Packit Service a166ed
short description: Manage FreeIPA privilege
Packit Service a166ed
description: Manage FreeIPA privilege and privilege members
Packit Service a166ed
options:
Packit Service a166ed
  ipaadmin_principal:
Packit Service a166ed
    description: The admin principal.
Packit Service a166ed
    default: admin
Packit Service a166ed
  ipaadmin_password:
Packit Service a166ed
    description: The admin password.
Packit Service a166ed
    required: false
Packit Service a166ed
  name:
Packit Service a166ed
    description: The list of privilege name strings.
Packit Service a166ed
    required: true
Packit Service a166ed
    aliases: ["cn"]
Packit Service a166ed
  description:
Packit Service a166ed
    description: Privilege description
Packit Service a166ed
    required: false
Packit Service a166ed
  rename:
Packit Service a166ed
    description: Rename the privilege object.
Packit Service a166ed
    required: false
Packit Service a166ed
    aliases: ["new_name"]
Packit Service a166ed
  permission:
Packit Service a166ed
    description: Permissions to be added to the privilege.
Packit Service a166ed
    required: false
Packit Service a166ed
  action:
Packit Service a166ed
    description: Work on privilege or member level.
Packit Service a166ed
    choices: ["privilege", "member"]
Packit Service a166ed
    default: privilege
Packit Service a166ed
    required: false
Packit Service a166ed
  state:
Packit Service a166ed
    description: The state to ensure.
Packit Service a166ed
    choices: ["present", "absent", "renamed"]
Packit Service a166ed
    default: present
Packit Service a166ed
    required: true
Packit Service a166ed
"""
Packit Service a166ed
Packit Service a166ed
EXAMPLES = """
Packit Service a166ed
# Ensure privilege "Broad Privilege" is present
Packit Service a166ed
- ipaprivilege:
Packit Service a166ed
    ipaadmin_password: SomeADMINpassword
Packit Service a166ed
    name: Broad Privilege
Packit Service a166ed
    description: Broad Privilege
Packit Service a166ed
Packit Service a166ed
# Ensure privilege "Broad Privilege" has permissions set
Packit Service a166ed
- ipaprivilege:
Packit Service a166ed
    ipaadmin_password: SomeADMINpassword
Packit Service a166ed
    name: Broad Privilege
Packit Service a166ed
    permission:
Packit Service a166ed
    - "Write IPA Configuration"
Packit Service a166ed
    - "System: Write DNS Configuration"
Packit Service a166ed
    - "System: Update DNS Entries"
Packit Service a166ed
    action: member
Packit Service a166ed
Packit Service a166ed
# Ensure privilege member permission 'Write IPA Configuration' is absent
Packit Service a166ed
- ipaprivilege:
Packit Service a166ed
    ipaadmin_password: SomeADMINpassword
Packit Service a166ed
    name: Broad Privilege
Packit Service a166ed
    permission:
Packit Service a166ed
    - "Write IPA Configuration"
Packit Service a166ed
    action: member
Packit Service a166ed
    state: absent
Packit Service a166ed
Packit Service a166ed
# Rename privilege "Broad Privilege" to "DNS Special Privilege"
Packit Service a166ed
- ipaprivilege:
Packit Service a166ed
    ipaadmin_password: SomeADMINpassword
Packit Service a166ed
    name: Broad Privilege
Packit Service a166ed
    rename: DNS Special Privilege
Packit Service a166ed
    state: renamed
Packit Service a166ed
Packit Service a166ed
# Ensure privilege "DNS Special Privilege" is absent
Packit Service a166ed
- ipaprivilege:
Packit Service a166ed
    ipaadmin_password: SomeADMINpassword
Packit Service a166ed
    name: DNS Special Privilege
Packit Service a166ed
    state: absent
Packit Service a166ed
"""
Packit Service a166ed
Packit Service a166ed
RETURN = """
Packit Service a166ed
"""
Packit Service a166ed
Packit Service a166ed
Packit Service a166ed
from ansible.module_utils.basic import AnsibleModule
Packit Service a166ed
from ansible.module_utils.ansible_freeipa_module import \
Packit Service a166ed
    temp_kinit, temp_kdestroy, valid_creds, api_connect, api_command, \
Packit Service a166ed
    compare_args_ipa, module_params_get, gen_add_del_lists
Packit Service a166ed
import six
Packit Service a166ed
Packit Service a166ed
if six.PY3:
Packit Service a166ed
    unicode = str
Packit Service a166ed
Packit Service a166ed
Packit Service a166ed
def find_privilege(module, name):
Packit Service a166ed
    """Find if a privilege with the given name already exist."""
Packit Service a166ed
    try:
Packit Service a166ed
        _result = api_command(module, "privilege_show", name, {"all": True})
Packit Service a166ed
    except Exception:  # pylint: disable=broad-except
Packit Service a166ed
        # An exception is raised if privilege name is not found.
Packit Service a166ed
        return None
Packit Service a166ed
    else:
Packit Service a166ed
        return _result["result"]
Packit Service a166ed
Packit Service a166ed
Packit Service a166ed
def main():
Packit Service a166ed
    ansible_module = AnsibleModule(
Packit Service a166ed
        argument_spec=dict(
Packit Service a166ed
            # general
Packit Service a166ed
            ipaadmin_principal=dict(type="str", default="admin"),
Packit Service a166ed
            ipaadmin_password=dict(type="str", required=False, no_log=True),
Packit Service a166ed
Packit Service a166ed
            name=dict(type="list", aliases=["cn"],
Packit Service a166ed
                      default=None, required=True),
Packit Service a166ed
            # present
Packit Service a166ed
            description=dict(required=False, type='str', default=None),
Packit Service a166ed
            rename=dict(required=False, type='str', default=None,
Packit Service a166ed
                        aliases=["new_name"], ),
Packit Service a166ed
            permission=dict(required=False, type='list', default=None),
Packit Service a166ed
            action=dict(type="str", default="privilege",
Packit Service a166ed
                        choices=["member", "privilege"]),
Packit Service a166ed
            # state
Packit Service a166ed
            state=dict(type="str", default="present",
Packit Service a166ed
                       choices=["present", "absent", "renamed"]),
Packit Service a166ed
        ),
Packit Service a166ed
        supports_check_mode=True,
Packit Service a166ed
    )
Packit Service a166ed
Packit Service a166ed
    ansible_module._ansible_debug = True
Packit Service a166ed
Packit Service a166ed
    # Get parameters
Packit Service a166ed
Packit Service a166ed
    # general
Packit Service a166ed
    ipaadmin_principal = module_params_get(ansible_module,
Packit Service a166ed
                                           "ipaadmin_principal")
Packit Service a166ed
    ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password")
Packit Service a166ed
    names = module_params_get(ansible_module, "name")
Packit Service a166ed
Packit Service a166ed
    # present
Packit Service a166ed
    description = module_params_get(ansible_module, "description")
Packit Service a166ed
    permission = module_params_get(ansible_module, "permission")
Packit Service a166ed
    rename = module_params_get(ansible_module, "rename")
Packit Service a166ed
    action = module_params_get(ansible_module, "action")
Packit Service a166ed
Packit Service a166ed
    # state
Packit Service a166ed
    state = module_params_get(ansible_module, "state")
Packit Service a166ed
Packit Service a166ed
    # Check parameters
Packit Service a166ed
    invalid = []
Packit Service a166ed
Packit Service a166ed
    if state == "present":
Packit Service a166ed
        if len(names) != 1:
Packit Service a166ed
            ansible_module.fail_json(
Packit Service a166ed
                msg="Only one privilege be added at a time.")
Packit Service a166ed
        if action == "member":
Packit Service a166ed
            invalid = ["description"]
Packit Service a166ed
Packit Service a166ed
    if state == "absent":
Packit Service a166ed
        if len(names) < 1:
Packit Service a166ed
            ansible_module.fail_json(msg="No name given.")
Packit Service a166ed
        invalid = ["description", "rename"]
Packit Service a166ed
        if action == "privilege":
Packit Service a166ed
            invalid.append("permission")
Packit Service a166ed
Packit Service a166ed
    if state == "renamed":
Packit Service a166ed
        if len(names) != 1:
Packit Service a166ed
            ansible_module.fail_json(
Packit Service a166ed
                msg="Only one privilege be added at a time.")
Packit Service a166ed
        invalid = ["description", "permission"]
Packit Service a166ed
        if action != "privilege":
Packit Service a166ed
            ansible_module.fail_json(
Packit Service a166ed
                msg="Action '%s' can not be used with state '%s'"
Packit Service a166ed
                    % (action, state))
Packit Service a166ed
Packit Service a166ed
    for x in invalid:
Packit Service a166ed
        if vars()[x] is not None:
Packit Service a166ed
            ansible_module.fail_json(
Packit Service a166ed
                msg="Argument '%s' can not be used with action "
Packit Service a166ed
                "'%s' and state '%s'" % (x, action, state))
Packit Service a166ed
Packit Service a166ed
    # Init
Packit Service a166ed
Packit Service a166ed
    changed = False
Packit Service a166ed
    exit_args = {}
Packit Service a166ed
    ccache_dir = None
Packit Service a166ed
    ccache_name = None
Packit Service a166ed
    try:
Packit Service a166ed
        if not valid_creds(ansible_module, ipaadmin_principal):
Packit Service a166ed
            ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
Packit Service a166ed
                                                 ipaadmin_password)
Packit Service a166ed
        api_connect()
Packit Service a166ed
Packit Service a166ed
        commands = []
Packit Service a166ed
        for name in names:
Packit Service a166ed
            # Make sure privilege exists
Packit Service a166ed
            res_find = find_privilege(ansible_module, name)
Packit Service a166ed
Packit Service a166ed
            # Create command
Packit Service a166ed
            if state == "present":
Packit Service a166ed
Packit Service a166ed
                args = {}
Packit Service a166ed
                if description:
Packit Service a166ed
                    args['description'] = description
Packit Service a166ed
Packit Service a166ed
                if action == "privilege":
Packit Service a166ed
                    # Found the privilege
Packit Service a166ed
                    if res_find is not None:
Packit Service a166ed
                        # For all settings is args, check if there are
Packit Service a166ed
                        # different settings in the find result.
Packit Service a166ed
                        # If yes: modify
Packit Service a166ed
                        if not compare_args_ipa(ansible_module, args,
Packit Service a166ed
                                                res_find):
Packit Service a166ed
                            commands.append([name, "privilege_mod", args])
Packit Service a166ed
                    else:
Packit Service a166ed
                        commands.append([name, "privilege_add", args])
Packit Service a166ed
Packit Service a166ed
                    member_args = {}
Packit Service a166ed
                    if permission:
Packit Service a166ed
                        member_args['permission'] = permission
Packit Service a166ed
Packit Service a166ed
                    if not compare_args_ipa(ansible_module, member_args,
Packit Service a166ed
                                            res_find):
Packit Service a166ed
Packit Service a166ed
                        # Generate addition and removal lists
Packit Service a166ed
                        permission_add, permission_del = gen_add_del_lists(
Packit Service a166ed
                                permission, res_find.get("member_permission"))
Packit Service a166ed
Packit Service a166ed
                        # Add members
Packit Service a166ed
                        if len(permission_add) > 0:
Packit Service a166ed
                            commands.append([name, "privilege_add_permission",
Packit Service a166ed
                                             {
Packit Service a166ed
                                                 "permission": permission_add,
Packit Service a166ed
                                             }])
Packit Service a166ed
                        # Remove members
Packit Service a166ed
                        if len(permission_del) > 0:
Packit Service a166ed
                            commands.append([
Packit Service a166ed
                                name,
Packit Service a166ed
                                "privilege_remove_permission",
Packit Service a166ed
                                {"permission": permission_del}
Packit Service a166ed
                            ])
Packit Service a166ed
Packit Service a166ed
                elif action == "member":
Packit Service a166ed
                    if res_find is None:
Packit Service a166ed
                        ansible_module.fail_json(
Packit Service a166ed
                            msg="No privilege '%s'" % name)
Packit Service a166ed
Packit Service a166ed
                    if permission is None:
Packit Service a166ed
                        ansible_module.fail_json(msg="No permission given")
Packit Service a166ed
Packit Service a166ed
                    commands.append([name, "privilege_add_permission",
Packit Service a166ed
                                     {"permission": permission}])
Packit Service a166ed
Packit Service a166ed
            elif state == "absent":
Packit Service a166ed
                if action == "privilege":
Packit Service a166ed
                    if res_find is not None:
Packit Service a166ed
                        commands.append([name, "privilege_del", {}])
Packit Service a166ed
Packit Service a166ed
                elif action == "member":
Packit Service a166ed
                    if res_find is None:
Packit Service a166ed
                        ansible_module.fail_json(
Packit Service a166ed
                            msg="No privilege '%s'" % name)
Packit Service a166ed
Packit Service a166ed
                    if permission is None:
Packit Service a166ed
                        ansible_module.fail_json(msg="No permission given")
Packit Service a166ed
Packit Service a166ed
                    commands.append([name, "privilege_remove_permission",
Packit Service a166ed
                                     {
Packit Service a166ed
                                         "permission": permission,
Packit Service a166ed
                                     }])
Packit Service a166ed
Packit Service a166ed
            elif state == "renamed":
Packit Service a166ed
                if not rename:
Packit Service a166ed
                    ansible_module.fail_json(msg="No rename value given.")
Packit Service a166ed
Packit Service a166ed
                if res_find is None:
Packit Service a166ed
                    ansible_module.fail_json(
Packit Service a166ed
                        msg="No privilege found to be renamed: '%s'" % (name))
Packit Service a166ed
Packit Service a166ed
                if name != rename:
Packit Service a166ed
                    commands.append(
Packit Service a166ed
                        [name, "privilege_mod", {"rename": rename}])
Packit Service a166ed
Packit Service a166ed
            else:
Packit Service a166ed
                ansible_module.fail_json(msg="Unkown state '%s'" % state)
Packit Service a166ed
Packit Service a166ed
        # Execute commands
Packit Service a166ed
Packit Service a166ed
        for name, command, args in commands:
Packit Service a166ed
            try:
Packit Service a166ed
                result = api_command(ansible_module, command, name,
Packit Service a166ed
                                     args)
Packit Service a166ed
                if "completed" in result:
Packit Service a166ed
                    if result["completed"] > 0:
Packit Service a166ed
                        changed = True
Packit Service a166ed
                else:
Packit Service a166ed
                    changed = True
Packit Service a166ed
            except Exception as e:
Packit Service a166ed
                ansible_module.fail_json(
Packit Service a166ed
                    msg="%s: %s: %s" % (command, name, str(e)))
Packit Service a166ed
            # Get all errors
Packit Service a166ed
            # All "already a member" and "not a member" failures in the
Packit Service a166ed
            # result are ignored. All others are reported.
Packit Service a166ed
            errors = []
Packit Service a166ed
            for failed_item in result.get("failed", []):
Packit Service a166ed
                failed = result["failed"][failed_item]
Packit Service a166ed
                for member_type in failed:
Packit Service a166ed
                    for member, failure in failed[member_type]:
Packit Service a166ed
                        if "already a member" in failure \
Packit Service a166ed
                           or "not a member" in failure:
Packit Service a166ed
                            continue
Packit Service a166ed
                        errors.append("%s: %s %s: %s" % (
Packit Service a166ed
                            command, member_type, member, failure))
Packit Service a166ed
            if len(errors) > 0:
Packit Service a166ed
                ansible_module.fail_json(msg=", ".join(errors))
Packit Service a166ed
Packit Service a166ed
    except Exception as e:
Packit Service a166ed
        ansible_module.fail_json(msg=str(e))
Packit Service a166ed
Packit Service a166ed
    finally:
Packit Service a166ed
        temp_kdestroy(ccache_dir, ccache_name)
Packit Service a166ed
Packit Service a166ed
    # Done
Packit Service a166ed
Packit Service a166ed
    ansible_module.exit_json(changed=changed, **exit_args)
Packit Service a166ed
Packit Service a166ed
Packit Service a166ed
if __name__ == "__main__":
Packit Service a166ed
    main()