diff options
author | Florence Blanc-Renaud <flo@redhat.com> | 2018-02-14 14:06:48 +0100 |
---|---|---|
committer | Christian Heimes <cheimes@redhat.com> | 2018-02-15 14:10:48 +0100 |
commit | c701cd21d31e6bdf5f1078cdfca49e410e093e28 (patch) | |
tree | 37a51ccbbaf65801777de2971f3857ace69b7524 | |
parent | 8b6506a5f1176ad768bb0e513436009906b8ff63 (diff) | |
download | freeipa-c701cd21d31e6bdf5f1078cdfca49e410e093e28.tar.gz freeipa-c701cd21d31e6bdf5f1078cdfca49e410e093e28.tar.xz freeipa-c701cd21d31e6bdf5f1078cdfca49e410e093e28.zip |
389-ds OTP lasttoken plugin: Add unit test
Add a xmlrpc test checking that a user cannot delete his last
OTP token.
Related to
https://pagure.io/freeipa/issue/7012
Reviewed-By: Nathaniel McCallum <npmccallum@redhat.com>
Reviewed-By: Alexey Slaykovsky <alexey@slaykovsky.com>
-rw-r--r-- | ipatests/test_xmlrpc/test_otptoken_plugin.py | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/ipatests/test_xmlrpc/test_otptoken_plugin.py b/ipatests/test_xmlrpc/test_otptoken_plugin.py new file mode 100644 index 000000000..2a152464b --- /dev/null +++ b/ipatests/test_xmlrpc/test_otptoken_plugin.py @@ -0,0 +1,173 @@ +# +# Copyright (C) 2018 FreeIPA Contributors see COPYING for license +# + + +""" +Test the otptoken plugin. +""" + +from __future__ import print_function + +import pytest + +from ipalib import api, errors +from ipatests.util import change_principal, unlock_principal_password +from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test +from ipatests.test_xmlrpc.tracker.user_plugin import UserTracker + + +user_password = u'userSecretPassword123' + + +@pytest.fixture +def user(request): + tracker = UserTracker(name=u'user_for_otp_test', + givenname=u'Test', sn=u'User for OTP') + return tracker.make_fixture(request) + + +def id_function(arg): + """ + Return a label for the test parameters. + + The params can be: + - the global config (list containing ipauserauthtypes) + in this case we need to extract the 'disabled' auth type to evaluate + whether user setting override is allowed + Example: [u'disabled', u'otp'] will return a label noOverride-otp + [u'otp', u'password'] otp+password + - the user config (list containing ipauserauthtypes) + - the expected outcome (boolean True if delete should be allowed) + """ + + if isinstance(arg, list): + # The arg is a list, need to extract the override flag + labels = list() + if u'disabled' in arg: + labels.append('noOverride') + + label = 'default' + if arg: + without_override = [item for item in arg if item != u'disabled'] + if without_override: + label = '+'.join(without_override) + labels.append(label) + + return "-".join(labels) + + if isinstance(arg, bool): + return "allowed" if arg else "forbidden" + + return 'default' + + +class TestDeleteLastOtpToken(XMLRPC_test): + + @pytest.mark.parametrize( + "globalCfg,userCfg,allowDelLast", [ + # When Global config is not set and prevents user override, + # it is possible to delete last token + ([u'disabled'], None, True), + ([u'disabled'], [u'otp'], True), + ([u'disabled'], [u'password'], True), + ([u'disabled'], [u'password', u'otp'], True), + # When Global config is not set and allows user override, + # the userCfg applies + # Deletion is forbidden only when usercfg = otp only + (None, None, True), + (None, [u'otp'], False), + (None, [u'password'], True), + (None, [u'password', u'otp'], True), + # When Global config is set to otp and prevents user override, + # it is forbidden to delete last token + ([u'disabled', u'otp'], None, False), + ([u'disabled', u'otp'], [u'otp'], False), + ([u'disabled', u'otp'], [u'password'], False), + ([u'disabled', u'otp'], [u'password', u'otp'], False), + # When Global config is set to otp and allows user override, + # the userCfg applies + # Deletion is forbidden when usercfg = otp only or usercfg not set + ([u'otp'], None, False), + ([u'otp'], [u'otp'], False), + ([u'otp'], [u'password'], True), + ([u'otp'], [u'password', u'otp'], True), + # When Global config is set to password and prevents user override, + # it is possible to delete last token + ([u'disabled', u'password'], None, True), + ([u'disabled', u'password'], [u'otp'], True), + ([u'disabled', u'password'], [u'password'], True), + ([u'disabled', u'password'], [u'password', u'otp'], True), + # When Global config is set to password and allows user override, + # the userCfg applies + # Deletion is forbidden when usercfg = otp only + ([u'password'], None, True), + ([u'password'], [u'otp'], False), + ([u'password'], [u'password'], True), + ([u'password'], [u'password', u'otp'], True), + # When Global config is set to password+otp and prevents user + # override, it is possible to delete last token + ([u'disabled', u'password', u'otp'], None, True), + ([u'disabled', u'password', u'otp'], [u'otp'], True), + ([u'disabled', u'password', u'otp'], [u'password'], True), + ([u'disabled', u'password', u'otp'], [u'password', u'otp'], True), + # When Global config is set to password+otp and allows user + # override, the userCfg applies + # Deletion is forbidden when usercfg = otp only + ([u'password', u'otp'], None, True), + ([u'password', u'otp'], [u'otp'], False), + ([u'password', u'otp'], [u'password'], True), + ([u'password', u'otp'], [u'password', u'otp'], True), + ], + ids=id_function) + def test_delete(self, globalCfg, userCfg, allowDelLast, user): + """ + Test the deletion of the last otp token + + The user auth type can be defined at a global level, or + per-user if the override is not disabled. + Depending on the resulting setting, the deletion of last token + is allowed or forbidden. + """ + # Save current global config + result = api.Command.config_show() + current_globalCfg = result.get('ipauserauthtype', None) + + try: + # Set the global config for the test + api.Command.config_mod(ipauserauthtype=globalCfg) + except errors.EmptyModlist: + pass + + try: + user.ensure_exists() + api.Command.user_mod(user.name, userpassword=user_password) + unlock_principal_password(user.name, + user_password, user_password) + # Set the user config for the test + api.Command.user_mod(user.name, ipauserauthtype=userCfg) + + # Connect as user, create and delete the token + with change_principal(user.name, user_password): + api.Command.otptoken_add(u'lastotp', description=u'last otp', + ipatokenowner=user.name) + if allowDelLast: + # We are expecting the del command to succeed + api.Command.otptoken_del(u'lastotp') + else: + # We are expecting the del command to fail + with pytest.raises(errors.DatabaseError): + api.Command.otptoken_del(u'lastotp') + + finally: + # Make sure the token is removed + try: + api.Command.otptoken_del(u'lastotp',) + except errors.NotFound: + pass + + # Restore the previous ipauserauthtype + try: + api.Command.config_mod(ipauserauthtype=current_globalCfg) + except errors.EmptyModlist: + pass |