From 64c933ade24447545af6d86d550fc9b2e3d9dcf9 Mon Sep 17 00:00:00 2001 From: Bailetti Tommaso Date: Tue, 31 Oct 2023 16:53:15 +0100 Subject: [PATCH] feat: added set/set password-policy actions (#23) --- .../get-password-policy/50get_password_policy | 43 +++++++++++ .../get-password-policy/validate-output.json | 71 +++++++++++++++++++ .../set-password-policy/50set_password_policy | 55 ++++++++++++++ .../set-password-policy/validate-input.json | 71 +++++++++++++++++++ 4 files changed, 240 insertions(+) create mode 100755 imageroot/actions/get-password-policy/50get_password_policy create mode 100644 imageroot/actions/get-password-policy/validate-output.json create mode 100755 imageroot/actions/set-password-policy/50set_password_policy create mode 100644 imageroot/actions/set-password-policy/validate-input.json diff --git a/imageroot/actions/get-password-policy/50get_password_policy b/imageroot/actions/get-password-policy/50get_password_policy new file mode 100755 index 00000000..fcb0ed02 --- /dev/null +++ b/imageroot/actions/get-password-policy/50get_password_policy @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2023 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +import json +import re +import subprocess +import sys + +result = subprocess.run(['podman', 'exec', 'samba-dc', 'samba-tool', 'domain', 'passwordsettings', 'show'], + check=True, capture_output=True, text=True) + +password_settings = { + 'expiration': { + 'max_age': int(re.search(r'Maximum password age \(days\): (\d.*)\n', result.stdout).group(1)), + 'min_age': int(re.search(r'Minimum password age \(days\): (\d.*)\n', result.stdout).group(1)) + }, + 'strength': { + 'history_length': int(re.search(r'Password history length: (\d.*)\n', result.stdout).group(1)), + 'password_min_length': int(re.search(r'Minimum password length: (\d.*)\n', result.stdout).group(1)), + 'complexity_check': re.search(r'Password complexity: (.*)\n', result.stdout).group(1) == 'on' + } +} + +password_settings['expiration']['enforced'] = password_settings['expiration']['max_age'] > 0 or \ + password_settings['expiration']['min_age'] > 0 +password_settings['strength']['enforced'] = password_settings['strength']['history_length'] > 0 or \ + password_settings['strength']['password_min_length'] > 0 or \ + password_settings['strength']['complexity_check'] + +if not password_settings['expiration']['enforced']: + password_settings['expiration']['max_age'] = 180 + password_settings['expiration']['min_age'] = 0 + +if not password_settings['strength']['enforced']: + password_settings['strength']['history_length'] = 24 + password_settings['strength']['password_min_length'] = 8 + password_settings['strength']['complexity_check'] = True + +json.dump(password_settings, fp=sys.stdout) diff --git a/imageroot/actions/get-password-policy/validate-output.json b/imageroot/actions/get-password-policy/validate-output.json new file mode 100644 index 00000000..41200d29 --- /dev/null +++ b/imageroot/actions/get-password-policy/validate-output.json @@ -0,0 +1,71 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "get-password-policy output", + "$id": "http://schema.nethserver.org/samba/get-password-policy-output.json", + "description": "Get the domain password policy", + "examples": [ + { + "expiration": { + "enforced": false, + "max_age": 0, + "min_age": 0 + }, + "strength": { + "enforced": true, + "history_length": 24, + "password_min_length": 5, + "complexity_check": true + } + } + ], + "type": "object", + "required": [ + "expiration", + "strength" + ], + "properties": { + "expiration": { + "type": "object", + "required": [ + "enforced", + "max_age", + "min_age" + ], + "properties": { + "enforced": { + "type": "boolean" + }, + "max_age": { + "type": "integer" + }, + "min_age": { + "type": "integer" + } + } + }, + "strength": { + "type": "object", + "required": [ + "enforced", + "history_length", + "password_min_length", + "complexity_check" + ], + "properties": { + "enforced": { + "type": "boolean" + }, + "history_length": { + "type": "integer" + }, + "password_min_length": { + "type": "integer" + }, + "complexity_check": { + "type": "boolean" + } + } + } + }, + "$defs": {} +} diff --git a/imageroot/actions/set-password-policy/50set_password_policy b/imageroot/actions/set-password-policy/50set_password_policy new file mode 100755 index 00000000..a5ef4cf8 --- /dev/null +++ b/imageroot/actions/set-password-policy/50set_password_policy @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2023 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +import json +import subprocess +import sys + +request = json.load(sys.stdin) + +password_policy = { + 'expiration': {}, + 'strength': {} +} + +if request['expiration']['enforced']: + password_policy['expiration']['min_age'] = request['expiration']['min_age'] + password_policy['expiration']['max_age'] = request['expiration']['max_age'] +else: + password_policy['expiration']['min_age'] = 0 + password_policy['expiration']['max_age'] = 0 + +if request['strength']['enforced']: + password_policy['strength']['history_length'] = request['strength']['history_length'] + password_policy['strength']['password_min_length'] = request['strength']['password_min_length'] + password_policy['strength']['complexity_check'] = request['strength']['complexity_check'] +else: + password_policy['strength']['history_length'] = 0 + password_policy['strength']['password_min_length'] = 0 + password_policy['strength']['complexity_check'] = False + +result = subprocess.run( + [ + 'podman', + 'exec', + 'samba-dc', + 'samba-tool', + 'domain', + 'passwordsettings', + 'set', + f'--min-pwd-age={password_policy["expiration"]["min_age"]}', + f'--max-pwd-age={password_policy["expiration"]["max_age"]}', + f'--history-length={password_policy["strength"]["history_length"]}', + f'--min-pwd-length={password_policy["strength"]["password_min_length"]}', + f'--complexity={"on" if password_policy["strength"]["complexity_check"] else "off"}' + ], + check=True, capture_output=True, text=True) + +# print all changes without last two lines (success message and empty line) +json.dump({ + 'changes': result.stdout.split('\n')[:-2] +}, fp=sys.stdout) diff --git a/imageroot/actions/set-password-policy/validate-input.json b/imageroot/actions/set-password-policy/validate-input.json new file mode 100644 index 00000000..a9cc52c5 --- /dev/null +++ b/imageroot/actions/set-password-policy/validate-input.json @@ -0,0 +1,71 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "set-password-policy input", + "$id": "http://schema.nethserver.org/samba/set-password-policy-input.json", + "description": "Set the domain password policy", + "examples": [ + { + "expiration": { + "enforced": false, + "max_age": 0, + "min_age": 0 + }, + "strength": { + "enforced": true, + "history_length": 24, + "password_min_length": 5, + "complexity_check": true + } + } + ], + "type": "object", + "required": [ + "expiration", + "strength" + ], + "properties": { + "expiration": { + "type": "object", + "required": [ + "enforced", + "max_age", + "min_age" + ], + "properties": { + "enforced": { + "type": "boolean" + }, + "max_age": { + "type": "integer" + }, + "min_age": { + "type": "integer" + } + } + }, + "strength": { + "type": "object", + "required": [ + "enforced", + "history_length", + "password_min_length", + "complexity_check" + ], + "properties": { + "enforced": { + "type": "boolean" + }, + "history_length": { + "type": "integer" + }, + "password_min_length": { + "type": "integer" + }, + "complexity_check": { + "type": "boolean" + } + } + } + }, + "$defs": {} +}