Blame plugins/modules/ipauser.py

Packit 8cb997
#!/usr/bin/python
Packit 8cb997
# -*- coding: utf-8 -*-
Packit 8cb997
Packit 8cb997
# Authors:
Packit 8cb997
#   Thomas Woerner <twoerner@redhat.com>
Packit 8cb997
#
Packit 8cb997
# Copyright (C) 2019 Red Hat
Packit 8cb997
# see file 'COPYING' for use and warranty information
Packit 8cb997
#
Packit 8cb997
# This program is free software; you can redistribute it and/or modify
Packit 8cb997
# it under the terms of the GNU General Public License as published by
Packit 8cb997
# the Free Software Foundation, either version 3 of the License, or
Packit 8cb997
# (at your option) any later version.
Packit 8cb997
#
Packit 8cb997
# This program is distributed in the hope that it will be useful,
Packit 8cb997
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8cb997
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8cb997
# GNU General Public License for more details.
Packit 8cb997
#
Packit 8cb997
# You should have received a copy of the GNU General Public License
Packit 8cb997
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 8cb997
Packit 8cb997
ANSIBLE_METADATA = {
Packit 8cb997
    "metadata_version": "1.0",
Packit 8cb997
    "supported_by": "community",
Packit 8cb997
    "status": ["preview"],
Packit 8cb997
}
Packit 8cb997
Packit 8cb997
DOCUMENTATION = """
Packit 8cb997
---
Packit 8cb997
module: ipauser
Packit 8cb997
short description: Manage FreeIPA users
Packit 8cb997
description: Manage FreeIPA users
Packit 8cb997
options:
Packit 8cb997
  ipaadmin_principal:
Packit 8cb997
    description: The admin principal
Packit 8cb997
    default: admin
Packit 8cb997
  ipaadmin_password:
Packit 8cb997
    description: The admin password
Packit 8cb997
    required: false
Packit 8cb997
  name:
Packit 8cb997
    description: The list of users (internally uid).
Packit 8cb997
    required: false
Packit 8cb997
  users:
Packit 8cb997
    description: The list of user dicts (internally uid).
Packit 8cb997
    options:
Packit 8cb997
      name:
Packit 8cb997
        description: The user (internally uid).
Packit 8cb997
        required: true
Packit 8cb997
      first:
Packit 8cb997
        description: The first name
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["givenname"]
Packit 8cb997
      last:
Packit 8cb997
        description: The last name
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["sn"]
Packit 8cb997
      fullname:
Packit 8cb997
        description: The full name
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["cn"]
Packit 8cb997
      displayname:
Packit 8cb997
        description: The display name
Packit 8cb997
        required: false
Packit 8cb997
      initials:
Packit 8cb997
        description: Initials
Packit 8cb997
        required: false
Packit 8cb997
      homedir:
Packit 8cb997
        description: The home directory
Packit 8cb997
        required: false
Packit 8cb997
      shell:
Packit 8cb997
        description: The login shell
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["loginshell"]
Packit 8cb997
      email:
Packit 8cb997
        description: List of email addresses
Packit 8cb997
        required: false
Packit 8cb997
      principal:
Packit 8cb997
        description: The kerberos principal
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["principalname", "krbprincipalname"]
Packit 8cb997
      principalexpiration:
Packit 8cb997
        description:
Packit 8cb997
        - The kerberos principal expiration date
Packit 8cb997
        - (possible formats: YYYYMMddHHmmssZ, YYYY-MM-ddTHH:mm:ssZ,
Packit 8cb997
        - YYYY-MM-ddTHH:mmZ, YYYY-MM-ddZ, YYYY-MM-dd HH:mm:ssZ,
Packit 8cb997
        - YYYY-MM-dd HH:mmZ) The trailing 'Z' can be skipped.
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["krbprincipalexpiration"]
Packit 8cb997
      passwordexpiration:
Packit 8cb997
        description:
Packit 8cb997
        - The kerberos password expiration date (FreeIPA-4.7+)
Packit 8cb997
        - (possible formats: YYYYMMddHHmmssZ, YYYY-MM-ddTHH:mm:ssZ,
Packit 8cb997
        - YYYY-MM-ddTHH:mmZ, YYYY-MM-ddZ, YYYY-MM-dd HH:mm:ssZ,
Packit 8cb997
        - YYYY-MM-dd HH:mmZ) The trailing 'Z' can be skipped.
Packit 8cb997
        - Only usable with IPA versions 4.7 and up.
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["krbpasswordexpiration"]
Packit 8cb997
      password:
Packit 8cb997
        description: The user password
Packit 8cb997
        required: false
Packit 8cb997
      random:
Packit 8cb997
        description: Generate a random user password
Packit 8cb997
        required: false
Packit 8cb997
        type: bool
Packit 8cb997
      uid:
Packit 8cb997
        description: The UID
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["uidnumber"]
Packit 8cb997
      gid:
Packit 8cb997
        description: The GID
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["gidnumber"]
Packit 8cb997
      city:
Packit 8cb997
        description: City
Packit 8cb997
        required: false
Packit 8cb997
      userstate:
Packit 8cb997
        description: State/Province
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["st"]
Packit 8cb997
      postalcode:
Packit 8cb997
        description: Postalcode/ZIP
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["zip"]
Packit 8cb997
      phone:
Packit 8cb997
        description: List of telephone numbers
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["telephonenumber"]
Packit 8cb997
      mobile:
Packit 8cb997
        description: List of mobile telephone numbers
Packit 8cb997
        required: false
Packit 8cb997
      pager:
Packit 8cb997
        description: List of pager numbers
Packit 8cb997
        required: false
Packit 8cb997
      fax:
Packit 8cb997
        description: List of fax numbers
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["facsimiletelephonenumber"]
Packit 8cb997
      orgunit:
Packit 8cb997
        description: Org. Unit
Packit 8cb997
        required: false
Packit 8cb997
      title:
Packit 8cb997
        description: The job title
Packit 8cb997
        required: false
Packit 8cb997
      manager:
Packit 8cb997
        description: List of managers
Packit 8cb997
        required: false
Packit 8cb997
      carlicense:
Packit 8cb997
        description: List of car licenses
Packit 8cb997
        required: false
Packit 8cb997
      sshpubkey:
Packit 8cb997
        description: List of SSH public keys
Packit 8cb997
        required: false
Packit 8cb997
        aliases: ["ipasshpubkey"]
Packit 8cb997
      userauthtype:
Packit 663f99
        description:
Packit 663f99
          List of supported user authentication types
Packit 663f99
          Use empty string to reset userauthtype to the initial value.
Packit 663f99
        choices=['password', 'radius', 'otp', '']
Packit 8cb997
        required: false
Packit 663f99
        aliases: ["ipauserauthtype"]
Packit 8cb997
      userclass:
Packit 8cb997
        description:
Packit 8cb997
        - User category
Packit 8cb997
        - (semantics placed on this attribute are for local interpretation)
Packit 8cb997
        required: false
Packit 8cb997
      radius:
Packit 8cb997
        description: RADIUS proxy configuration
Packit 8cb997
        required: false
Packit 8cb997
      radiususer:
Packit 8cb997
        description: RADIUS proxy username
Packit 8cb997
        required: false
Packit 8cb997
      departmentnumber:
Packit 8cb997
        description: Department Number
Packit 8cb997
        required: false
Packit 8cb997
      employeenumber:
Packit 8cb997
        description: Employee Number
Packit 8cb997
        required: false
Packit 8cb997
      employeetype:
Packit 8cb997
        description: Employee Type
Packit 8cb997
        required: false
Packit 8cb997
      preferredlanguage:
Packit 8cb997
        description: Preferred Language
Packit 8cb997
        required: false
Packit 8cb997
      certificate:
Packit 8cb997
        description: List of base-64 encoded user certificates
Packit 8cb997
        required: false
Packit 8cb997
      certmapdata:
Packit 8cb997
        description: List of certificate mappings
Packit 8cb997
        options:
Packit 8cb997
          certificate:
Packit 8cb997
            description: Base-64 encoded user certificate
Packit 8cb997
            required: false
Packit 8cb997
          issuer:
Packit 8cb997
            description: Issuer of the certificate
Packit 8cb997
            required: false
Packit 8cb997
          subject:
Packit 8cb997
            description: Subject of the certificate
Packit 8cb997
            required: false
Packit 8cb997
        required: false
Packit 8cb997
      noprivate:
Packit 8cb997
        description: Don't create user private group
Packit 8cb997
        required: false
Packit 8cb997
        type: bool
Packit 8cb997
      nomembers:
Packit 8cb997
        description: Suppress processing of membership attributes
Packit 8cb997
        required: false
Packit 8cb997
        type: bool
Packit 8cb997
    required: false
Packit 8cb997
  first:
Packit 8cb997
    description: The first name
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["givenname"]
Packit 8cb997
  last:
Packit 8cb997
    description: The last name
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["sn"]
Packit 8cb997
  fullname:
Packit 8cb997
    description: The full name
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["cn"]
Packit 8cb997
  displayname:
Packit 8cb997
    description: The display name
Packit 8cb997
    required: false
Packit 8cb997
  initials:
Packit 8cb997
    description: Initials
Packit 8cb997
    required: false
Packit 8cb997
  homedir:
Packit 8cb997
    description: The home directory
Packit 8cb997
    required: false
Packit 8cb997
  shell:
Packit 8cb997
    description: The login shell
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["loginshell"]
Packit 8cb997
  email:
Packit 8cb997
    description: List of email addresses
Packit 8cb997
    required: false
Packit 8cb997
  principal:
Packit 8cb997
    description: The kerberos principal
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["principalname", "krbprincipalname"]
Packit 8cb997
  principalexpiration:
Packit 8cb997
    description:
Packit 8cb997
    - The kerberos principal expiration date
Packit 8cb997
    - (possible formats: YYYYMMddHHmmssZ, YYYY-MM-ddTHH:mm:ssZ,
Packit 8cb997
    - YYYY-MM-ddTHH:mmZ, YYYY-MM-ddZ, YYYY-MM-dd HH:mm:ssZ,
Packit 8cb997
    - YYYY-MM-dd HH:mmZ) The trailing 'Z' can be skipped.
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["krbprincipalexpiration"]
Packit 8cb997
  passwordexpiration:
Packit 8cb997
    description:
Packit 8cb997
    - The kerberos password expiration date (FreeIPA-4.7+)
Packit 8cb997
    - (possible formats: YYYYMMddHHmmssZ, YYYY-MM-ddTHH:mm:ssZ,
Packit 8cb997
    - YYYY-MM-ddTHH:mmZ, YYYY-MM-ddZ, YYYY-MM-dd HH:mm:ssZ,
Packit 8cb997
    - YYYY-MM-dd HH:mmZ) The trailing 'Z' can be skipped.
Packit 8cb997
    - Only usable with IPA versions 4.7 and up.
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["krbpasswordexpiration"]
Packit 8cb997
  password:
Packit 8cb997
    description: The user password
Packit 8cb997
    required: false
Packit 8cb997
  random:
Packit 8cb997
    description: Generate a random user password
Packit 8cb997
    required: false
Packit 8cb997
    type: bool
Packit 8cb997
  uid:
Packit 8cb997
    description: The UID
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["uidnumber"]
Packit 8cb997
  gid:
Packit 8cb997
    description: The GID
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["gidnumber"]
Packit 8cb997
  city:
Packit 8cb997
    description: City
Packit 8cb997
    required: false
Packit 8cb997
  userstate:
Packit 8cb997
    description: State/Province
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["st"]
Packit 8cb997
  postalcode:
Packit 8cb997
    description: ZIP
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["zip"]
Packit 8cb997
  phone:
Packit 8cb997
    description: List of telephone numbers
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["telephonenumber"]
Packit 8cb997
  mobile:
Packit 8cb997
    description: List of mobile telephone numbers
Packit 8cb997
    required: false
Packit 8cb997
  pager:
Packit 8cb997
    description: List of pager numbers
Packit 8cb997
    required: false
Packit 8cb997
  fax:
Packit 8cb997
    description: List of fax numbers
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["facsimiletelephonenumber"]
Packit 8cb997
  orgunit:
Packit 8cb997
    description: Org. Unit
Packit 8cb997
    required: false
Packit 8cb997
  title:
Packit 8cb997
    description: The job title
Packit 8cb997
    required: false
Packit 8cb997
  manager:
Packit 8cb997
    description: List of managers
Packit 8cb997
    required: false
Packit 8cb997
  carlicense:
Packit 8cb997
    description: List of car licenses
Packit 8cb997
    required: false
Packit 8cb997
  sshpubkey:
Packit 8cb997
    description: List of SSH public keys
Packit 8cb997
    required: false
Packit 8cb997
    aliases: ["ipasshpubkey"]
Packit 8cb997
  userauthtype:
Packit 663f99
    description:
Packit 663f99
      List of supported user authentication types
Packit 663f99
      Use empty string to reset userauthtype to the initial value.
Packit 663f99
    choices=['password', 'radius', 'otp', '']
Packit 8cb997
    required: false
Packit 663f99
    aliases: ["ipauserauthtype"]
Packit 8cb997
  userclass:
Packit 8cb997
    description:
Packit 8cb997
    - User category
Packit 8cb997
    - (semantics placed on this attribute are for local interpretation)
Packit 8cb997
    required: false
Packit 8cb997
  radius:
Packit 8cb997
    description: RADIUS proxy configuration
Packit 8cb997
    required: false
Packit 8cb997
  radiususer:
Packit 8cb997
    description: RADIUS proxy username
Packit 8cb997
    required: false
Packit 8cb997
  departmentnumber:
Packit 8cb997
    description: Department Number
Packit 8cb997
    required: false
Packit 8cb997
  employeenumber:
Packit 8cb997
    description: Employee Number
Packit 8cb997
    required: false
Packit 8cb997
  employeetype:
Packit 8cb997
    description: Employee Type
Packit 8cb997
    required: false
Packit 8cb997
  preferredlanguage:
Packit 8cb997
    description: Preferred Language
Packit 8cb997
    required: false
Packit 8cb997
  certificate:
Packit 8cb997
    description: List of base-64 encoded user certificates
Packit 8cb997
    required: false
Packit 8cb997
  certmapdata:
Packit 8cb997
    description: List of certificate mappings
Packit 8cb997
    options:
Packit 8cb997
      certificate:
Packit 8cb997
        description: Base-64 encoded user certificate
Packit 8cb997
        required: false
Packit 8cb997
      issuer:
Packit 8cb997
        description: Issuer of the certificate
Packit 8cb997
        required: false
Packit 8cb997
      subject:
Packit 8cb997
        description: Subject of the certificate
Packit 8cb997
        required: false
Packit 8cb997
    required: false
Packit 8cb997
  noprivate:
Packit 8cb997
    description: Don't create user private group
Packit 8cb997
    required: false
Packit 8cb997
    type: bool
Packit 8cb997
  nomembers:
Packit 8cb997
    description: Suppress processing of membership attributes
Packit 8cb997
    required: false
Packit 8cb997
    type: bool
Packit 8cb997
  preserve:
Packit 8cb997
    description: Delete a user, keeping the entry available for future use
Packit 8cb997
    required: false
Packit 8cb997
  update_password:
Packit 8cb997
    description:
Packit 8cb997
      Set password for a user in present state only on creation or always
Packit 8cb997
    default: "always"
Packit 8cb997
    choices: ["always", "on_create"]
Packit 8cb997
    required: false
Packit 8cb997
  action:
Packit 8cb997
    description: Work on user or member level
Packit 8cb997
    default: "user"
Packit 8cb997
    choices: ["member", "user"]
Packit 8cb997
  state:
Packit 8cb997
    description: State to ensure
Packit 8cb997
    default: present
Packit 8cb997
    choices: ["present", "absent",
Packit 8cb997
              "enabled", "disabled",
Packit 8cb997
              "unlocked", "undeleted"]
Packit 8cb997
author:
Packit 8cb997
    - Thomas Woerner
Packit 8cb997
"""
Packit 8cb997
Packit 8cb997
EXAMPLES = """
Packit 8cb997
# Create user pinky
Packit 8cb997
- ipauser:
Packit 8cb997
    ipaadmin_password: MyPassword123
Packit 8cb997
    name: pinky
Packit 8cb997
    first: pinky
Packit 8cb997
    last: Acme
Packit 8cb997
    uid: 10001
Packit 8cb997
    gid: 100
Packit 8cb997
    phone: "+555123457"
Packit 8cb997
    email: pinky@acme.com
Packit 8cb997
    passwordexpiration: "2023-01-19 23:59:59"
Packit 8cb997
    password: "no-brain"
Packit 8cb997
    update_password: on_create
Packit 8cb997
Packit 8cb997
# Create user brain
Packit 8cb997
- ipauser:
Packit 8cb997
    ipaadmin_password: MyPassword123
Packit 8cb997
    name: brain
Packit 8cb997
    first: brain
Packit 8cb997
    last: Acme
Packit 8cb997
Packit 8cb997
# Delete user pinky, but preserved
Packit 8cb997
- ipauser:
Packit 8cb997
    ipaadmin_password: MyPassword123
Packit 8cb997
    name: pinky
Packit 8cb997
    preserve: yes
Packit 8cb997
    state: absent
Packit 8cb997
Packit 8cb997
# Undelete user pinky
Packit 8cb997
- ipauser:
Packit 8cb997
    ipaadmin_password: MyPassword123
Packit 8cb997
    name: pinky
Packit 8cb997
    state: undeleted
Packit 8cb997
Packit 8cb997
# Disable user pinky
Packit 8cb997
- ipauser:
Packit 8cb997
    ipaadmin_password: MyPassword123
Packit 8cb997
    name: pinky,brain
Packit 8cb997
    state: disabled
Packit 8cb997
Packit 8cb997
# Enable user pinky and brain
Packit 8cb997
- ipauser:
Packit 8cb997
    ipaadmin_password: MyPassword123
Packit 8cb997
    name: pinky,brain
Packit 8cb997
    state: enabled
Packit 8cb997
Packit 8cb997
# Remove user pinky and brain
Packit 8cb997
- ipauser:
Packit 8cb997
    ipaadmin_password: MyPassword123
Packit 8cb997
    name: pinky,brain
Packit 8cb997
    state: disabled
Packit 8cb997
"""
Packit 8cb997
Packit 8cb997
RETURN = """
Packit 8cb997
user:
Packit 8cb997
  description: User dict with random password
Packit 8cb997
  returned: If random is yes and user did not exist or update_password is yes
Packit 8cb997
  type: dict
Packit 8cb997
  options:
Packit 8cb997
    randompassword:
Packit 8cb997
      description: The generated random password
Packit 8cb997
      returned: If only one user is handled by the module
Packit 8cb997
    name:
Packit 8cb997
      description: The user name of the user that got a new random password
Packit 8cb997
      returned: If several users are handled by the module
Packit 8cb997
      type: dict
Packit 8cb997
      options:
Packit 8cb997
        randompassword:
Packit 8cb997
          description: The generated random password
Packit 8cb997
          returned: always
Packit 8cb997
"""
Packit 8cb997
Packit 8cb997
from ansible.module_utils.basic import AnsibleModule
Packit 8cb997
from ansible.module_utils._text import to_text
Packit 8cb997
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
Packit 8cb997
    temp_kdestroy, valid_creds, api_connect, api_command, date_format, \
Packit 8cb997
    compare_args_ipa, module_params_get, api_check_param, api_get_realm, \
Packit 8cb997
    api_command_no_name
Packit 8cb997
import six
Packit 8cb997
Packit 8cb997
Packit 8cb997
if six.PY3:
Packit 8cb997
    unicode = str
Packit 8cb997
Packit 8cb997
Packit 8cb997
def find_user(module, name, preserved=False):
Packit 8cb997
    _args = {
Packit 8cb997
        "all": True,
Packit 8cb997
        "uid": name,
Packit 8cb997
    }
Packit 8cb997
    if preserved:
Packit 8cb997
        _args["preserved"] = preserved
Packit 8cb997
Packit 8cb997
    _result = api_command(module, "user_find", name, _args)
Packit 8cb997
Packit 8cb997
    if len(_result["result"]) > 1:
Packit 8cb997
        module.fail_json(
Packit 8cb997
            msg="There is more than one user '%s'" % (name))
Packit 8cb997
    elif len(_result["result"]) == 1:
Packit 8cb997
        # Transform each principal to a string
Packit 8cb997
        _result = _result["result"][0]
Packit 8cb997
        if "krbprincipalname" in _result \
Packit 8cb997
           and _result["krbprincipalname"] is not None:
Packit 8cb997
            _list = []
Packit 8cb997
            for x in _result["krbprincipalname"]:
Packit 8cb997
                _list.append(str(x))
Packit 8cb997
            _result["krbprincipalname"] = _list
Packit 8cb997
        return _result
Packit 8cb997
    else:
Packit 8cb997
        return None
Packit 8cb997
Packit 8cb997
Packit 8cb997
def gen_args(first, last, fullname, displayname, initials, homedir, shell,
Packit 8cb997
             email, principalexpiration, passwordexpiration, password,
Packit 8cb997
             random, uid, gid, city, userstate, postalcode, phone, mobile,
Packit 8cb997
             pager, fax, orgunit, title, carlicense, sshpubkey, userauthtype,
Packit 8cb997
             userclass, radius, radiususer, departmentnumber, employeenumber,
Packit 8cb997
             employeetype, preferredlanguage, noprivate, nomembers):
Packit 8cb997
    # principal, manager, certificate and certmapdata are handled not in here
Packit 8cb997
    _args = {}
Packit 8cb997
    if first is not None:
Packit 8cb997
        _args["givenname"] = first
Packit 8cb997
    if last is not None:
Packit 8cb997
        _args["sn"] = last
Packit 8cb997
    if fullname is not None:
Packit 8cb997
        _args["cn"] = fullname
Packit 8cb997
    if displayname is not None:
Packit 8cb997
        _args["displayname"] = displayname
Packit 8cb997
    if initials is not None:
Packit 8cb997
        _args["initials"] = initials
Packit 8cb997
    if homedir is not None:
Packit 8cb997
        _args["homedirectory"] = homedir
Packit 8cb997
    if shell is not None:
Packit 8cb997
        _args["loginshell"] = shell
Packit 8cb997
    if email is not None and len(email) > 0:
Packit 8cb997
        _args["mail"] = email
Packit 8cb997
    if principalexpiration is not None:
Packit 8cb997
        _args["krbprincipalexpiration"] = principalexpiration
Packit 8cb997
    if passwordexpiration is not None:
Packit 8cb997
        _args["krbpasswordexpiration"] = passwordexpiration
Packit 8cb997
    if password is not None:
Packit 8cb997
        _args["userpassword"] = password
Packit 8cb997
    if random is not None:
Packit 8cb997
        _args["random"] = random
Packit 8cb997
    if uid is not None:
Packit 8cb997
        _args["uidnumber"] = to_text(str(uid))
Packit 8cb997
    if gid is not None:
Packit 8cb997
        _args["gidnumber"] = to_text(str(gid))
Packit 8cb997
    if city is not None:
Packit 8cb997
        _args["l"] = city
Packit 8cb997
    if userstate is not None:
Packit 8cb997
        _args["st"] = userstate
Packit 8cb997
    if postalcode is not None:
Packit 8cb997
        _args["postalcode"] = postalcode
Packit 8cb997
    if phone is not None and len(phone) > 0:
Packit 8cb997
        _args["telephonenumber"] = phone
Packit 8cb997
    if mobile is not None and len(mobile) > 0:
Packit 8cb997
        _args["mobile"] = mobile
Packit 8cb997
    if pager is not None and len(pager) > 0:
Packit 8cb997
        _args["pager"] = pager
Packit 8cb997
    if fax is not None and len(fax) > 0:
Packit 8cb997
        _args["facsimiletelephonenumber"] = fax
Packit 8cb997
    if orgunit is not None:
Packit 8cb997
        _args["ou"] = orgunit
Packit 8cb997
    if title is not None:
Packit 8cb997
        _args["title"] = title
Packit 8cb997
    if carlicense is not None and len(carlicense) > 0:
Packit 8cb997
        _args["carlicense"] = carlicense
Packit 8cb997
    if sshpubkey is not None and len(sshpubkey) > 0:
Packit 8cb997
        _args["ipasshpubkey"] = sshpubkey
Packit 8cb997
    if userauthtype is not None and len(userauthtype) > 0:
Packit 8cb997
        _args["ipauserauthtype"] = userauthtype
Packit 8cb997
    if userclass is not None:
Packit 8cb997
        _args["userclass"] = userclass
Packit 8cb997
    if radius is not None:
Packit 8cb997
        _args["ipatokenradiusconfiglink"] = radius
Packit 8cb997
    if radiususer is not None:
Packit 8cb997
        _args["ipatokenradiususername"] = radiususer
Packit 8cb997
    if departmentnumber is not None:
Packit 8cb997
        _args["departmentnumber"] = departmentnumber
Packit 8cb997
    if employeenumber is not None:
Packit 8cb997
        _args["employeenumber"] = employeenumber
Packit 8cb997
    if employeetype is not None:
Packit 8cb997
        _args["employeetype"] = employeetype
Packit 8cb997
    if preferredlanguage is not None:
Packit 8cb997
        _args["preferredlanguage"] = preferredlanguage
Packit 8cb997
    if noprivate is not None:
Packit 8cb997
        _args["noprivate"] = noprivate
Packit 8cb997
    if nomembers is not None:
Packit 8cb997
        _args["no_members"] = nomembers
Packit 8cb997
    return _args
Packit 8cb997
Packit 8cb997
Packit 8cb997
def check_parameters(module, state, action,
Packit 8cb997
                     first, last, fullname, displayname, initials, homedir,
Packit 8cb997
                     shell, email, principal, principalexpiration,
Packit 8cb997
                     passwordexpiration, password, random, uid, gid, city,
Packit 8cb997
                     phone, mobile, pager, fax, orgunit, title, manager,
Packit 8cb997
                     carlicense, sshpubkey, userauthtype, userclass, radius,
Packit 8cb997
                     radiususer, departmentnumber, employeenumber,
Packit 8cb997
                     employeetype, preferredlanguage, certificate,
Packit 8cb997
                     certmapdata, noprivate, nomembers, preserve,
Packit 8cb997
                     update_password):
Packit 8cb997
Packit 8cb997
    if state == "present":
Packit 8cb997
        if action == "member":
Packit 8cb997
            invalid = ["first", "last", "fullname", "displayname", "initials",
Packit 8cb997
                       "homedir", "shell", "email", "principalexpiration",
Packit 8cb997
                       "passwordexpiration", "password", "random", "uid",
Packit 8cb997
                       "gid", "city", "phone", "mobile", "pager", "fax",
Packit 8cb997
                       "orgunit", "title", "carlicense", "sshpubkey",
Packit 8cb997
                       "userauthtype", "userclass", "radius", "radiususer",
Packit 8cb997
                       "departmentnumber", "employeenumber", "employeetype",
Packit 8cb997
                       "preferredlanguage", "noprivate", "nomembers",
Packit 8cb997
                       "preserve", "update_password"]
Packit 8cb997
            for x in invalid:
Packit 8cb997
                if vars()[x] is not None:
Packit 8cb997
                    module.fail_json(
Packit 8cb997
                        msg="Argument '%s' can not be used with action "
Packit 8cb997
                        "'%s'" % (x, action))
Packit 8cb997
Packit 8cb997
    else:
Packit 8cb997
        invalid = ["first", "last", "fullname", "displayname", "initials",
Packit 8cb997
                   "homedir", "shell", "email", "principalexpiration",
Packit 8cb997
                   "passwordexpiration", "password", "random", "uid",
Packit 8cb997
                   "gid", "city", "phone", "mobile", "pager", "fax",
Packit 8cb997
                   "orgunit", "title", "carlicense", "sshpubkey",
Packit 8cb997
                   "userauthtype", "userclass", "radius", "radiususer",
Packit 8cb997
                   "departmentnumber", "employeenumber", "employeetype",
Packit 8cb997
                   "preferredlanguage", "noprivate", "nomembers",
Packit 8cb997
                   "update_password"]
Packit 8cb997
        if action == "user":
Packit 8cb997
            invalid.extend(["principal", "manager",
Packit 8cb997
                            "certificate", "certmapdata",
Packit 8cb997
                            ])
Packit 8cb997
        for x in invalid:
Packit 8cb997
            if vars()[x] is not None:
Packit 8cb997
                module.fail_json(
Packit 8cb997
                    msg="Argument '%s' can not be used with state '%s'" %
Packit 8cb997
                    (x, state))
Packit 8cb997
Packit 8cb997
        if state != "absent" and preserve is not None:
Packit 8cb997
            module.fail_json(
Packit 8cb997
                msg="Preserve is only possible for state=absent")
Packit 8cb997
Packit 8cb997
    if certmapdata is not None:
Packit 8cb997
        for x in certmapdata:
Packit 8cb997
            certificate = x.get("certificate")
Packit 8cb997
            issuer = x.get("issuer")
Packit 8cb997
            subject = x.get("subject")
Packit 8cb997
Packit 8cb997
            if certificate is not None \
Packit 8cb997
               and (issuer is not None or subject is not None):
Packit 8cb997
                module.fail_json(
Packit 8cb997
                    msg="certmapdata: certificate can not be used with "
Packit 8cb997
                    "issuer or subject")
Packit 8cb997
            if certificate is None:
Packit 8cb997
                if issuer is None:
Packit 8cb997
                    module.fail_json(msg="certmapdata: issuer is missing")
Packit 8cb997
                if subject is None:
Packit 8cb997
                    module.fail_json(msg="certmapdata: subject is missing")
Packit 8cb997
Packit 8cb997
Packit 8cb997
def extend_emails(email, default_email_domain):
Packit 8cb997
    if email is not None:
Packit 8cb997
        return [ "%s@%s" % (_email, default_email_domain)
Packit 8cb997
                 if "@" not in _email else _email
Packit 8cb997
                 for _email in email]
Packit 8cb997
    return email
Packit 8cb997
Packit 8cb997
Packit 8cb997
def gen_certmapdata_args(certmapdata):
Packit 8cb997
    certificate = certmapdata.get("certificate")
Packit 8cb997
    issuer = certmapdata.get("issuer")
Packit 8cb997
    subject = certmapdata.get("subject")
Packit 8cb997
Packit 8cb997
    _args = {}
Packit 8cb997
    if certificate is not None:
Packit 8cb997
        _args["certificate"] = certificate
Packit 8cb997
    if issuer is not None:
Packit 8cb997
        _args["issuer"] = issuer
Packit 8cb997
    if subject is not None:
Packit 8cb997
        _args["subject"] = subject
Packit 8cb997
    return _args
Packit 8cb997
Packit 8cb997
Packit 8cb997
def main():
Packit 8cb997
    user_spec = dict(
Packit 8cb997
        # present
Packit 8cb997
        first=dict(type="str", aliases=["givenname"], default=None),
Packit 8cb997
        last=dict(type="str", aliases=["sn"], default=None),
Packit 8cb997
        fullname=dict(type="str", aliases=["cn"], default=None),
Packit 8cb997
        displayname=dict(type="str", default=None),
Packit 8cb997
        initials=dict(type="str", default=None),
Packit 8cb997
        homedir=dict(type="str", default=None),
Packit 8cb997
        shell=dict(type="str", aliases=["loginshell"], default=None),
Packit 8cb997
        email=dict(type="list", default=None),
Packit 8cb997
        principal=dict(type="list", aliases=["principalname",
Packit 8cb997
                                             "krbprincipalname"],
Packit 8cb997
                       default=None),
Packit 8cb997
        principalexpiration=dict(type="str",
Packit 8cb997
                                 aliases=["krbprincipalexpiration"],
Packit 8cb997
                                 default=None),
Packit 8cb997
        passwordexpiration=dict(type="str",
Packit 8cb997
                                aliases=["krbpasswordexpiration"],
Packit 8cb997
                                default=None),
Packit 8cb997
        password=dict(type="str", default=None, no_log=True),
Packit 8cb997
        random=dict(type='bool', default=None),
Packit 8cb997
        uid=dict(type="int", aliases=["uidnumber"], default=None),
Packit 8cb997
        gid=dict(type="int", aliases=["gidnumber"], default=None),
Packit 8cb997
        city=dict(type="str", default=None),
Packit 8cb997
        userstate=dict(type="str", aliases=["st"], default=None),
Packit 8cb997
        postalcode=dict(type="str", aliases=["zip"], default=None),
Packit 8cb997
        phone=dict(type="list", aliases=["telephonenumber"], default=None),
Packit 8cb997
        mobile=dict(type="list", default=None),
Packit 8cb997
        pager=dict(type="list", default=None),
Packit 8cb997
        fax=dict(type="list", aliases=["facsimiletelephonenumber"],
Packit 8cb997
                 default=None),
Packit 8cb997
        orgunit=dict(type="str", aliases=["ou"], default=None),
Packit 8cb997
        title=dict(type="str", default=None),
Packit 8cb997
        manager=dict(type="list", default=None),
Packit 8cb997
        carlicense=dict(type="list", default=None),
Packit 8cb997
        sshpubkey=dict(type="list", aliases=["ipasshpubkey"],
Packit 8cb997
                       default=None),
Packit 8cb997
        userauthtype=dict(type='list', aliases=["ipauserauthtype"],
Packit 8cb997
                          default=None,
Packit 663f99
                          choices=['password', 'radius', 'otp', '']),
Packit 8cb997
        userclass=dict(type="list", aliases=["class"],
Packit 8cb997
                       default=None),
Packit 8cb997
        radius=dict(type="str", aliases=["ipatokenradiusconfiglink"],
Packit 8cb997
                    default=None),
Packit 8cb997
        radiususer=dict(type="str", aliases=["radiususername",
Packit 8cb997
                                             "ipatokenradiususername"],
Packit 8cb997
                        default=None),
Packit 8cb997
        departmentnumber=dict(type="list", default=None),
Packit 8cb997
        employeenumber=dict(type="str", default=None),
Packit 8cb997
        employeetype=dict(type="str", default=None),
Packit 8cb997
        preferredlanguage=dict(type="str", default=None),
Packit 8cb997
        certificate=dict(type="list", aliases=["usercertificate"],
Packit 8cb997
                         default=None),
Packit 8cb997
        certmapdata=dict(type="list", default=None,
Packit 8cb997
                         options=dict(
Packit 8cb997
                             # Here certificate is a simple string
Packit 8cb997
                             certificate=dict(type="str", default=None),
Packit 8cb997
                             issuer=dict(type="str", default=None),
Packit 8cb997
                             subject=dict(type="str", default=None)
Packit 8cb997
                         ),
Packit 8cb997
                         elements='dict', required=False),
Packit 8cb997
        noprivate=dict(type='bool', default=None),
Packit 8cb997
        nomembers=dict(type='bool', default=None),
Packit 8cb997
    )
Packit 8cb997
Packit 8cb997
    ansible_module = AnsibleModule(
Packit 8cb997
        argument_spec=dict(
Packit 8cb997
            # general
Packit 8cb997
            ipaadmin_principal=dict(type="str", default="admin"),
Packit 8cb997
            ipaadmin_password=dict(type="str", required=False, no_log=True),
Packit 8cb997
Packit 8cb997
            name=dict(type="list", aliases=["login"], default=None,
Packit 8cb997
                      required=False),
Packit 8cb997
            users=dict(type="list", aliases=["login"], default=None,
Packit 8cb997
                       options=dict(
Packit 8cb997
                           # Here name is a simple string
Packit 8cb997
                           name=dict(type="str", required=True),
Packit 8cb997
                           # Add user specific parameters
Packit 8cb997
                           **user_spec
Packit 8cb997
                       ),
Packit 8cb997
                       elements='dict', required=False),
Packit 8cb997
Packit 8cb997
            # deleted
Packit 8cb997
            preserve=dict(required=False, type='bool', default=None),
Packit 8cb997
Packit 8cb997
            # mod
Packit 8cb997
            update_password=dict(type='str', default=None,
Packit 8cb997
                                 choices=['always', 'on_create']),
Packit 8cb997
Packit 8cb997
            # general
Packit 8cb997
            action=dict(type="str", default="user",
Packit 8cb997
                        choices=["member", "user"]),
Packit 8cb997
            state=dict(type="str", default="present",
Packit 8cb997
                       choices=["present", "absent", "enabled", "disabled",
Packit 8cb997
                                "unlocked", "undeleted"]),
Packit 8cb997
Packit 8cb997
            # Add user specific parameters for simple use case
Packit 8cb997
            **user_spec
Packit 8cb997
        ),
Packit 8cb997
        mutually_exclusive=[["name", "users"]],
Packit 8cb997
        required_one_of=[["name", "users"]],
Packit 8cb997
        supports_check_mode=True,
Packit 8cb997
    )
Packit 8cb997
Packit 8cb997
    ansible_module._ansible_debug = True
Packit 8cb997
Packit 8cb997
    # Get parameters
Packit 8cb997
Packit 8cb997
    # general
Packit 8cb997
    ipaadmin_principal = module_params_get(ansible_module,
Packit 8cb997
                                           "ipaadmin_principal")
Packit 8cb997
    ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password")
Packit 8cb997
    names = module_params_get(ansible_module, "name")
Packit 8cb997
    users = module_params_get(ansible_module, "users")
Packit 8cb997
Packit 8cb997
    # present
Packit 8cb997
    first = module_params_get(ansible_module, "first")
Packit 8cb997
    last = module_params_get(ansible_module, "last")
Packit 8cb997
    fullname = module_params_get(ansible_module, "fullname")
Packit 8cb997
    displayname = module_params_get(ansible_module, "displayname")
Packit 8cb997
    initials = module_params_get(ansible_module, "initials")
Packit 8cb997
    homedir = module_params_get(ansible_module, "homedir")
Packit 8cb997
    shell = module_params_get(ansible_module, "shell")
Packit 8cb997
    email = module_params_get(ansible_module, "email")
Packit 8cb997
    principal = module_params_get(ansible_module, "principal")
Packit 8cb997
    principalexpiration = module_params_get(ansible_module,
Packit 8cb997
                                            "principalexpiration")
Packit 8cb997
    if principalexpiration is not None:
Packit 8cb997
        if principalexpiration[:-1] != "Z":
Packit 8cb997
            principalexpiration = principalexpiration + "Z"
Packit 8cb997
        principalexpiration = date_format(principalexpiration)
Packit 8cb997
    passwordexpiration = module_params_get(ansible_module,
Packit 8cb997
                                           "passwordexpiration")
Packit 8cb997
    if passwordexpiration is not None:
Packit 8cb997
        if passwordexpiration[:-1] != "Z":
Packit 8cb997
            passwordexpiration = passwordexpiration + "Z"
Packit 8cb997
        passwordexpiration = date_format(passwordexpiration)
Packit 8cb997
    password = module_params_get(ansible_module, "password")
Packit 8cb997
    random = module_params_get(ansible_module, "random")
Packit 8cb997
    uid = module_params_get(ansible_module, "uid")
Packit 8cb997
    gid = module_params_get(ansible_module, "gid")
Packit 8cb997
    city = module_params_get(ansible_module, "city")
Packit 8cb997
    userstate = module_params_get(ansible_module, "userstate")
Packit 8cb997
    postalcode = module_params_get(ansible_module, "postalcode")
Packit 8cb997
    phone = module_params_get(ansible_module, "phone")
Packit 8cb997
    mobile = module_params_get(ansible_module, "mobile")
Packit 8cb997
    pager = module_params_get(ansible_module, "pager")
Packit 8cb997
    fax = module_params_get(ansible_module, "fax")
Packit 8cb997
    orgunit = module_params_get(ansible_module, "orgunit")
Packit 8cb997
    title = module_params_get(ansible_module, "title")
Packit 8cb997
    manager = module_params_get(ansible_module, "manager")
Packit 8cb997
    carlicense = module_params_get(ansible_module, "carlicense")
Packit 8cb997
    sshpubkey = module_params_get(ansible_module, "sshpubkey")
Packit 8cb997
    userauthtype = module_params_get(ansible_module, "userauthtype")
Packit 8cb997
    userclass = module_params_get(ansible_module, "userclass")
Packit 8cb997
    radius = module_params_get(ansible_module, "radius")
Packit 8cb997
    radiususer = module_params_get(ansible_module, "radiususer")
Packit 8cb997
    departmentnumber = module_params_get(ansible_module, "departmentnumber")
Packit 8cb997
    employeenumber = module_params_get(ansible_module, "employeenumber")
Packit 8cb997
    employeetype = module_params_get(ansible_module, "employeetype")
Packit 8cb997
    preferredlanguage = module_params_get(ansible_module, "preferredlanguage")
Packit 8cb997
    certificate = module_params_get(ansible_module, "certificate")
Packit 8cb997
    certmapdata = module_params_get(ansible_module, "certmapdata")
Packit 8cb997
    noprivate = module_params_get(ansible_module, "noprivate")
Packit 8cb997
    nomembers = module_params_get(ansible_module, "nomembers")
Packit 8cb997
    # deleted
Packit 8cb997
    preserve = module_params_get(ansible_module, "preserve")
Packit 8cb997
    # mod
Packit 8cb997
    update_password = module_params_get(ansible_module, "update_password")
Packit 8cb997
    # general
Packit 8cb997
    action = module_params_get(ansible_module, "action")
Packit 8cb997
    state = module_params_get(ansible_module, "state")
Packit 8cb997
Packit 8cb997
    # Check parameters
Packit 8cb997
Packit 8cb997
    if (names is None or len(names) < 1) and \
Packit 8cb997
       (users is None or len(users) < 1):
Packit 8cb997
        ansible_module.fail_json(msg="One of name and users is required")
Packit 8cb997
Packit 8cb997
    if state == "present":
Packit 8cb997
        if names is not None and len(names) != 1:
Packit 8cb997
            ansible_module.fail_json(
Packit 8cb997
                msg="Only one user can be added at a time using name.")
Packit 8cb997
Packit 8cb997
    check_parameters(
Packit 8cb997
        ansible_module, state, action,
Packit 8cb997
        first, last, fullname, displayname, initials, homedir, shell, email,
Packit 8cb997
        principal, principalexpiration, passwordexpiration, password, random,
Packit 8cb997
        uid, gid, city, phone, mobile, pager, fax, orgunit, title, manager,
Packit 8cb997
        carlicense, sshpubkey, userauthtype, userclass, radius, radiususer,
Packit 8cb997
        departmentnumber, employeenumber, employeetype, preferredlanguage,
Packit 8cb997
        certificate, certmapdata, noprivate, nomembers, preserve,
Packit 8cb997
        update_password)
Packit 8cb997
Packit 8cb997
    # Use users if names is None
Packit 8cb997
    if users is not None:
Packit 8cb997
        names = users
Packit 8cb997
Packit 8cb997
    # Init
Packit 8cb997
Packit 8cb997
    changed = False
Packit 8cb997
    exit_args = {}
Packit 8cb997
    ccache_dir = None
Packit 8cb997
    ccache_name = None
Packit 8cb997
    try:
Packit 8cb997
        if not valid_creds(ansible_module, ipaadmin_principal):
Packit 8cb997
            ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
Packit 8cb997
                                                 ipaadmin_password)
Packit 8cb997
        api_connect()
Packit 8cb997
Packit 8cb997
        # Check version specific settings
Packit 8cb997
Packit 8cb997
        server_realm = api_get_realm()
Packit 8cb997
Packit 8cb997
        # Default email domain
Packit 8cb997
Packit 8cb997
        result = api_command_no_name(ansible_module, "config_show", {})
Packit 8cb997
        default_email_domain = result["result"]["ipadefaultemaildomain"][0]
Packit 8cb997
Packit 8cb997
        # Extend email addresses
Packit 8cb997
Packit 8cb997
        email = extend_emails(email, default_email_domain)
Packit 8cb997
Packit 8cb997
        # commands
Packit 8cb997
Packit 8cb997
        commands = []
Packit 8cb997
Packit 8cb997
        for user in names:
Packit 8cb997
            if isinstance(user, dict):
Packit 8cb997
                name = user.get("name")
Packit 8cb997
                # present
Packit 8cb997
                first = user.get("first")
Packit 8cb997
                last = user.get("last")
Packit 8cb997
                fullname = user.get("fullname")
Packit 8cb997
                displayname = user.get("displayname")
Packit 8cb997
                initials = user.get("initials")
Packit 8cb997
                homedir = user.get("homedir")
Packit 8cb997
                shell = user.get("shell")
Packit 8cb997
                email = user.get("email")
Packit 8cb997
                principal = user.get("principal")
Packit 8cb997
                principalexpiration = user.get("principalexpiration")
Packit 8cb997
                if principalexpiration is not None:
Packit 8cb997
                    if principalexpiration[:-1] != "Z":
Packit 8cb997
                        principalexpiration = principalexpiration + "Z"
Packit 8cb997
                    principalexpiration = date_format(principalexpiration)
Packit 8cb997
                passwordexpiration = user.get("passwordexpiration")
Packit 8cb997
                if passwordexpiration is not None:
Packit 8cb997
                    if passwordexpiration[:-1] != "Z":
Packit 8cb997
                        passwordexpiration = passwordexpiration + "Z"
Packit 8cb997
                    passwordexpiration = date_format(passwordexpiration)
Packit 8cb997
                password = user.get("password")
Packit 8cb997
                random = user.get("random")
Packit 8cb997
                uid = user.get("uid")
Packit 8cb997
                gid = user.get("gid")
Packit 8cb997
                city = user.get("city")
Packit 8cb997
                userstate = user.get("userstate")
Packit 8cb997
                postalcode = user.get("postalcode")
Packit 8cb997
                phone = user.get("phone")
Packit 8cb997
                mobile = user.get("mobile")
Packit 8cb997
                pager = user.get("pager")
Packit 8cb997
                fax = user.get("fax")
Packit 8cb997
                orgunit = user.get("orgunit")
Packit 8cb997
                title = user.get("title")
Packit 8cb997
                manager = user.get("manager")
Packit 8cb997
                carlicense = user.get("carlicense")
Packit 8cb997
                sshpubkey = user.get("sshpubkey")
Packit 8cb997
                userauthtype = user.get("userauthtype")
Packit 8cb997
                userclass = user.get("userclass")
Packit 8cb997
                radius = user.get("radius")
Packit 8cb997
                radiususer = user.get("radiususer")
Packit 8cb997
                departmentnumber = user.get("departmentnumber")
Packit 8cb997
                employeenumber = user.get("employeenumber")
Packit 8cb997
                employeetype = user.get("employeetype")
Packit 8cb997
                preferredlanguage = user.get("preferredlanguage")
Packit 8cb997
                certificate = user.get("certificate")
Packit 8cb997
                certmapdata = user.get("certmapdata")
Packit 8cb997
                noprivate = user.get("noprivate")
Packit 8cb997
                nomembers = user.get("nomembers")
Packit 8cb997
Packit 8cb997
                check_parameters(
Packit 8cb997
                    ansible_module, state, action,
Packit 8cb997
                    first, last, fullname, displayname, initials, homedir,
Packit 8cb997
                    shell, email, principal, principalexpiration,
Packit 8cb997
                    passwordexpiration, password, random, uid, gid, city,
Packit 8cb997
                    phone, mobile, pager, fax, orgunit, title, manager,
Packit 8cb997
                    carlicense, sshpubkey, userauthtype, userclass, radius,
Packit 8cb997
                    radiususer, departmentnumber, employeenumber,
Packit 8cb997
                    employeetype, preferredlanguage, certificate,
Packit 8cb997
                    certmapdata, noprivate, nomembers, preserve,
Packit 8cb997
                    update_password)
Packit 8cb997
Packit 8cb997
                # Extend email addresses
Packit 8cb997
Packit 8cb997
                email = extend_emails(email, default_email_domain)
Packit 8cb997
Packit 8cb997
            elif isinstance(user, str) or isinstance(user, unicode):
Packit 8cb997
                name = user
Packit 8cb997
            else:
Packit 8cb997
                ansible_module.fail_json(msg="User '%s' is not valid" %
Packit 8cb997
                                         repr(user))
Packit 8cb997
Packit 8cb997
            # Fix principals: add realm if missing
Packit 8cb997
            # We need the connected API for the realm, therefore it can not
Packit 8cb997
            # be part of check_parameters as this is used also before the
Packit 8cb997
            # connection to the API has been established.
Packit 8cb997
            if principal is not None:
Packit 8cb997
                principal = [x if "@" in x else x + "@" + server_realm
Packit 8cb997
                             for x in principal]
Packit 8cb997
Packit 8cb997
            # Check passwordexpiration availability.
Packit 8cb997
            # We need the connected API for this test, therefore it can not
Packit 8cb997
            # be part of check_parameters as this is used also before the
Packit 8cb997
            # connection to the API has been established.
Packit 8cb997
            if passwordexpiration is not None and \
Packit 8cb997
               not api_check_param("user_add", "krbpasswordexpiration"):
Packit 8cb997
                ansible_module.fail_json(
Packit 8cb997
                    msg="The use of passwordexpiration is not supported by "
Packit 8cb997
                    "your IPA version")
Packit 8cb997
Packit 8cb997
            # Make sure user exists
Packit 8cb997
            res_find = find_user(ansible_module, name)
Packit 8cb997
            # Also search for preserved user if the user could not be found
Packit 8cb997
            if res_find is None:
Packit 8cb997
                res_find_preserved = find_user(ansible_module, name,
Packit 8cb997
                                               preserved=True)
Packit 8cb997
            else:
Packit 8cb997
                res_find_preserved = None
Packit 8cb997
Packit 8cb997
            # Create command
Packit 8cb997
            if state == "present":
Packit 8cb997
                # Generate args
Packit 8cb997
                args = gen_args(
Packit 8cb997
                    first, last, fullname, displayname, initials, homedir,
Packit 8cb997
                    shell, email, principalexpiration, passwordexpiration,
Packit 8cb997
                    password, random, uid, gid, city, userstate, postalcode,
Packit 8cb997
                    phone, mobile, pager, fax, orgunit, title, carlicense,
Packit 8cb997
                    sshpubkey, userauthtype, userclass, radius, radiususer,
Packit 8cb997
                    departmentnumber, employeenumber, employeetype,
Packit 8cb997
                    preferredlanguage, noprivate, nomembers)
Packit 8cb997
Packit 8cb997
                # Also check preserved users
Packit 8cb997
                if res_find is None and res_find_preserved is not None:
Packit 8cb997
                    res_find = res_find_preserved
Packit 8cb997
Packit 8cb997
                if action == "user":
Packit 8cb997
                    # Found the user
Packit 8cb997
                    if res_find is not None:
Packit 8cb997
                        # Ignore password and random with
Packit 8cb997
                        # update_password == on_create
Packit 8cb997
                        if update_password == "on_create":
Packit 8cb997
                            if "userpassword" in args:
Packit 8cb997
                                del args["userpassword"]
Packit 8cb997
                            if "random" in args:
Packit 8cb997
                                del args["random"]
Packit 8cb997
                        if "noprivate" in args:
Packit 8cb997
                            del args["noprivate"]
Packit 8cb997
Packit 663f99
                        # Ignore userauthtype if it is empty (for resetting)
Packit 663f99
                        # and not set in for the user
Packit 663f99
                        if "ipauserauthtype" not in res_find and \
Packit 663f99
                           "ipauserauthtype" in args and \
Packit 663f99
                           args["ipauserauthtype"] == ['']:
Packit 663f99
                            del args["ipauserauthtype"]
Packit 663f99
Packit 8cb997
                        # For all settings is args, check if there are
Packit 8cb997
                        # different settings in the find result.
Packit 8cb997
                        # If yes: modify
Packit 8cb997
                        if not compare_args_ipa(ansible_module, args,
Packit 8cb997
                                                res_find):
Packit 8cb997
                            commands.append([name, "user_mod", args])
Packit 8cb997
Packit 8cb997
                    else:
Packit 663f99
                        # Make sure we have a first and last name
Packit 663f99
                        if first is None:
Packit 663f99
                            ansible_module.fail_json(
Packit 663f99
                                msg="First name is needed")
Packit 663f99
                        if last is None:
Packit 663f99
                            ansible_module.fail_json(
Packit 663f99
                                msg="Last name is needed")
Packit 663f99
Packit 8cb997
                        commands.append([name, "user_add", args])
Packit 8cb997
Packit 8cb997
                    # Handle members: principal, manager, certificate and
Packit 8cb997
                    # certmapdata
Packit 8cb997
                    if res_find is not None:
Packit 8cb997
                        # Generate addition and removal lists
Packit 8cb997
                        manager_add = list(
Packit 8cb997
                            set(manager or []) -
Packit 8cb997
                            set(res_find.get("manager", [])))
Packit 8cb997
                        manager_del = list(
Packit 8cb997
                            set(res_find.get("manager", [])) -
Packit 8cb997
                            set(manager or []))
Packit 8cb997
                        principal_add = list(
Packit 8cb997
                            set(principal or []) -
Packit 8cb997
                            set(res_find.get("krbprincipalname", [])))
Packit 8cb997
                        principal_del = list(
Packit 8cb997
                            set(res_find.get("krbprincipalname", [])) -
Packit 8cb997
                            set(principal or []))
Packit 8cb997
Packit 8cb997
                        # Principals are not returned as utf8 for IPA using
Packit 8cb997
                        # python2 using user_find, therefore we need to
Packit 8cb997
                        # convert the principals that we should remove.
Packit 8cb997
                        principal_del = [to_text(x) for x in principal_del]
Packit 8cb997
Packit 8cb997
                        certificate_add = list(
Packit 8cb997
                            set(certificate or []) -
Packit 8cb997
                            set(res_find.get("certificate", [])))
Packit 8cb997
                        certificate_del = list(
Packit 8cb997
                            set(res_find.get("certificate", [])) -
Packit 8cb997
                            set(certificate or []))
Packit 8cb997
                        certmapdata_add = list(
Packit 8cb997
                            set(certmapdata or []) -
Packit 8cb997
                            set(res_find.get("ipaCertMapData", [])))
Packit 8cb997
                        certmapdata_del = list(
Packit 8cb997
                            set(res_find.get("ipaCertMapData", [])) -
Packit 8cb997
                            set(certmapdata or []))
Packit 8cb997
Packit 8cb997
                    else:
Packit 8cb997
                        # Use given managers and principals
Packit 8cb997
                        manager_add = manager or []
Packit 8cb997
                        manager_del = []
Packit 8cb997
                        principal_add = principal or []
Packit 8cb997
                        principal_del = []
Packit 8cb997
                        certificate_add = certificate or []
Packit 8cb997
                        certificate_del = []
Packit 8cb997
                        certmapdata_add = certmapdata or []
Packit 8cb997
                        certmapdata_del = []
Packit 8cb997
Packit 8cb997
                    # Remove canonical principal from principal_del
Packit 8cb997
                    canonical_principal = name + "@" + server_realm
Packit 8cb997
                    if canonical_principal in principal_del:
Packit 8cb997
                        principal_del.remove(canonical_principal)
Packit 8cb997
Packit 8cb997
                    # Add managers
Packit 8cb997
                    if len(manager_add) > 0:
Packit 8cb997
                        commands.append([name, "user_add_manager",
Packit 8cb997
                                         {
Packit 8cb997
                                             "user": manager_add,
Packit 8cb997
                                         }])
Packit 8cb997
                    # Remove managers
Packit 8cb997
                    if len(manager_del) > 0:
Packit 8cb997
                        commands.append([name, "user_remove_manager",
Packit 8cb997
                                         {
Packit 8cb997
                                             "user": manager_del,
Packit 8cb997
                                         }])
Packit 8cb997
Packit 8cb997
                    # Principals need to be added and removed one by one,
Packit 8cb997
                    # because if entry already exists, the processing of
Packit 8cb997
                    # the remaining enries is stopped. The same applies to
Packit 8cb997
                    # the removal of non-existing entries.
Packit 8cb997
Packit 8cb997
                    # Add principals
Packit 8cb997
                    if len(principal_add) > 0:
Packit 8cb997
                        for _principal in principal_add:
Packit 8cb997
                            commands.append([name, "user_add_principal",
Packit 8cb997
                                             {
Packit 8cb997
                                                 "krbprincipalname":
Packit 8cb997
                                                 _principal,
Packit 8cb997
                                             }])
Packit 8cb997
                    # Remove principals
Packit 8cb997
                    if len(principal_del) > 0:
Packit 8cb997
                        for _principal in principal_del:
Packit 8cb997
                            commands.append([name, "user_remove_principal",
Packit 8cb997
                                             {
Packit 8cb997
                                                 "krbprincipalname":
Packit 8cb997
                                                 _principal,
Packit 8cb997
                                             }])
Packit 8cb997
Packit 8cb997
                    # Certificates need to be added and removed one by one,
Packit 8cb997
                    # because if entry already exists, the processing of
Packit 8cb997
                    # the remaining enries is stopped. The same applies to
Packit 8cb997
                    # the removal of non-existing entries.
Packit 8cb997
Packit 8cb997
                    # Add certificates
Packit 8cb997
                    if len(certificate_add) > 0:
Packit 8cb997
                        for _certificate in certificate_add:
Packit 8cb997
                            commands.append([name, "user_add_cert",
Packit 8cb997
                                             {
Packit 8cb997
                                                 "usercertificate":
Packit 8cb997
                                                 _certificate,
Packit 8cb997
                                             }])
Packit 8cb997
                    # Remove certificates
Packit 8cb997
                    if len(certificate_del) > 0:
Packit 8cb997
                        for _certificate in certificate_del:
Packit 8cb997
                            commands.append([name, "user_remove_cert",
Packit 8cb997
                                             {
Packit 8cb997
                                                 "usercertificate":
Packit 8cb997
                                                 _certificate,
Packit 8cb997
                                             }])
Packit 8cb997
Packit 8cb997
                    # certmapdata need to be added and removed one by one,
Packit 8cb997
                    # because issuer and subject can only be done one by
Packit 8cb997
                    # one reliably (https://pagure.io/freeipa/issue/8097)
Packit 8cb997
Packit 8cb997
                    # Add certmapdata
Packit 8cb997
                    if len(certmapdata_add) > 0:
Packit 8cb997
                        for _data in certmapdata_add:
Packit 8cb997
                            commands.append([name, "user_add_certmapdata",
Packit 8cb997
                                             gen_certmapdata_args(_data)])
Packit 8cb997
                    # Remove certmapdata
Packit 8cb997
                    if len(certmapdata_del) > 0:
Packit 8cb997
                        for _data in certmapdata_del:
Packit 8cb997
                            commands.append([name, "user_add_certmapdata",
Packit 8cb997
                                             gen_certmapdata_args(_data)])
Packit 8cb997
Packit 8cb997
                elif action == "member":
Packit 8cb997
                    if res_find is None:
Packit 8cb997
                        ansible_module.fail_json(
Packit 8cb997
                            msg="No user '%s'" % name)
Packit 8cb997
Packit 8cb997
                    # Ensure managers are present
Packit 8cb997
                    if manager is not None and len(manager) > 0:
Packit 8cb997
                        commands.append([name, "user_add_manager",
Packit 8cb997
                                         {
Packit 8cb997
                                             "user": manager,
Packit 8cb997
                                         }])
Packit 8cb997
Packit 8cb997
                    # Principals need to be added and removed one by one,
Packit 8cb997
                    # because if entry already exists, the processing of
Packit 8cb997
                    # the remaining enries is stopped. The same applies to
Packit 8cb997
                    # the removal of non-existing entries.
Packit 8cb997
Packit 8cb997
                    # Ensure principals are present
Packit 8cb997
                    if principal is not None and len(principal) > 0:
Packit 8cb997
                        for _principal in principal:
Packit 8cb997
                            commands.append([name, "user_add_principal",
Packit 8cb997
                                             {
Packit 8cb997
                                                 "krbprincipalname":
Packit 8cb997
                                                 _principal,
Packit 8cb997
                                             }])
Packit 8cb997
Packit 8cb997
                    # Certificates need to be added and removed one by one,
Packit 8cb997
                    # because if entry already exists, the processing of
Packit 8cb997
                    # the remaining enries is stopped. The same applies to
Packit 8cb997
                    # the removal of non-existing entries.
Packit 8cb997
Packit 8cb997
                    # Ensure certificates are present
Packit 8cb997
                    if certificate is not None and len(certificate) > 0:
Packit 8cb997
                        for _certificate in certificate:
Packit 8cb997
                            commands.append([name, "user_add_cert",
Packit 8cb997
                                             {
Packit 8cb997
                                                 "usercertificate":
Packit 8cb997
                                                 _certificate,
Packit 8cb997
                                             }])
Packit 8cb997
Packit 8cb997
                    # certmapdata need to be added and removed one by one,
Packit 8cb997
                    # because issuer and subject can only be done one by
Packit 8cb997
                    # one reliably (https://pagure.io/freeipa/issue/8097)
Packit 8cb997
Packit 8cb997
                    # Ensure certmapdata are present
Packit 8cb997
                    if certmapdata is not None and len(certmapdata) > 0:
Packit 8cb997
                        for _data in certmapdata:
Packit 8cb997
                            commands.append([name, "user_add_certmapdata",
Packit 8cb997
                                             gen_certmapdata_args(_data)])
Packit 8cb997
Packit 8cb997
            elif state == "absent":
Packit 8cb997
                # Also check preserved users
Packit 8cb997
                if res_find is None and res_find_preserved is not None:
Packit 8cb997
                    res_find = res_find_preserved
Packit 8cb997
Packit 8cb997
                if action == "user":
Packit 8cb997
                    if res_find is not None:
Packit 8cb997
                        args = {}
Packit 8cb997
                        if preserve is not None:
Packit 8cb997
                            args["preserve"] = preserve
Packit 8cb997
                        commands.append([name, "user_del", args])
Packit 8cb997
                elif action == "member":
Packit 8cb997
                    if res_find is None:
Packit 8cb997
                        ansible_module.fail_json(
Packit 8cb997
                            msg="No user '%s'" % name)
Packit 8cb997
Packit 8cb997
                    # Ensure managers are absent
Packit 8cb997
                    if manager is not None and len(manager) > 0:
Packit 8cb997
                        commands.append([name, "user_remove_manager",
Packit 8cb997
                                         {
Packit 8cb997
                                             "user": manager,
Packit 8cb997
                                         }])
Packit 8cb997
Packit 8cb997
                    # Principals need to be added and removed one by one,
Packit 8cb997
                    # because if entry already exists, the processing of
Packit 8cb997
                    # the remaining enries is stopped. The same applies to
Packit 8cb997
                    # the removal of non-existing entries.
Packit 8cb997
Packit 8cb997
                    # Ensure principals are absent
Packit 8cb997
                    if principal is not None and len(principal) > 0:
Packit 8cb997
                        commands.append([name, "user_remove_principal",
Packit 8cb997
                                         {
Packit 8cb997
                                             "krbprincipalname": principal,
Packit 8cb997
                                         }])
Packit 8cb997
Packit 8cb997
                    # Certificates need to be added and removed one by one,
Packit 8cb997
                    # because if entry already exists, the processing of
Packit 8cb997
                    # the remaining enries is stopped. The same applies to
Packit 8cb997
                    # the removal of non-existing entries.
Packit 8cb997
Packit 8cb997
                    # Ensure certificates are absent
Packit 8cb997
                    if certificate is not None and len(certificate) > 0:
Packit 8cb997
                        for _certificate in certificate:
Packit 8cb997
                            commands.append([name, "user_remove_cert",
Packit 8cb997
                                             {
Packit 8cb997
                                                 "usercertificate":
Packit 8cb997
                                                 _certificate,
Packit 8cb997
                                             }])
Packit 8cb997
Packit 8cb997
                    # certmapdata need to be added and removed one by one,
Packit 8cb997
                    # because issuer and subject can only be done one by
Packit 8cb997
                    # one reliably (https://pagure.io/freeipa/issue/8097)
Packit 8cb997
Packit 8cb997
                    # Ensure certmapdata are absent
Packit 8cb997
                    if certmapdata is not None and len(certmapdata) > 0:
Packit 8cb997
                        # Using issuer and subject can only be done one by
Packit 8cb997
                        # one reliably (https://pagure.io/freeipa/issue/8097)
Packit 8cb997
                        for _data in certmapdata:
Packit 8cb997
                            commands.append([name, "user_remove_certmapdata",
Packit 8cb997
                                             gen_certmapdata_args(_data)])
Packit 8cb997
            elif state == "undeleted":
Packit 8cb997
                if res_find_preserved is not None:
Packit 8cb997
                    commands.append([name, "user_undel", {}])
Packit 8cb997
                else:
Packit 8cb997
                    raise ValueError("No preserved user '%s'" % name)
Packit 8cb997
Packit 8cb997
            elif state == "enabled":
Packit 8cb997
                if res_find is not None:
Packit 8cb997
                    if res_find["nsaccountlock"]:
Packit 8cb997
                        commands.append([name, "user_enable", {}])
Packit 8cb997
                else:
Packit 8cb997
                    raise ValueError("No disabled user '%s'" % name)
Packit 8cb997
Packit 8cb997
            elif state == "disabled":
Packit 8cb997
                if res_find is not None:
Packit 8cb997
                    if not res_find["nsaccountlock"]:
Packit 8cb997
                        commands.append([name, "user_disable", {}])
Packit 8cb997
                else:
Packit 8cb997
                    raise ValueError("No user '%s'" % name)
Packit 8cb997
Packit 8cb997
            elif state == "unlocked":
Packit 8cb997
                if res_find is not None:
Packit 8cb997
                    commands.append([name, "user_unlock", {}])
Packit 8cb997
Packit 8cb997
            else:
Packit 8cb997
                ansible_module.fail_json(msg="Unkown state '%s'" % state)
Packit 8cb997
Packit 8cb997
        # Execute commands
Packit 8cb997
Packit 8cb997
        errors = []
Packit 8cb997
        for name, command, args in commands:
Packit 8cb997
            try:
Packit 8cb997
                result = api_command(ansible_module, command, name,
Packit 8cb997
                                     args)
Packit 8cb997
                if "completed" in result:
Packit 8cb997
                    if result["completed"] > 0:
Packit 8cb997
                        changed = True
Packit 8cb997
                else:
Packit 8cb997
                    changed = True
Packit 8cb997
Packit 8cb997
                if "random" in args and command in ["user_add", "user_mod"] \
Packit 8cb997
                   and "randompassword" in result["result"]:
Packit 8cb997
                    if len(names) == 1:
Packit 8cb997
                        exit_args["randompassword"] = \
Packit 8cb997
                            result["result"]["randompassword"]
Packit 8cb997
                    else:
Packit 8cb997
                        exit_args.setdefault(name, {})["randompassword"] = \
Packit 8cb997
                            result["result"]["randompassword"]
Packit 8cb997
Packit 8cb997
            except Exception as e:
Packit 8cb997
                msg = str(e)
Packit 8cb997
                if "already contains" in msg \
Packit 8cb997
                   or "does not contain" in msg:
Packit 8cb997
                    continue
Packit 8cb997
                #  The canonical principal name may not be removed
Packit 8cb997
                if "equal to the canonical principal name must" in msg:
Packit 8cb997
                    continue
Packit 8cb997
                ansible_module.fail_json(msg="%s: %s: %s" % (command, name,
Packit 8cb997
                                                             msg))
Packit 8cb997
Packit 8cb997
            # Get all errors
Packit 8cb997
            # All "already a member" and "not a member" failures in the
Packit 8cb997
            # result are ignored. All others are reported.
Packit 8cb997
            if "failed" in result and len(result["failed"]) > 0:
Packit 8cb997
                for item in result["failed"]:
Packit 8cb997
                    failed_item = result["failed"][item]
Packit 8cb997
                    for member_type in failed_item:
Packit 8cb997
                        for member, failure in failed_item[member_type]:
Packit 8cb997
                            if "already a member" in failure \
Packit 8cb997
                               or "not a member" in failure:
Packit 8cb997
                                continue
Packit 8cb997
                            errors.append("%s: %s %s: %s" % (
Packit 8cb997
                                command, member_type, member, failure))
Packit 8cb997
Packit 8cb997
        if len(errors) > 0:
Packit 8cb997
            ansible_module.fail_json(msg=", ".join(errors))
Packit 8cb997
Packit 8cb997
    except Exception as e:
Packit 8cb997
        ansible_module.fail_json(msg=str(e))
Packit 8cb997
Packit 8cb997
    finally:
Packit 8cb997
        temp_kdestroy(ccache_dir, ccache_name)
Packit 8cb997
Packit 8cb997
    # Done
Packit 8cb997
Packit 8cb997
    ansible_module.exit_json(changed=changed, user=exit_args)
Packit 8cb997
Packit 8cb997
Packit 8cb997
if __name__ == "__main__":
Packit 8cb997
    main()