Skip to content
Snippets Groups Projects
Commit c7db1878 authored by Rafael Guterres Jeffman's avatar Rafael Guterres Jeffman
Browse files

Add support for adding external members to ipagroup.

This patch add support for adding external members to ipagroup which
have the `external` attribute set. It adds another attribute to the
module, `external_members`, which is a list of users or groups from
an external trust, to be added to the group.

This patch requires server-trust-ad to be tested, as such, the tests
have been guarded by a test block, for when such tests are available
in ansible-freeipa CI.

Fixes issue #418
parent 698bd814
No related branches found
No related tags found
No related merge requests found
...@@ -109,6 +109,24 @@ Example playbook to add group members to a group: ...@@ -109,6 +109,24 @@ Example playbook to add group members to a group:
- appops - appops
``` ```
Example playbook to add members from a trusted realm to an external group:
```yaml
--
- name: Playbook to handle groups.
hosts: ipaserver
became: true
- name: Create an external group and add members from a trust to it.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
external: yes
externalmember:
- WINIPA\\Web Users
- WINIPA\\Developers
```
Example playbook to remove groups: Example playbook to remove groups:
```yaml ```yaml
...@@ -148,6 +166,7 @@ Variable | Description | Required ...@@ -148,6 +166,7 @@ Variable | Description | Required
`service` | List of service name strings assigned to this group. Only usable with IPA versions 4.7 and up. | no `service` | List of service name strings assigned to this group. Only usable with IPA versions 4.7 and up. | no
`membermanager_user` | List of member manager users assigned to this group. Only usable with IPA versions 4.8.4 and up. | no `membermanager_user` | List of member manager users assigned to this group. Only usable with IPA versions 4.8.4 and up. | no
`membermanager_group` | List of member manager groups assigned to this group. Only usable with IPA versions 4.8.4 and up. | no `membermanager_group` | List of member manager groups assigned to this group. Only usable with IPA versions 4.8.4 and up. | no
`externalmember` \| `ipaexternalmember` \| `external_member`| List of members of a trusted domain in DOM\\name or name@domain form. | no
`action` | Work on group or member level. It can be on of `member` or `group` and defaults to `group`. | no `action` | Work on group or member level. It can be on of `member` or `group` and defaults to `group`. | no
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | yes `state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | yes
......
...@@ -92,6 +92,12 @@ options: ...@@ -92,6 +92,12 @@ options:
- Only usable with IPA versions 4.8.4 and up. - Only usable with IPA versions 4.8.4 and up.
required: false required: false
type: list type: list
externalmember:
description:
- List of members of a trusted domain in DOM\\name or name@domain form.
required: false
type: list
ailases: ["ipaexternalmember", "external_member"]
action: action:
description: Work on group or member level description: Work on group or member level
default: group default: group
...@@ -145,7 +151,6 @@ EXAMPLES = """ ...@@ -145,7 +151,6 @@ EXAMPLES = """
- sysops - sysops
- appops - appops
# Create a non-POSIX group # Create a non-POSIX group
- ipagroup: - ipagroup:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
...@@ -158,6 +163,15 @@ EXAMPLES = """ ...@@ -158,6 +163,15 @@ EXAMPLES = """
name: nonposix name: nonposix
posix: yes posix: yes
# Create an external group and add members from a trust to it.
- ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
external: yes
externalmember:
- WINIPA\\Web Users
- WINIPA\\Developers
# Remove goups sysops, appops, ops and nongroup # Remove goups sysops, appops, ops and nongroup
- ipagroup: - ipagroup:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
...@@ -203,7 +217,7 @@ def gen_args(description, gid, nomembers): ...@@ -203,7 +217,7 @@ def gen_args(description, gid, nomembers):
return _args return _args
def gen_member_args(user, group, service): def gen_member_args(user, group, service, externalmember):
_args = {} _args = {}
if user is not None: if user is not None:
_args["member_user"] = user _args["member_user"] = user
...@@ -211,12 +225,24 @@ def gen_member_args(user, group, service): ...@@ -211,12 +225,24 @@ def gen_member_args(user, group, service):
_args["member_group"] = group _args["member_group"] = group
if service is not None: if service is not None:
_args["member_service"] = service _args["member_service"] = service
if externalmember is not None:
_args["member_external"] = externalmember
return _args return _args
def is_external_group(res_find):
"""Verify if the result group is an external group."""
return res_find and 'ipaexternalgroup' in res_find['objectclass']
def is_posix_group(res_find):
"""Verify if the result group is an external group."""
return res_find and 'posixgroup' in res_find['objectclass']
def check_objectclass_args(module, res_find, nonposix, posix, external): def check_objectclass_args(module, res_find, nonposix, posix, external):
if res_find and 'posixgroup' in res_find['objectclass']: if is_posix_group(res_find):
if ( if (
(posix is not None and posix is False) (posix is not None and posix is False)
or nonposix or nonposix
...@@ -226,7 +252,7 @@ def check_objectclass_args(module, res_find, nonposix, posix, external): ...@@ -226,7 +252,7 @@ def check_objectclass_args(module, res_find, nonposix, posix, external):
msg="Cannot change `POSIX` status of a group " msg="Cannot change `POSIX` status of a group "
"to `non-POSIX` or `external`.") "to `non-POSIX` or `external`.")
# Can't change an existing external group # Can't change an existing external group
if res_find and 'ipaexternalgroup' in res_find['objectclass']: if is_external_group(res_find):
if ( if (
posix posix
or (nonposix is not None and nonposix is False) or (nonposix is not None and nonposix is False)
...@@ -242,10 +268,10 @@ def should_modify_group(module, res_find, args, nonposix, posix, external): ...@@ -242,10 +268,10 @@ def should_modify_group(module, res_find, args, nonposix, posix, external):
return True return True
if any([posix, nonposix]): if any([posix, nonposix]):
set_posix = posix or (nonposix is not None and not nonposix) set_posix = posix or (nonposix is not None and not nonposix)
if set_posix and 'posixgroup' not in res_find['objectclass']: if set_posix and not is_posix_group(res_find):
return True return True
if 'ipaexternalgroup' not in res_find['objectclass'] and external: if not is_external_group(res_find) and external:
if 'posixgroup' not in res_find['objectclass']: if not is_posix_group(res_find):
return True return True
return False return False
...@@ -272,6 +298,11 @@ def main(): ...@@ -272,6 +298,11 @@ def main():
membermanager_user=dict(required=False, type='list', default=None), membermanager_user=dict(required=False, type='list', default=None),
membermanager_group=dict(required=False, type='list', membermanager_group=dict(required=False, type='list',
default=None), default=None),
externalmember=dict(required=False, type='list', default=None,
aliases=[
"ipaexternalmember",
"external_member"
]),
action=dict(type="str", default="group", action=dict(type="str", default="group",
choices=["member", "group"]), choices=["member", "group"]),
# state # state
...@@ -308,6 +339,7 @@ def main(): ...@@ -308,6 +339,7 @@ def main():
"membermanager_user") "membermanager_user")
membermanager_group = module_params_get(ansible_module, membermanager_group = module_params_get(ansible_module,
"membermanager_group") "membermanager_group")
externalmember = module_params_get(ansible_module, "externalmember")
action = module_params_get(ansible_module, "action") action = module_params_get(ansible_module, "action")
# state # state
state = module_params_get(ansible_module, "state") state = module_params_get(ansible_module, "state")
...@@ -334,7 +366,7 @@ def main(): ...@@ -334,7 +366,7 @@ def main():
invalid = ["description", "gid", "posix", "nonposix", "external", invalid = ["description", "gid", "posix", "nonposix", "external",
"nomembers"] "nomembers"]
if action == "group": if action == "group":
invalid.extend(["user", "group", "service"]) invalid.extend(["user", "group", "service", "externalmember"])
for x in invalid: for x in invalid:
if vars()[x] is not None: if vars()[x] is not None:
ansible_module.fail_json( ansible_module.fail_json(
...@@ -404,10 +436,19 @@ def main(): ...@@ -404,10 +436,19 @@ def main():
if external: if external:
args['external'] = True args['external'] = True
commands.append([name, "group_add", args]) commands.append([name, "group_add", args])
# Set res_find to empty dict for next step # Set res_find dict for next step
res_find = {} res_find = {}
member_args = gen_member_args(user, group, service) # if we just created/modified the group, update res_find
res_find.setdefault("objectclass", [])
if external and not is_external_group(res_find):
res_find["objectclass"].append("ipaexternalgroup")
if posix and not is_posix_group(res_find):
res_find["objectclass"].append("posixgroup")
member_args = gen_member_args(
user, group, service, externalmember
)
if not compare_args_ipa(ansible_module, member_args, if not compare_args_ipa(ansible_module, member_args,
res_find): res_find):
# Generate addition and removal lists # Generate addition and removal lists
...@@ -420,40 +461,48 @@ def main(): ...@@ -420,40 +461,48 @@ def main():
service_add, service_del = gen_add_del_lists( service_add, service_del = gen_add_del_lists(
service, res_find.get("member_service")) service, res_find.get("member_service"))
if has_add_member_service: (externalmember_add,
# Add members externalmember_del) = gen_add_del_lists(
if len(user_add) > 0 or len(group_add) > 0 or \ externalmember, res_find.get("member_external"))
len(service_add) > 0:
commands.append([name, "group_add_member", # setup member args for add/remove members.
{ add_member_args = {
"user": user_add, "user": user_add,
"group": group_add, "group": group_add,
"service": service_add, }
}]) del_member_args = {
# Remove members
if len(user_del) > 0 or len(group_del) > 0 or \
len(service_del) > 0:
commands.append([name, "group_remove_member",
{
"user": user_del, "user": user_del,
"group": group_del, "group": group_del,
"service": service_del, }
}]) if has_add_member_service:
else: add_member_args["service"] = service_add
del_member_args["service"] = service_del
if is_external_group(res_find):
add_member_args["ipaexternalmember"] = \
externalmember_add
del_member_args["ipaexternalmember"] = \
externalmember_del
elif externalmember or external:
ansible_module.fail_json(
msg="Cannot add external members to a "
"non-external group."
)
# Add members # Add members
if len(user_add) > 0 or len(group_add) > 0: add_members = any([user_add, group_add,
commands.append([name, "group_add_member", service_add, externalmember_add])
{ if add_members:
"user": user_add, commands.append(
"group": group_add, [name, "group_add_member", add_member_args]
}]) )
# Remove members # Remove members
if len(user_del) > 0 or len(group_del) > 0: remove_members = any([user_del, group_del,
commands.append([name, "group_remove_member", service_del, externalmember_del])
{ if remove_members:
"user": user_del, commands.append(
"group": group_del, [name, "group_remove_member", del_member_args]
}]) )
membermanager_user_add, membermanager_user_del = \ membermanager_user_add, membermanager_user_del = \
gen_add_del_lists( gen_add_del_lists(
...@@ -492,19 +541,25 @@ def main(): ...@@ -492,19 +541,25 @@ def main():
elif action == "member": elif action == "member":
if res_find is None: if res_find is None:
ansible_module.fail_json(msg="No group '%s'" % name) ansible_module.fail_json(msg="No group '%s'" % name)
if has_add_member_service:
commands.append([name, "group_add_member", add_member_args = {
{
"user": user,
"group": group,
"service": service,
}])
else:
commands.append([name, "group_add_member",
{
"user": user, "user": user,
"group": group, "group": group,
}]) }
if has_add_member_service:
add_member_args["service"] = service
if is_external_group(res_find):
add_member_args["ipaexternalmember"] = externalmember
elif externalmember:
ansible_module.fail_json(
msg="Cannot add external members to a "
"non-external group."
)
if any([user, group, service, externalmember]):
commands.append(
[name, "group_add_member", add_member_args]
)
if has_add_membermanager: if has_add_membermanager:
# Add membermanager users and groups # Add membermanager users and groups
...@@ -527,19 +582,24 @@ def main(): ...@@ -527,19 +582,24 @@ def main():
if res_find is None: if res_find is None:
ansible_module.fail_json(msg="No group '%s'" % name) ansible_module.fail_json(msg="No group '%s'" % name)
if has_add_member_service: del_member_args = {
commands.append([name, "group_remove_member",
{
"user": user,
"group": group,
"service": service,
}])
else:
commands.append([name, "group_remove_member",
{
"user": user, "user": user,
"group": group, "group": group,
}]) }
if has_add_member_service:
del_member_args["service"] = service
if is_external_group(res_find):
del_member_args["ipaexternalmember"] = externalmember
elif externalmember:
ansible_module.fail_json(
msg="Cannot add external members to a "
"non-external group."
)
if any([user, group, service, externalmember]):
commands.append(
[name, "group_remove_member", del_member_args]
)
if has_add_membermanager: if has_add_membermanager:
# Remove membermanager users and groups # Remove membermanager users and groups
......
...@@ -16,3 +16,4 @@ ...@@ -16,3 +16,4 @@
set_fact: set_fact:
ipa_version: "{{ ipa_cmd_version.stdout_lines[0] }}" ipa_version: "{{ ipa_cmd_version.stdout_lines[0] }}"
ipa_api_version: "{{ ipa_cmd_version.stdout_lines[1] }}" ipa_api_version: "{{ ipa_cmd_version.stdout_lines[1] }}"
trust_test_is_supported: no
---
- name: find trust
hosts: ipaserver
become: true
gather_facts: false
tasks:
- include_tasks: ../env_freeipa_facts.yml
- block:
- name: Add nonposix group.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
nonposix: yes
register: result
failed_when: result.failed or not result.changed
- name: Set group to be external
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
external: yes
register: result
failed_when: result.failed or not result.changed
- name: Add AD users to group
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
external_member: "AD\\Domain Users"
register: result
failed_when: result.failed or not result.changed
- name: Add AD users to group, again
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
external_member: "AD\\Domain Users"
register: result
failed_when: result.failed or result.changed
- name: Remove external group
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
state: absent
register: result
failed_when: result.failed or not result.changed
- name: Add nonposix, external group, with AD users.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
nonposix: yes
external: yes
external_member: "AD\\Domain Users"
register: result
failed_when: result.failed or not result.changed
- name: Add nonposix, external group, with AD users, again.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
nonposix: yes
external: yes
external_member: "AD\\Domain Users"
register: result
failed_when: result.failed or result.changed
- name: Remove group
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
state: absent
register: result
failed_when: result.failed or not result.changed
- name: Add nonposix group.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
nonposix: yes
register: result
failed_when: result.failed or not result.changed
- name: Set group to be external, and add users.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
external: yes
external_member: "AD\\Domain Users"
register: result
failed_when: result.failed or not result.changed
- name: Set group to be external, and add users, again.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
external: yes
external_member: "AD\\Domain Users"
register: result
failed_when: result.failed or result.changed
- name: Cleanup environment.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: extgroup
state: absent
when: trust_test_is_supported | default(false)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment