Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

re-add user previous attributes when updating user, fix time format in description to make allow and disallow access time parameters work #55

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ RETURN VALUES:
OPTIONS (= is mandatory):

- allow_access_after
Hour to allow access. Format --:--
Hour to allow access. Format --:--:--
[Default: (null)]
type: str

Expand Down Expand Up @@ -405,7 +405,7 @@ OPTIONS (= is mandatory):
type: bool

- do_not_allow_access_after
Hour to disallow access. Format --:--
Hour to disallow access. Format --:--:--
[Default: (null)]
type: str

Expand Down
32 changes: 26 additions & 6 deletions plugins/modules/guacamole_connections_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@
required: true
type: str

substring_match:
description:
- If true, the module will search for the group_name as a substring of the group name
required: false
type: bool

parent_group:
description:
- Parent group in case this is a sub-group
Expand Down Expand Up @@ -239,7 +245,8 @@ def main():
max_connections_per_user=dict(type='int'),
enable_session_affinity=dict(type='bool'),
state=dict(type='str', choices=['absent', 'present'], default='present'),
force_deletion=dict(type='bool', default=False)
force_deletion=dict(type='bool', default=False),
substring_match=dict(type='bool', default=False)
)

result = dict(changed=False, msg='', connections_group_info={})
Expand Down Expand Up @@ -285,13 +292,22 @@ def main():
module.fail_json(msg=str(e))

# check if the connections group already exists
# If the connections group exists we get the numeric id
# If the connections group exists we get the numeric id and name (later displayed in msg)
guacamole_connections_group_exists = False
guacamole_connections_group_name = module.params.get('group_name')
for group_id, group_info in guacamole_connections_groups_before.items():
if group_info['name'] == module.params.get('group_name'):
group_numeric_id = group_info['identifier']
guacamole_connections_group_exists = True
break
if module.params.get('substring_match'):
if module.params.get('group_name') in group_info['name']:
group_numeric_id = group_info['identifier']
guacamole_connections_group_name = group_info['name']
guacamole_connections_group_exists = True
break
else:
if group_info['name'] == module.params.get('group_name'):
group_numeric_id = group_info['identifier']
guacamole_connections_group_name = group_info['name']
guacamole_connections_group_exists = True
break

# module arg state=present so we have to create a new connections group
# or update an existing one
Expand Down Expand Up @@ -352,6 +368,8 @@ def main():
except GuacamoleError as e:
module.fail_json(msg=str(e))

result['msg'] = "Connections group '%s' deleted" % guacamole_connections_group_name

# if we are here it's because the group exists and force_deletion=false
else:

Expand Down Expand Up @@ -382,6 +400,8 @@ def main():
except GuacamoleError as e:
module.fail_json(msg=str(e))

result['msg'] = "Connections group '%s' deleted" % guacamole_connections_group_name

# if the group has child connections and force_deletion=false fail and exit
else:
module.fail_json(
Expand Down
156 changes: 113 additions & 43 deletions plugins/modules/guacamole_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@
type: list
elements: str

allowed_connections_identifiers:
description:
- List of connections identifiers where this user can connect
type: list
elements: str

state:
description:
- Create or delete the user?
Expand All @@ -92,12 +98,12 @@

allow_access_after:
description:
- Hour to allow access. Format --:--
- Hour to allow access. Format --:--:--
type: str

do_not_allow_access_after:
description:
- Hour to disallow access. Format --:--
- Hour to disallow access. Format --:--:--
type: str

enable_account_after:
Expand Down Expand Up @@ -189,6 +195,7 @@
URL_UPDATE_USER = "{url}/api/session/data/{datasource}/users/{username}?token={token}"
URL_DELETE_USER = URL_UPDATE_USER
URL_GET_USER_PERMISSIONS = "{url}/api/session/data/{datasource}/users/{username}/permissions?token={token}"
URL_GET_USER_ATTRIBUTES = URL_UPDATE_USER
URL_UPDATE_USER_PERMISSIONS = URL_GET_USER_PERMISSIONS
URL_UPDATE_PASSWORD_CURRENT_USER = "{url}/api/session/data/{datasource}/users/{username}/password?token={token}"

Expand All @@ -209,7 +216,7 @@ def guacamole_populate_user_payload(module_params):
"access-window-end": module_params['do_not_allow_access_after'],
"valid-from": module_params['enable_account_after'],
"valid-until": module_params['disable_account_after'],
"timezone": "",
"timezone": module_params["timezone"],
"guac-full-name": module_params['full_name'],
"guac-email-address": module_params['email'],
"guac-organization": module_params['organization'],
Expand Down Expand Up @@ -290,6 +297,27 @@ def guacamole_get_user_permissions(base_url, validate_certs, datasource, usernam
return user_permissions


def guacamole_get_user_attributes(base_url, validate_certs, datasource, username, auth_token):
"""
Return a dict with detailed current attributes for a user
"""

url_get_user_attributes = URL_GET_USER_ATTRIBUTES.format(
url=base_url, datasource=datasource, username=username, token=auth_token)

try:
user_attributes = json.load(open_url(url_get_user_attributes, method='GET', validate_certs=validate_certs))
except ValueError as e:
raise GuacamoleError(
'API returned invalid JSON when trying to obtain user attributes from %s: %s'
% (url_get_user_attributes, str(e)))
except Exception as e:
raise GuacamoleError('Could not obtain user attributes from %s: %s'
% (url_get_user_attributes, str(e)))

return user_attributes


def guacamole_update_user_permissions_for_connection(base_url, validate_certs, datasource, username,
connection_id, operation, auth_token):
"""
Expand Down Expand Up @@ -378,6 +406,7 @@ def main():
username=dict(type='str', aliases=['name'], required=True),
password=dict(type='str', no_log=True),
allowed_connections=dict(type='list', default=[]),
allowed_connections_identifiers=dict(type='list', default=[]),
state=dict(type='str', choices=['absent', 'present'], default='present'),
full_name=dict(type='str', Default=None),
email=dict(type='str', Default=None),
Expand Down Expand Up @@ -465,17 +494,44 @@ def main():
username=module.params.get('username'),
auth_token=guacamole_token['authToken'],
)
user_attributes_before = guacamole_get_user_attributes(
base_url=module.params.get('base_url'),
validate_certs=module.params.get('validate_certs'),
datasource=guacamole_token['dataSource'],
username=module.params.get('username'),
auth_token=guacamole_token['authToken'],
)
except GuacamoleError as e:
module.fail_json(msg=str(e))

# module arg state=present so we must create or update a user in guacamole
if module.params.get('state') == 'present':

# populate the payload with the user info to send to the API
payload = guacamole_populate_user_payload(module.params)

# if the user already exists in guacamole we update it
if guacamole_user_exists:
# Mapping of guacamole attribute keys to module parameter names
attribute_to_param_map = {
"guac-full-name": "full_name",
"guac-email-address": "email",
"guac-organization": "organization",
"guac-organizational-role": "organizational_role",
"disabled": "disabled",
"expired": "expired",
"timezone": "timezone",
"valid-until": "disable_account_after",
"valid-from": "enable_account_after",
"access-window-start": "allow_access_after",
"access-window-end": "do_not_allow_access_after"
}

# Iterate over the mapping and update module parameters with existing user attributes if they are not provided
for attribute_key, param_name in attribute_to_param_map.items():
if user_attributes_before['attributes'][attribute_key] and (module.params[param_name] is None or module.params[param_name] == ''):
module.params[param_name] = user_attributes_before['attributes'][attribute_key]

# populate the payload with the user info to send to the API
payload = guacamole_populate_user_payload(module.params)

try:
guacamole_update_user(
base_url=module.params.get('base_url'),
Expand All @@ -491,6 +547,7 @@ def main():

# if the user doesn't exist in guacamole we create it
else:
payload = guacamole_populate_user_payload(module.params)
try:
guacamole_add_user(
base_url=module.params.get('base_url'),
Expand Down Expand Up @@ -547,19 +604,32 @@ def fetch_parent_grous_id(parentid):
for group_id in guacamole_connections_groups:
if group_id == parentid:
fetch_parent_grous_id(guacamole_connections_groups[group_id]['parentIdentifier'])

fetch_parent_grous_id(conn['parentIdentifier'])

current_conn_ids = set()
current_group_ids = set()
if guacamole_user_exists:
current_conn_ids = set(user_permissions_before['connectionPermissions'].keys())
current_group_ids = set(user_permissions_before['connectionGroupPermissions'].keys())
if conn['identifier'] in module.params['allowed_connections_identifiers']:
allowed_conn_ids.add(conn['identifier'])
def fetch_parent_grous_id(parentid):
if parentid != 'ROOT':
allowed_group_ids.add(parentid)
for group_id in guacamole_connections_groups:
if group_id == parentid:
fetch_parent_grous_id(guacamole_connections_groups[group_id]['parentIdentifier'])

fetch_parent_grous_id(conn['parentIdentifier'])

# current_conn_ids = set()
# current_group_ids = set()
# if guacamole_user_exists:
# current_conn_ids = set(user_permissions_before['connectionPermissions'].keys())
# current_group_ids = set(user_permissions_before['connectionGroupPermissions'].keys())

add_conn_ids = allowed_conn_ids - current_conn_ids
add_group_ids = allowed_group_ids - current_group_ids
delete_conn_ids = current_conn_ids - allowed_conn_ids
delete_group_ids = current_group_ids - allowed_group_ids
add_conn_ids = allowed_conn_ids
add_group_ids = allowed_group_ids
# add_conn_ids = allowed_conn_ids - current_conn_ids
# add_group_ids = allowed_group_ids - current_group_ids
# delete_conn_ids = current_conn_ids - allowed_conn_ids
# delete_group_ids = current_group_ids - allowed_group_ids

for conn_id in add_conn_ids:
try:
Expand Down Expand Up @@ -589,33 +659,33 @@ def fetch_parent_grous_id(parentid):
except GuacamoleError as e:
module.fail_json(msg=str(e))

for conn_id in delete_conn_ids:
try:
guacamole_update_user_permissions_for_connection(
base_url=module.params.get('base_url'),
validate_certs=module.params.get('validate_certs'),
datasource=guacamole_token['dataSource'],
auth_token=guacamole_token['authToken'],
username=module.params.get('username'),
connection_id=conn_id,
operation='remove'
)
except GuacamoleError as e:
module.fail_json(msg=str(e))

for group_id in delete_group_ids:
try:
guacamole_update_user_permissions_for_group(
base_url=module.params.get('base_url'),
validate_certs=module.params.get('validate_certs'),
datasource=guacamole_token['dataSource'],
auth_token=guacamole_token['authToken'],
username=module.params.get('username'),
group_id=group_id,
operation='remove'
)
except GuacamoleError as e:
module.fail_json(msg=str(e))
# for conn_id in delete_conn_ids:
# try:
# guacamole_update_user_permissions_for_connection(
# base_url=module.params.get('base_url'),
# validate_certs=module.params.get('validate_certs'),
# datasource=guacamole_token['dataSource'],
# auth_token=guacamole_token['authToken'],
# username=module.params.get('username'),
# connection_id=conn_id,
# operation='remove'
# )
# except GuacamoleError as e:
# module.fail_json(msg=str(e))

# for group_id in delete_group_ids:
# try:
# guacamole_update_user_permissions_for_group(
# base_url=module.params.get('base_url'),
# validate_certs=module.params.get('validate_certs'),
# datasource=guacamole_token['dataSource'],
# auth_token=guacamole_token['authToken'],
# username=module.params.get('username'),
# group_id=group_id,
# operation='remove'
# )
# except GuacamoleError as e:
# module.fail_json(msg=str(e))


# module arg state=absent so we must delete a user from guacamole
Expand Down
Loading