mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-08-02 12:54:52 +00:00
ipauser: Fix certmapdata, add missing certmapdata data option
certmapdata was not processed properly. The certificate was not loaded and therefore the `issuer` and `subject` could not be compared to the certmapdata entries in the user record. The function `load_cert_from_str` from ansible_freeipa_moduleis used for this. Additionally there was no way to use the certmapdata data format. This is now possible with the `data` option in the certmapdata dict. Example: "data: X509:<I>dc=com,dc=example,CN=ca<S>dc=com,dc=example,CN=test" `data` may not be used together with `certificate`, `issuer` and `subject` in the same record. Given certmapdata for the ipauser module is now converted to the internal data representation using also the new function `DN_x500_text` from `ansible_freeipa_module`. New functions `convert_certmapdata` and `check_certmapdata` have been added to ipauser. tests/user/certmapdata/test_user_certmapdata.yml has been extended with additional tasks to verify more complex issuer and subjects and also using the data format.
This commit is contained in:
@@ -417,10 +417,11 @@ Variable | Description | Required
|
|||||||
`employeetype` | Employee Type | no
|
`employeetype` | Employee Type | no
|
||||||
`preferredlanguage` | Preferred Language | no
|
`preferredlanguage` | Preferred Language | no
|
||||||
`certificate` | List of base-64 encoded user certificates. | no
|
`certificate` | List of base-64 encoded user certificates. | no
|
||||||
`certmapdata` | List of certificate mappings. Either `certificate` or `issuer` together with `subject` need to be specified. <br>Options: | no
|
`certmapdata` | List of certificate mappings. Either `data` or `certificate` or `issuer` together with `subject` need to be specified. Only usable with IPA versions 4.5 and up. <br>Options: | no
|
||||||
| `certificate` - Base-64 encoded user certificate | no
|
| `certificate` - Base-64 encoded user certificate, not usable with other certmapdata options. | no
|
||||||
| `issuer` - Issuer of the certificate | no
|
| `issuer` - Issuer of the certificate, only usable together with `usbject` option. | no
|
||||||
| `subject` - Subject of the certificate | no
|
| `subject` - Subject of the certificate, only usable together with `issuer` option. | no
|
||||||
|
| `data` - Certmap data, not usable with other certmapdata options. | no
|
||||||
`noprivate` | Do not create user private group. (bool) | no
|
`noprivate` | Do not create user private group. (bool) | no
|
||||||
`nomembers` | Suppress processing of membership attributes. (bool) | no
|
`nomembers` | Suppress processing of membership attributes. (bool) | no
|
||||||
|
|
||||||
|
|||||||
@@ -186,7 +186,9 @@ options:
|
|||||||
description: List of base-64 encoded user certificates
|
description: List of base-64 encoded user certificates
|
||||||
required: false
|
required: false
|
||||||
certmapdata:
|
certmapdata:
|
||||||
description: List of certificate mappings
|
description:
|
||||||
|
- List of certificate mappings
|
||||||
|
- Only usable with IPA versions 4.5 and up.
|
||||||
options:
|
options:
|
||||||
certificate:
|
certificate:
|
||||||
description: Base-64 encoded user certificate
|
description: Base-64 encoded user certificate
|
||||||
@@ -197,6 +199,9 @@ options:
|
|||||||
subject:
|
subject:
|
||||||
description: Subject of the certificate
|
description: Subject of the certificate
|
||||||
required: false
|
required: false
|
||||||
|
data:
|
||||||
|
description: Certmap data
|
||||||
|
required: false
|
||||||
required: false
|
required: false
|
||||||
noprivate:
|
noprivate:
|
||||||
description: Don't create user private group
|
description: Don't create user private group
|
||||||
@@ -346,7 +351,9 @@ options:
|
|||||||
description: List of base-64 encoded user certificates
|
description: List of base-64 encoded user certificates
|
||||||
required: false
|
required: false
|
||||||
certmapdata:
|
certmapdata:
|
||||||
description: List of certificate mappings
|
description:
|
||||||
|
- List of certificate mappings
|
||||||
|
- Only usable with IPA versions 4.5 and up.
|
||||||
options:
|
options:
|
||||||
certificate:
|
certificate:
|
||||||
description: Base-64 encoded user certificate
|
description: Base-64 encoded user certificate
|
||||||
@@ -357,6 +364,9 @@ options:
|
|||||||
subject:
|
subject:
|
||||||
description: Subject of the certificate
|
description: Subject of the certificate
|
||||||
required: false
|
required: false
|
||||||
|
data:
|
||||||
|
description: Certmap data
|
||||||
|
required: false
|
||||||
required: false
|
required: false
|
||||||
noprivate:
|
noprivate:
|
||||||
description: Don't create user private group
|
description: Don't create user private group
|
||||||
@@ -467,7 +477,8 @@ from ansible.module_utils._text import to_text
|
|||||||
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
|
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
|
||||||
temp_kdestroy, valid_creds, api_connect, api_command, date_format, \
|
temp_kdestroy, valid_creds, api_connect, api_command, date_format, \
|
||||||
compare_args_ipa, module_params_get, api_check_param, api_get_realm, \
|
compare_args_ipa, module_params_get, api_check_param, api_get_realm, \
|
||||||
api_command_no_name, gen_add_del_lists, encode_certificate
|
api_command_no_name, gen_add_del_lists, encode_certificate, \
|
||||||
|
load_cert_from_str, DN_x500_text, api_check_command
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
@@ -645,13 +656,21 @@ def check_parameters(module, state, action,
|
|||||||
certificate = x.get("certificate")
|
certificate = x.get("certificate")
|
||||||
issuer = x.get("issuer")
|
issuer = x.get("issuer")
|
||||||
subject = x.get("subject")
|
subject = x.get("subject")
|
||||||
|
data = x.get("data")
|
||||||
|
|
||||||
|
if data is not None:
|
||||||
|
if certificate is not None or issuer is not None or \
|
||||||
|
subject is not None:
|
||||||
|
module.fail_json(
|
||||||
|
msg="certmapdata: data can not be used with "
|
||||||
|
"certificate, issuer or subject")
|
||||||
|
check_certmapdata(data)
|
||||||
if certificate is not None \
|
if certificate is not None \
|
||||||
and (issuer is not None or subject is not None):
|
and (issuer is not None or subject is not None):
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="certmapdata: certificate can not be used with "
|
msg="certmapdata: certificate can not be used with "
|
||||||
"issuer or subject")
|
"issuer or subject")
|
||||||
if certificate is None:
|
if data is None and certificate is None:
|
||||||
if issuer is None:
|
if issuer is None:
|
||||||
module.fail_json(msg="certmapdata: issuer is missing")
|
module.fail_json(msg="certmapdata: issuer is missing")
|
||||||
if subject is None:
|
if subject is None:
|
||||||
@@ -666,19 +685,48 @@ def extend_emails(email, default_email_domain):
|
|||||||
return email
|
return email
|
||||||
|
|
||||||
|
|
||||||
def gen_certmapdata_args(certmapdata):
|
def convert_certmapdata(certmapdata):
|
||||||
certificate = certmapdata.get("certificate")
|
if certmapdata is None:
|
||||||
issuer = certmapdata.get("issuer")
|
return None
|
||||||
subject = certmapdata.get("subject")
|
|
||||||
|
|
||||||
_args = {}
|
_result = []
|
||||||
if certificate is not None:
|
for x in certmapdata:
|
||||||
_args["certificate"] = certificate
|
certificate = x.get("certificate")
|
||||||
if issuer is not None:
|
issuer = x.get("issuer")
|
||||||
_args["issuer"] = issuer
|
subject = x.get("subject")
|
||||||
if subject is not None:
|
data = x.get("data")
|
||||||
_args["subject"] = subject
|
|
||||||
return _args
|
if data is None:
|
||||||
|
if issuer is None and subject is None:
|
||||||
|
cert = load_cert_from_str(certificate)
|
||||||
|
issuer = cert.issuer
|
||||||
|
subject = cert.subject
|
||||||
|
|
||||||
|
_result.append("X509:<I>%s<S>%s" % (DN_x500_text(issuer),
|
||||||
|
DN_x500_text(subject)))
|
||||||
|
else:
|
||||||
|
_result.append(data)
|
||||||
|
|
||||||
|
return _result
|
||||||
|
|
||||||
|
|
||||||
|
def check_certmapdata(data):
|
||||||
|
if not data.startswith("X509:"):
|
||||||
|
return False
|
||||||
|
|
||||||
|
i = data.find("<I>", 4)
|
||||||
|
s = data.find("<S>", i)
|
||||||
|
issuer = data[i+3:s]
|
||||||
|
subject = data[s+3:]
|
||||||
|
|
||||||
|
if i < 0 or s < 0 or "CN" not in issuer or "CN" not in subject:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def gen_certmapdata_args(certmapdata):
|
||||||
|
return {"ipacertmapdata": to_text(certmapdata)}
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -740,7 +788,8 @@ def main():
|
|||||||
# Here certificate is a simple string
|
# Here certificate is a simple string
|
||||||
certificate=dict(type="str", default=None),
|
certificate=dict(type="str", default=None),
|
||||||
issuer=dict(type="str", default=None),
|
issuer=dict(type="str", default=None),
|
||||||
subject=dict(type="str", default=None)
|
subject=dict(type="str", default=None),
|
||||||
|
data=dict(type="str", default=None)
|
||||||
),
|
),
|
||||||
elements='dict', required=False),
|
elements='dict', required=False),
|
||||||
noprivate=dict(type='bool', default=None),
|
noprivate=dict(type='bool', default=None),
|
||||||
@@ -875,6 +924,7 @@ def main():
|
|||||||
departmentnumber, employeenumber, employeetype, preferredlanguage,
|
departmentnumber, employeenumber, employeetype, preferredlanguage,
|
||||||
certificate, certmapdata, noprivate, nomembers, preserve,
|
certificate, certmapdata, noprivate, nomembers, preserve,
|
||||||
update_password)
|
update_password)
|
||||||
|
certmapdata = convert_certmapdata(certmapdata)
|
||||||
|
|
||||||
# Use users if names is None
|
# Use users if names is None
|
||||||
if users is not None:
|
if users is not None:
|
||||||
@@ -972,6 +1022,7 @@ def main():
|
|||||||
employeetype, preferredlanguage, certificate,
|
employeetype, preferredlanguage, certificate,
|
||||||
certmapdata, noprivate, nomembers, preserve,
|
certmapdata, noprivate, nomembers, preserve,
|
||||||
update_password)
|
update_password)
|
||||||
|
certmapdata = convert_certmapdata(certmapdata)
|
||||||
|
|
||||||
# Extend email addresses
|
# Extend email addresses
|
||||||
|
|
||||||
@@ -1001,6 +1052,16 @@ def main():
|
|||||||
msg="The use of passwordexpiration is not supported by "
|
msg="The use of passwordexpiration is not supported by "
|
||||||
"your IPA version")
|
"your IPA version")
|
||||||
|
|
||||||
|
# Check certmapdata availability.
|
||||||
|
# We need the connected API for this test, therefore it can not
|
||||||
|
# be part of check_parameters as this is used also before the
|
||||||
|
# connection to the API has been established.
|
||||||
|
if certmapdata is not None and \
|
||||||
|
not api_check_command("user_add_certmapdata"):
|
||||||
|
ansible_module.fail_json(
|
||||||
|
msg="The use of certmapdata is not supported by "
|
||||||
|
"your IPA version")
|
||||||
|
|
||||||
# Make sure user exists
|
# Make sure user exists
|
||||||
res_find = find_user(ansible_module, name)
|
res_find = find_user(ansible_module, name)
|
||||||
# Also search for preserved user if the user could not be found
|
# Also search for preserved user if the user could not be found
|
||||||
@@ -1082,7 +1143,7 @@ def main():
|
|||||||
certificate, res_find.get("usercertificate"))
|
certificate, res_find.get("usercertificate"))
|
||||||
|
|
||||||
certmapdata_add, certmapdata_del = gen_add_del_lists(
|
certmapdata_add, certmapdata_del = gen_add_del_lists(
|
||||||
certmapdata, res_find.get("ipaCertMapData"))
|
certmapdata, res_find.get("ipacertmapdata"))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Use given managers and principals
|
# Use given managers and principals
|
||||||
@@ -1169,7 +1230,7 @@ def main():
|
|||||||
# Remove certmapdata
|
# Remove certmapdata
|
||||||
if len(certmapdata_del) > 0:
|
if len(certmapdata_del) > 0:
|
||||||
for _data in certmapdata_del:
|
for _data in certmapdata_del:
|
||||||
commands.append([name, "user_add_certmapdata",
|
commands.append([name, "user_remove_certmapdata",
|
||||||
gen_certmapdata_args(_data)])
|
gen_certmapdata_args(_data)])
|
||||||
|
|
||||||
elif action == "member":
|
elif action == "member":
|
||||||
|
|||||||
@@ -126,8 +126,6 @@
|
|||||||
certmapdata:
|
certmapdata:
|
||||||
- issuer: CN=issuer1
|
- issuer: CN=issuer1
|
||||||
subject: CN=subject1
|
subject: CN=subject1
|
||||||
- issuer: CN=issuer2
|
|
||||||
subject: CN=subject2
|
|
||||||
- issuer: CN=issuer3
|
- issuer: CN=issuer3
|
||||||
subject: CN=subject3
|
subject: CN=subject3
|
||||||
action: member
|
action: member
|
||||||
@@ -142,8 +140,6 @@
|
|||||||
certmapdata:
|
certmapdata:
|
||||||
- issuer: CN=issuer1
|
- issuer: CN=issuer1
|
||||||
subject: CN=subject1
|
subject: CN=subject1
|
||||||
- issuer: CN=issuer2
|
|
||||||
subject: CN=subject2
|
|
||||||
- issuer: CN=issuer3
|
- issuer: CN=issuer3
|
||||||
subject: CN=subject3
|
subject: CN=subject3
|
||||||
action: member
|
action: member
|
||||||
@@ -151,6 +147,85 @@
|
|||||||
register: result
|
register: result
|
||||||
failed_when: result.changed
|
failed_when: result.changed
|
||||||
|
|
||||||
|
- name: User test certmapdata members absent
|
||||||
|
ipauser:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: test
|
||||||
|
certmapdata:
|
||||||
|
- issuer: CN=issuer2
|
||||||
|
subject: CN=subject2
|
||||||
|
action: member
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
failed_when: not result.changed
|
||||||
|
|
||||||
|
- name: User test certmapdata members absent again
|
||||||
|
ipauser:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: test
|
||||||
|
certmapdata:
|
||||||
|
- issuer: CN=issuer2
|
||||||
|
subject: CN=subject2
|
||||||
|
action: member
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
failed_when: result.changed
|
||||||
|
|
||||||
|
- name: User test certmapdata member present
|
||||||
|
ipauser:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: test
|
||||||
|
certmapdata:
|
||||||
|
- issuer: CN=ca,dc=example,dc=com
|
||||||
|
subject: CN=test,dc=example,dc=com
|
||||||
|
action: member
|
||||||
|
register: result
|
||||||
|
failed_when: not result.changed
|
||||||
|
|
||||||
|
- name: User test certmapdata member present again
|
||||||
|
ipauser:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: test
|
||||||
|
certmapdata:
|
||||||
|
- issuer: CN=ca,dc=example,dc=com
|
||||||
|
subject: CN=test,dc=example,dc=com
|
||||||
|
action: member
|
||||||
|
register: result
|
||||||
|
failed_when: result.changed
|
||||||
|
|
||||||
|
- name: User test certmapdata member (data) present again
|
||||||
|
ipauser:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: test
|
||||||
|
certmapdata:
|
||||||
|
- data: X509:<I>dc=com,dc=example,CN=ca<S>dc=com,dc=example,CN=test
|
||||||
|
action: member
|
||||||
|
register: result
|
||||||
|
failed_when: result.changed
|
||||||
|
|
||||||
|
- name: User test certmapdata member absent
|
||||||
|
ipauser:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: test
|
||||||
|
certmapdata:
|
||||||
|
- issuer: CN=ca,dc=example,dc=com
|
||||||
|
subject: CN=test,dc=example,dc=com
|
||||||
|
action: member
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
failed_when: not result.changed
|
||||||
|
|
||||||
|
- name: User test certmapdata member (data) absent again
|
||||||
|
ipauser:
|
||||||
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
name: test
|
||||||
|
certmapdata:
|
||||||
|
- data: X509:<I>dc=com,dc=example,CN=ca<S>dc=com,dc=example,CN=test
|
||||||
|
action: member
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
failed_when: result.changed
|
||||||
|
|
||||||
- name: User test absent
|
- name: User test absent
|
||||||
ipauser:
|
ipauser:
|
||||||
ipaadmin_password: SomeADMINpassword
|
ipaadmin_password: SomeADMINpassword
|
||||||
|
|||||||
Reference in New Issue
Block a user