456 lines
14 KiB
Python
456 lines
14 KiB
Python
#!/usr/bin/python
|
|
# (c) 2019, Whitney Champion <whitney.ellis.champion@gmail.com>
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
ANSIBLE_METADATA = {'metadata_version': '1.0',
|
|
'status': ['preview'],
|
|
'supported_by': 'community'}
|
|
|
|
DOCUMENTATION = """
|
|
module: okta_users
|
|
short_description: Communicate with the Okta API to manage users
|
|
description:
|
|
- The Okta user module manages Okta users
|
|
version_added: "1.0"
|
|
author: "Whitney Champion (@shortstack)"
|
|
options:
|
|
organization:
|
|
description:
|
|
- Okta subdomain for your organization. (i.e.
|
|
mycompany.okta.com).
|
|
required: false
|
|
default: None
|
|
api_key:
|
|
description:
|
|
- Okta API key.
|
|
required: false
|
|
default: None
|
|
action:
|
|
description:
|
|
- Action to take against user API.
|
|
required: false
|
|
default: list
|
|
choices: [ create, update, delete, list, activate, deactivate ]
|
|
id:
|
|
description:
|
|
- ID of the user.
|
|
required: false
|
|
default: None
|
|
login:
|
|
description:
|
|
- Username.
|
|
required: false
|
|
default: None
|
|
activate:
|
|
description:
|
|
- Whether or not the new user is activate.
|
|
required: false
|
|
default: yes
|
|
password:
|
|
description:
|
|
- Password.
|
|
required: false
|
|
default: None
|
|
first_name:
|
|
description:
|
|
- First name.
|
|
required: false
|
|
default: None
|
|
last_name:
|
|
description:
|
|
- Last name.
|
|
required: false
|
|
default: None
|
|
email:
|
|
description:
|
|
- Email.
|
|
required: false
|
|
default: None
|
|
group_ids:
|
|
description:
|
|
- List of Group IDs to add the user to.
|
|
required: false
|
|
default: None
|
|
limit:
|
|
description:
|
|
- List limit.
|
|
required: false
|
|
default: 25
|
|
"""
|
|
|
|
EXAMPLES = '''
|
|
# List users
|
|
- okta_users:
|
|
organization: "unicorns"
|
|
api_key: "TmHvH4LY9HH9MDRDiLChLGwhRjHsarTCBzpwbua3ntnQ"
|
|
limit: 25
|
|
|
|
# Create user
|
|
- okta_users:
|
|
action: create
|
|
organization: "unicorns"
|
|
api_key: "TmHvH4LY9HH9MDRDiLChLGwhRjHsarTCBzpwbua3ntnQ"
|
|
login: "whitney@unicorns.lol"
|
|
first_name: "Whitney"
|
|
last_name: "Champion"
|
|
email: "whitney@unicorns.lol"
|
|
password: "cookiesaredelicious"
|
|
activate: yes
|
|
|
|
# Create user in group(s)
|
|
- okta_users:
|
|
action: create
|
|
organization: "unicorns"
|
|
api_key: "TmHvH4LY9HH9MDRDiLChLGwhRjHsarTCBzpwbua3ntnQ"
|
|
login: "whitney@unicorns.lol"
|
|
first_name: "Whitney"
|
|
last_name: "Champion"
|
|
email: "whitney@unicorns.lol"
|
|
password: "cookiesaredelicious"
|
|
group_ids:
|
|
- "00f5b3gqiLpE114tV2M7"
|
|
activate: yes
|
|
|
|
# Create multiple users in group
|
|
- okta_users:
|
|
action: create
|
|
organization: "crypto"
|
|
api_key: "TmHvH4LY9HH9MDRDiLChLGwhRjHsarTCBzpwbua3ntnQ"
|
|
login: "{{ item.login }}"
|
|
first_name: "{{ item.first_name }}"
|
|
last_name: "{{ item.last_name }}"
|
|
email: "{{ item.email }}"
|
|
password: "{{ item.password }}"
|
|
group_ids:
|
|
- "00f5b3gqiLpE324tV2M7"
|
|
activate: "{{ item.activate }}"
|
|
with_items:
|
|
- { login: "alice@aol.com", first_name: "Alice", last_name: "A", email: "alice@aolcom", password: "ilovebob111", activate: yes }
|
|
- { login: "bob@aol.com", first_name: "Bob", last_name: "B", email: "bob@aolcom", password: "ilovealice111", activate: yes }
|
|
|
|
# Update user's email address
|
|
- okta_users:
|
|
action: update
|
|
organization: "unicorns"
|
|
api_key: "TmHvH4LY9HH9MDRDiLChLGwhRjHsarTCBzpwbua3ntnQ"
|
|
id: "01c5pEucucMPWXjFM456"
|
|
email: "whitney@ihateunicorns.lol"
|
|
|
|
# Activate user
|
|
- okta_users:
|
|
action: activate
|
|
organization: "unicorns"
|
|
api_key: "TmHvH4LY9HH9MDRDiLChLGwhRjHsarTCBzpwbua3ntnQ"
|
|
id: "01c5pEucucMPWXjFM456"
|
|
|
|
# Deactivate user
|
|
- okta_users:
|
|
action: deactivate
|
|
organization: "unicorns"
|
|
api_key: "TmHvH4LY9HH9MDRDiLChLGwhRjHsarTCBzpwbua3ntnQ"
|
|
id: "01c5pEucucMPWXjFM456"
|
|
|
|
# Delete user
|
|
- okta_users:
|
|
action: delete
|
|
organization: "unicorns"
|
|
api_key: "TmHvH4LY9HH9MDRDiLChLGwhRjHsarTCBzpwbua3ntnQ"
|
|
id: "01c5pEucucMPWXjFM456"
|
|
|
|
# Get a list of groups a user is in
|
|
- okta_users:
|
|
action: usergroups
|
|
organization: "unicorns"
|
|
api_key: "TmHvH4LY9HH9MDRDiLChLGwhRjHsarTCBzpwbua3ntnQ"
|
|
id: "01c5pEucucMPWXjFM456"
|
|
|
|
|
|
'''
|
|
|
|
RETURN = r'''
|
|
json:
|
|
description: The JSON response from the Okta API
|
|
returned: always
|
|
type: complex
|
|
msg:
|
|
description: The HTTP message from the request
|
|
returned: always
|
|
type: str
|
|
sample: OK (unknown bytes)
|
|
status:
|
|
description: The HTTP status code from the request
|
|
returned: always
|
|
type: int
|
|
sample: 200
|
|
url:
|
|
description: The actual URL used for the request
|
|
returned: always
|
|
type: str
|
|
sample: https://www.ansible.com/
|
|
'''
|
|
|
|
def create(module,base_url,api_key,login,password_input,email,first_name,last_name,group_ids,activate):
|
|
|
|
headers = '{ "Content-Type": "application/json", "Authorization": "SSWS %s", "Accept": "application/json" }' % (api_key)
|
|
|
|
payload = {}
|
|
profile = {}
|
|
credentials = {}
|
|
password = {}
|
|
groupIds= []
|
|
|
|
if first_name is not None:
|
|
profile['firstName'] = first_name
|
|
if last_name is not None:
|
|
profile['lastName'] = last_name
|
|
if email is not None:
|
|
profile['email'] = email
|
|
if login is not None:
|
|
profile['login'] = login
|
|
if password_input is not None:
|
|
password['value'] = password_input
|
|
if group_ids is not None:
|
|
groupIds = group_ids
|
|
|
|
credentials['password'] = password
|
|
payload['credentials'] = credentials
|
|
payload['groupIds'] = groupIds
|
|
payload['profile'] = profile
|
|
|
|
url = base_url+"?activate=%s" % (activate)
|
|
|
|
response, info = fetch_url(module=module, url=url, headers=json.loads(headers), method='POST', data=module.jsonify(payload))
|
|
|
|
if info['status'] != 200:
|
|
module.fail_json(msg="Fail: %s" % ( "Status: "+str(info['msg']) + ", Message: " + str(info['body'])))
|
|
|
|
try:
|
|
content = response.read()
|
|
except AttributeError:
|
|
content = info.pop('body', '')
|
|
|
|
return info['status'], info['msg'], content, url
|
|
|
|
def update(module,base_url,api_key,id,login,email,first_name,last_name):
|
|
|
|
headers = '{ "Content-Type": "application/json", "Authorization": "SSWS %s", "Accept": "application/json" }' % (api_key)
|
|
|
|
url = base_url+"/%s" % (id)
|
|
|
|
payload = {}
|
|
profile = {}
|
|
|
|
if first_name is not None:
|
|
profile['firstName'] = first_name
|
|
if last_name is not None:
|
|
profile['lastName'] = last_name
|
|
if email is not None:
|
|
profile['email'] = email
|
|
if login is not None:
|
|
profile['login'] = login
|
|
|
|
payload['profile'] = profile
|
|
|
|
response, info = fetch_url(module=module, url=url, headers=json.loads(headers), method='POST', data=module.jsonify(payload))
|
|
|
|
if info['status'] != 200:
|
|
module.fail_json(msg="Fail: %s" % ( "Status: "+str(info['msg']) + ", Message: " + str(info['body'])))
|
|
|
|
try:
|
|
content = response.read()
|
|
except AttributeError:
|
|
content = info.pop('body', '')
|
|
|
|
return info['status'], info['msg'], content, url
|
|
|
|
def delete(module,base_url,api_key,id):
|
|
|
|
headers = '{ "Content-Type": "application/json", "Authorization": "SSWS %s", "Accept": "application/json" }' % (api_key)
|
|
|
|
url = base_url+"/%s" % (id)
|
|
|
|
response, info = fetch_url(module=module, url=url, headers=json.loads(headers), method='DELETE')
|
|
|
|
if info['status'] != 204:
|
|
module.fail_json(msg="Fail: %s" % ( "Status: "+str(info['msg']) + ", Message: " + str(info['body'])))
|
|
|
|
try:
|
|
content = response.read()
|
|
except AttributeError:
|
|
content = info.pop('body', '')
|
|
|
|
return info['status'], info['msg'], content, url
|
|
|
|
def activate(module,base_url,api_key,id):
|
|
|
|
headers = '{ "Content-Type": "application/json", "Authorization": "SSWS %s", "Accept": "application/json" }' % (api_key)
|
|
|
|
url = base_url+"/%s/lifecycle/activate" % (id)
|
|
|
|
response, info = fetch_url(module=module, url=url, headers=json.loads(headers), method='POST')
|
|
|
|
if info['status'] != 200:
|
|
module.fail_json(msg="Fail: %s" % ( "Status: "+str(info['msg']) + ", Message: " + str(info['body'])))
|
|
|
|
try:
|
|
content = response.read()
|
|
except AttributeError:
|
|
content = info.pop('body', '')
|
|
|
|
return info['status'], info['msg'], content, url
|
|
|
|
def deactivate(module,base_url,api_key,id):
|
|
|
|
headers = '{ "Content-Type": "application/json", "Authorization": "SSWS %s", "Accept": "application/json" }' % (api_key)
|
|
|
|
url = base_url+"/%s/lifecycle/deactivate" % (id)
|
|
|
|
response, info = fetch_url(module=module, url=url, headers=json.loads(headers), method='POST')
|
|
|
|
if info['status'] != 200:
|
|
module.fail_json(msg="Fail: %s" % ( "Status: "+str(info['msg']) + ", Message: " + str(info['body'])))
|
|
|
|
try:
|
|
content = response.read()
|
|
except AttributeError:
|
|
content = info.pop('body', '')
|
|
|
|
return info['status'], info['msg'], content, url
|
|
|
|
def list(module,base_url,api_key,limit):
|
|
|
|
headers = '{ "Content-Type": "application/json", "Authorization": "SSWS %s", "Accept": "application/json" }' % (api_key)
|
|
|
|
url = base_url+"/?limit=%s" % (limit)
|
|
|
|
response, info = fetch_url(module=module, url=url, headers=json.loads(headers), method='GET')
|
|
|
|
if info['status'] != 200:
|
|
module.fail_json(msg="Fail: %s" % ( "Status: "+str(info['msg']) + ", Message: " + str(info['body'])))
|
|
|
|
try:
|
|
content = response.read()
|
|
except AttributeError:
|
|
content = info.pop('body', '')
|
|
|
|
return info['status'], info['msg'], content, url
|
|
|
|
def findByLogin(module, base_url, api_key, login):
|
|
headers = '{ "Content-Type": "application/json", "Authorization": "SSWS %s", "Accept": "application/json" }' % (api_key)
|
|
#url = base_url+"?q=%s&limit=1" % (login)
|
|
url = base_url+"?filter=profile.login+eq+\"%s\"" % (login)
|
|
response, info = fetch_url(module=module, url=url, headers=json.loads(headers), method='GET')
|
|
if info['status'] != 200:
|
|
module.fail_json(msg="Fail: %s" % ( "Status: "+str(info['msg']) + ", Message: " + str(info['body'])))
|
|
try:
|
|
content = response.read()
|
|
except AttributeError:
|
|
content = info.pop('body', '')
|
|
return info['status'], info['msg'], content, url
|
|
|
|
def findByName(module, base_url, api_key, Name):
|
|
headers = '{ "Content-Type": "application/json", "Authorization": "SSWS %s", "Accept": "application/json" }' % (api_key)
|
|
url = base_url+"?q=%s&limit=1" % (Name)
|
|
response, info = fetch_url(module=module, url=url, headers=json.loads(headers), method='GET')
|
|
if info['status'] != 200:
|
|
module.fail_json(msg="Fail: %s" % ( "Status: "+str(info['msg']) + ", Message: " + str(info['body'])))
|
|
try:
|
|
content = response.read()
|
|
except AttributeError:
|
|
content = info.pop('body', '')
|
|
return info['status'], info['msg'], content, url
|
|
|
|
def getusergroups(module, base_url, api_key, id):
|
|
headers = '{ "Content-Type": "application/json", "Authorization": "SSWS %s", "Accept": "application/json" }' % (api_key)
|
|
url = base_url+"/%s/groups" % (id)
|
|
response, info = fetch_url(module=module, url=url, headers=json.loads(headers), method='GET')
|
|
|
|
if info['status'] != 200:
|
|
module.fail_json(msg="Fail: %s" % ( "Status: "+str(info['msg']) + ", Message: " + str(info['body'])))
|
|
|
|
try:
|
|
content = response.read()
|
|
except AttributeError:
|
|
content = info.pop('body', '')
|
|
|
|
return info['status'], info['msg'], content, url
|
|
|
|
def main():
|
|
module = AnsibleModule(
|
|
argument_spec = dict(
|
|
organization = dict(type='str', default=None),
|
|
api_key = dict(type='str', no_log=True),
|
|
action = dict(type='str', default='list', choices=['create', 'update', 'delete', 'list', 'activate', 'deactivate', 'usergroups']),
|
|
id = dict(type='str', default=None),
|
|
login = dict(type='str', default=None),
|
|
password = dict(type='str', default=None, no_log=True),
|
|
first_name = dict(type='str', default=None),
|
|
last_name = dict(type='str', default=None),
|
|
email = dict(type='str', default=None),
|
|
group_ids = dict(type='list', default=None),
|
|
limit = dict(type='int', default=25),
|
|
activate = dict(type='bool', default='yes')
|
|
)
|
|
)
|
|
|
|
organization = module.params['organization']
|
|
api_key = module.params['api_key']
|
|
action = module.params['action']
|
|
id = module.params['id']
|
|
login = module.params['login']
|
|
password = module.params['password']
|
|
first_name = module.params['first_name']
|
|
last_name = module.params['last_name']
|
|
email = module.params['email']
|
|
group_ids = module.params['group_ids']
|
|
limit = module.params['limit']
|
|
activate = module.params['activate']
|
|
|
|
base_url = "https://%s-admin.okta.com/api/v1/users" % (organization)
|
|
|
|
if action == "create":
|
|
status, message, content, url = create(module,base_url,api_key,login,password,email,first_name,last_name,group_ids,activate)
|
|
elif action == "update":
|
|
status, message, content, url = update(module,base_url,api_key,id,login,email,first_name,last_name)
|
|
elif action == "delete":
|
|
status, message, content, url = deactivate(module,base_url,api_key,id)
|
|
status, message, content, url = delete(module,base_url,api_key,id)
|
|
elif action == "activate":
|
|
status, message, content, url = activate(module,base_url,api_key,id)
|
|
elif action == "deactivate":
|
|
status, message, content, url = deactivate(module,base_url,api_key,id)
|
|
elif action == "list":
|
|
if login is not None:
|
|
status, message, content, url = findByLogin(module,base_url,api_key,login)
|
|
elif first_name is not None:
|
|
status, message, content, url = findByName(module,base_url,api_key, first_name)
|
|
elif last_name is not None:
|
|
status, message, content, url = findByName(module,base_url,api_key,last_name)
|
|
else:
|
|
status, message, content, url = list(module,base_url,api_key,limit)
|
|
elif action == "usergroups":
|
|
status, message, content, url = getusergroups(module, base_url, api_key, id)
|
|
|
|
uresp = {}
|
|
content = to_text(content, encoding='UTF-8')
|
|
|
|
try:
|
|
js = json.loads(content)
|
|
except ValueError, e:
|
|
js = ""
|
|
|
|
uresp['json'] = js
|
|
uresp['status'] = status
|
|
uresp['msg'] = message
|
|
uresp['url'] = url
|
|
|
|
module.exit_json(**uresp)
|
|
|
|
# import module snippets
|
|
import json
|
|
from ansible.module_utils.basic import *
|
|
from ansible.module_utils.urls import *
|
|
|
|
if __name__ == '__main__':
|
|
main()
|