mirror of
https://github.com/famedly/ansible-collection-matrix
synced 2024-12-12 20:22:28 +00:00
feat(matrix_token_login): add module for jwt token based logins
This commit is contained in:
parent
337d9123b8
commit
c318acccbd
2 changed files with 168 additions and 4 deletions
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
# (c) 2021, Famedly GmbH
|
||||
# (c) 2021-2022, Famedly GmbH
|
||||
# GNU Affero General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/agpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
@ -26,12 +26,12 @@ class AnsibleNioModule():
|
|||
bypass_checks=False,
|
||||
no_log=False,
|
||||
mutually_exclusive=[['password', 'token']],
|
||||
required_together=[['user_id', 'password']],
|
||||
required_one_of=[['password', 'token']],
|
||||
required_together=None,
|
||||
required_one_of=[['password', 'token', 'key']],
|
||||
required_by={'password': 'user_id', 'key': 'user_id'},
|
||||
add_file_common_args=False,
|
||||
supports_check_mode=True,
|
||||
required_if=None,
|
||||
required_by=None,
|
||||
user_logout=True):
|
||||
|
||||
#If a user/password login is provided, should we logout when exiting?
|
||||
|
|
164
plugins/modules/matrix_token_login.py
Normal file
164
plugins/modules/matrix_token_login.py
Normal file
|
@ -0,0 +1,164 @@
|
|||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
# (c) 2018, Jan Christian Grünhage <jan.christian@gruenhage.xyz>
|
||||
# (c) 2020-2021, Famedly GmbH
|
||||
# (c) 2022 Famedly GmbH
|
||||
# GNU Affero General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/agpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
author: "Jan Christian Grünhage"
|
||||
module: matrix_token_login
|
||||
short_description: Use com.famedly.token based logins to obtain an access token
|
||||
description:
|
||||
- Log in to a matrix homeserver com.famedly.login for authentication and get an access token back
|
||||
options:
|
||||
hs_url:
|
||||
description:
|
||||
- URL of the homeserver, where the CS-API is reachable
|
||||
required: true
|
||||
user_id:
|
||||
description:
|
||||
- The user id of the user
|
||||
required: true
|
||||
key:
|
||||
description:
|
||||
- The key to sign the log in token with
|
||||
required: true
|
||||
admin:
|
||||
description:
|
||||
- Whether to set the user as admin during login
|
||||
requirements:
|
||||
- matrix-nio (Python library)
|
||||
- jwcrypto (Python library)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Log in to matrix
|
||||
matrix_token_login:
|
||||
hs_url: "https://example.famedly.care"
|
||||
user_id: "{{ matrix_user }}"
|
||||
admin: false
|
||||
key: "{{ matrix_token_login_key }}"
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
token:
|
||||
description: The access token aquired by logging in
|
||||
returned: When login was successful
|
||||
type: str
|
||||
device_id:
|
||||
description: The device ID assigned by the server
|
||||
returned: When login was successful
|
||||
type: str
|
||||
'''
|
||||
import traceback
|
||||
import asyncio
|
||||
import json
|
||||
import base64
|
||||
from jwcrypto import jwt, jwk
|
||||
import time
|
||||
|
||||
from ansible_collections.famedly.matrix.plugins.module_utils.matrix import *
|
||||
|
||||
async def run_module():
|
||||
module_args = dict(
|
||||
key=dict(type='str', required=True),
|
||||
admin=dict(type='str', required=False),
|
||||
)
|
||||
|
||||
result = dict(
|
||||
changed=False,
|
||||
msg="",
|
||||
)
|
||||
|
||||
module = AnsibleNioModule(module_args, user_logout=False)
|
||||
|
||||
if module.check_mode:
|
||||
return result
|
||||
|
||||
failed = False
|
||||
|
||||
# Create client object
|
||||
client = AsyncClient(module.params['hs_url'], module.params['user_id'])
|
||||
module.client = client
|
||||
|
||||
# Collect and check login information
|
||||
key = module.params['key']
|
||||
if key is None:
|
||||
await module.fail_json(msg="A key has to be provided")
|
||||
|
||||
admin = module.params['admin']
|
||||
if admin is None:
|
||||
admin = false
|
||||
|
||||
method, path, data = Api.login(
|
||||
client.user,
|
||||
password="",
|
||||
)
|
||||
|
||||
key = {
|
||||
# See rfc7518#section-6.4.1: k should contain the base64url encoded binary key.
|
||||
"k": base64.urlsafe_b64encode(key.encode("utf-8")).decode("utf-8"),
|
||||
"kty": "oct"
|
||||
}
|
||||
key = jwk.JWK(**key)
|
||||
claims = {
|
||||
"iss": "Matrix UIA Login Ansible Module",
|
||||
"sub": client.user,
|
||||
"admin": admin,
|
||||
"exp": int(time.time()) + 60 * 30,
|
||||
}
|
||||
token = jwt.JWT(header={"alg": "HS512"},
|
||||
claims=claims)
|
||||
|
||||
token.make_signed_token(key)
|
||||
|
||||
auth = {
|
||||
"type": "com.famedly.login.token",
|
||||
"identifier" : {
|
||||
"type": "m.id.user",
|
||||
"user": client.user
|
||||
},
|
||||
"token": token.serialize()
|
||||
}
|
||||
|
||||
payload = json.dumps(auth)
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"Content-Length": str(len(payload))
|
||||
}
|
||||
|
||||
raw_response = await client.send(method, path, payload, headers)
|
||||
res = await client.parse_body(raw_response)
|
||||
|
||||
if raw_response.status != 200:
|
||||
failed = True
|
||||
result['msg'] = await raw_response.text()
|
||||
else:
|
||||
result["token"] = res["access_token"]
|
||||
result["device_id"] = res["device_id"]
|
||||
|
||||
if failed:
|
||||
await module.fail_json(**result)
|
||||
else:
|
||||
await module.exit_json(**result)
|
||||
|
||||
|
||||
def main():
|
||||
asyncio.run(run_module())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in a new issue