Merge pull request #43203 from rallytime/fix-21969

Return a SaltInvocationError when passing incorrect function pattern for wheel/runner functions.
This commit is contained in:
Erik Johnson 2017-09-14 12:17:48 -05:00 committed by GitHub
commit 792cc0eb54
8 changed files with 645 additions and 140 deletions

View file

@ -293,29 +293,31 @@ class LoadAuth(object):
def authenticate_key(self, load, key):
'''
Authenticate a user by the key passed in load.
Return the effective user id (name) if it's differ from the specified one (for sudo).
If the effective user id is the same as passed one return True on success or False on
Return the effective user id (name) if it's different from the specified one (for sudo).
If the effective user id is the same as the passed one, return True on success or False on
failure.
'''
auth_key = load.pop('key')
if not auth_key:
log.warning('Authentication failure of type "user" occurred.')
error_msg = 'Authentication failure of type "user" occurred.'
auth_key = load.pop('key', None)
if auth_key is None:
log.warning(error_msg)
return False
if 'user' in load:
auth_user = AuthUser(load['user'])
if auth_user.is_sudo():
# If someone sudos check to make sure there is no ACL's around their username
if auth_key != key[self.opts.get('user', 'root')]:
log.warning('Authentication failure of type "user" occurred.')
log.warning(error_msg)
return False
return auth_user.sudo_name()
elif load['user'] == self.opts.get('user', 'root') or load['user'] == 'root':
if auth_key != key[self.opts.get('user', 'root')]:
log.warning('Authentication failure of type "user" occurred.')
log.warning(error_msg)
return False
elif auth_user.is_running_user():
if auth_key != key.get(load['user']):
log.warning('Authentication failure of type "user" occurred.')
log.warning(error_msg)
return False
elif auth_key == key.get('root'):
pass
@ -323,15 +325,15 @@ class LoadAuth(object):
if load['user'] in key:
# User is authorised, check key and check perms
if auth_key != key[load['user']]:
log.warning('Authentication failure of type "user" occurred.')
log.warning(error_msg)
return False
return load['user']
else:
log.warning('Authentication failure of type "user" occurred.')
log.warning(error_msg)
return False
else:
if auth_key != key[salt.utils.get_user()]:
log.warning('Authentication failure of type "other" occurred.')
log.warning(error_msg)
return False
return True
@ -413,6 +415,64 @@ class LoadAuth(object):
return auth_list
def check_authentication(self, load, auth_type, key=None, show_username=False):
'''
.. versionadded:: Oxygen
Go through various checks to see if the token/eauth/user can be authenticated.
Returns a dictionary containing the following keys:
- auth_list
- username
- error
If an error is encountered, return immediately with the relevant error dictionary
as authentication has failed. Otherwise, return the username and valid auth_list.
'''
auth_list = []
username = load.get('username', 'UNKNOWN')
ret = {'auth_list': auth_list,
'username': username,
'error': {}}
# Authenticate
if auth_type == 'token':
token = self.authenticate_token(load)
if not token:
ret['error'] = {'name': 'TokenAuthenticationError',
'message': 'Authentication failure of type "token" occurred.'}
return ret
# Update username for token
username = token['name']
ret['username'] = username
auth_list = self.get_auth_list(load, token=token)
elif auth_type == 'eauth':
if not self.authenticate_eauth(load):
ret['error'] = {'name': 'EauthAuthenticationError',
'message': 'Authentication failure of type "eauth" occurred for '
'user {0}.'.format(username)}
return ret
auth_list = self.get_auth_list(load)
elif auth_type == 'user':
if not self.authenticate_key(load, key):
if show_username:
msg = 'Authentication failure of type "user" occurred for user {0}.'.format(username)
else:
msg = 'Authentication failure of type "user" occurred'
ret['error'] = {'name': 'UserAuthenticationError', 'message': msg}
return ret
else:
ret['error'] = {'name': 'SaltInvocationError',
'message': 'Authentication type not supported.'}
return ret
# Authentication checks passed
ret['auth_list'] = auth_list
return ret
class Authorize(object):
'''
@ -558,6 +618,15 @@ class Authorize(object):
load.get('arg', None),
load.get('tgt', None),
load.get('tgt_type', 'glob'))
# Handle possible return of dict data structure from any_auth call to
# avoid a stacktrace. As mentioned in PR #43181, this entire class is
# dead code and is marked for removal in Salt Neon. But until then, we
# should handle the dict return, which is an error and should return
# False until this class is removed.
if isinstance(good, dict):
return False
if not good:
# Accept find_job so the CLI will function cleanly
if load.get('fun', '') != 'saltutil.find_job':
@ -570,7 +639,7 @@ class Authorize(object):
authorization
Note: this will check that the user has at least one right that will let
him execute "load", this does not deal with conflicting rules
the user execute "load", this does not deal with conflicting rules
'''
adata = self.auth_data

View file

@ -1013,30 +1013,33 @@ class LocalFuncs(object):
'''
Send a master control function back to the runner system
'''
if 'token' in load:
auth_type = 'token'
err_name = 'TokenAuthenticationError'
token = self.loadauth.authenticate_token(load)
if not token:
return dict(error=dict(name=err_name,
message='Authentication failure of type "token" occurred.'))
username = token['name']
auth_list = self.loadauth.get_auth_list(load, token)
else:
auth_type = 'eauth'
err_name = 'EauthAuthenticationError'
username = load.get('username', 'UNKNOWN')
if not self.loadauth.authenticate_eauth(load):
return dict(error=dict(name=err_name,
message=('Authentication failure of type "eauth" occurred '
'for user {0}.').format(username)))
auth_list = self.loadauth.get_auth_list(load)
# All runner opts pass through eauth
auth_type, err_name, key = self._prep_auth_info(load)
if not self.ckminions.runner_check(auth_list, load['fun'], load['kwarg']):
return dict(error=dict(name=err_name,
message=('Authentication failure of type "{0}" occurred '
'for user {1}.').format(auth_type, username)))
# Authenticate
auth_check = self.loadauth.check_authentication(load, auth_type)
error = auth_check.get('error')
if error:
# Authentication error occurred: do not continue.
return {'error': error}
# Authorize
runner_check = self.ckminions.runner_check(
auth_check.get('auth_list', []),
load['fun'],
load['kwarg']
)
username = auth_check.get('username')
if not runner_check:
return {'error': {'name': err_name,
'message': 'Authentication failure of type "{0}" occurred '
'for user {1}.'.format(auth_type, username)}}
elif isinstance(runner_check, dict) and 'error' in runner_check:
# A dictionary with an error name/message was handled by ckminions.runner_check
return runner_check
# Authorized. Do the job!
try:
fun = load.pop('fun')
runner_client = salt.runner.RunnerClient(self.opts)
@ -1045,48 +1048,46 @@ class LocalFuncs(object):
username)
except Exception as exc:
log.error('Exception occurred while '
'introspecting {0}: {1}'.format(fun, exc))
return dict(error=dict(name=exc.__class__.__name__,
args=exc.args,
message=str(exc)))
'introspecting {0}: {1}'.format(fun, exc))
return {'error': {'name': exc.__class__.__name__,
'args': exc.args,
'message': str(exc)}}
def wheel(self, load):
'''
Send a master control function back to the wheel system
'''
# All wheel ops pass through eauth
if 'token' in load:
auth_type = 'token'
err_name = 'TokenAuthenticationError'
token = self.loadauth.authenticate_token(load)
if not token:
return dict(error=dict(name=err_name,
message='Authentication failure of type "token" occurred.'))
username = token['name']
auth_list = self.loadauth.get_auth_list(load, token)
elif 'eauth' in load:
auth_type = 'eauth'
err_name = 'EauthAuthenticationError'
username = load.get('username', 'UNKNOWN')
if not self.loadauth.authenticate_eauth(load):
return dict(error=dict(name=err_name,
message=('Authentication failure of type "eauth" occurred for '
'user {0}.').format(username)))
auth_list = self.loadauth.get_auth_list(load)
else:
auth_type = 'user'
err_name = 'UserAuthenticationError'
username = load.get('username', 'UNKNOWN')
if not self.loadauth.authenticate_key(load, self.key):
return dict(error=dict(name=err_name,
message=('Authentication failure of type "user" occurred for '
'user {0}.').format(username)))
auth_type, err_name, key = self._prep_auth_info(load)
# Authenticate
auth_check = self.loadauth.check_authentication(
load,
auth_type,
key=key,
show_username=True
)
error = auth_check.get('error')
if error:
# Authentication error occurred: do not continue.
return {'error': error}
# Authorize
username = auth_check.get('username')
if auth_type != 'user':
if not self.ckminions.wheel_check(auth_list, load['fun'], load['kwarg']):
return dict(error=dict(name=err_name,
message=('Authentication failure of type "{0}" occurred for '
'user {1}.').format(auth_type, username)))
wheel_check = self.ckminions.wheel_check(
auth_check.get('auth_list', []),
load['fun'],
load['kwarg']
)
if not wheel_check:
return {'error': {'name': err_name,
'message': 'Authentication failure of type "{0}" occurred for '
'user {1}.'.format(auth_type, username)}}
elif isinstance(wheel_check, dict) and 'error' in wheel_check:
# A dictionary with an error name/message was handled by ckminions.wheel_check
return wheel_check
# Authenticated. Do the job.
jid = salt.utils.jid.gen_jid(self.opts)
@ -1106,7 +1107,7 @@ class LocalFuncs(object):
'data': data}
except Exception as exc:
log.error('Exception occurred while '
'introspecting {0}: {1}'.format(fun, exc))
'introspecting {0}: {1}'.format(fun, exc))
data['return'] = 'Exception occurred in wheel {0}: {1}: {2}'.format(
fun,
exc.__class__.__name__,
@ -1371,3 +1372,18 @@ class LocalFuncs(object):
},
'pub': pub_load
}
def _prep_auth_info(self, load):
key = None
if 'token' in load:
auth_type = 'token'
err_name = 'TokenAuthenticationError'
elif 'eauth' in load:
auth_type = 'eauth'
err_name = 'EauthAuthenticationError'
else:
auth_type = 'user'
err_name = 'UserAuthenticationError'
key = self.key
return auth_type, err_name, key

View file

@ -1668,44 +1668,36 @@ class ClearFuncs(object):
Send a master control function back to the runner system
'''
# All runner ops pass through eauth
if u'token' in clear_load:
# Authenticate
token = self.loadauth.authenticate_token(clear_load)
auth_type, err_name, key, sensitive_load_keys = self._prep_auth_info(clear_load)
if not token:
return dict(error=dict(name=u'TokenAuthenticationError',
message=u'Authentication failure of type "token" occurred.'))
# Authenticate
auth_check = self.loadauth.check_authentication(clear_load, auth_type, key=key)
error = auth_check.get(u'error')
# Authorize
auth_list = self.loadauth.get_auth_list(clear_load, token)
if error:
# Authentication error occurred: do not continue.
return {u'error': error}
if not self.ckminions.runner_check(auth_list, clear_load[u'fun'], clear_load.get(u'kwarg', {})):
return dict(error=dict(name=u'TokenAuthenticationError',
message=(u'Authentication failure of type "token" occurred for '
u'user {0}.').format(token[u'name'])))
clear_load.pop(u'token')
username = token[u'name']
elif u'eauth' in clear_load:
if not self.loadauth.authenticate_eauth(clear_load):
return dict(error=dict(name=u'EauthAuthenticationError',
message=(u'Authentication failure of type "eauth" occurred for '
u'user {0}.').format(clear_load.get(u'username', u'UNKNOWN'))))
# Authorize
username = auth_check.get(u'username')
if auth_type != u'user':
runner_check = self.ckminions.runner_check(
auth_check.get(u'auth_list', []),
clear_load[u'fun'],
clear_load.get(u'kwarg', {})
)
if not runner_check:
return {u'error': {u'name': err_name,
u'message': u'Authentication failure of type "{0}" occurred for '
u'user {1}.'.format(auth_type, username)}}
elif isinstance(runner_check, dict) and u'error' in runner_check:
# A dictionary with an error name/message was handled by ckminions.runner_check
return runner_check
auth_list = self.loadauth.get_auth_list(clear_load)
if not self.ckminions.runner_check(auth_list, clear_load[u'fun'], clear_load.get(u'kwarg', {})):
return dict(error=dict(name=u'EauthAuthenticationError',
message=(u'Authentication failure of type "eauth" occurred for '
u'user {0}.').format(clear_load.get(u'username', u'UNKNOWN'))))
# No error occurred, consume the password from the clear_load if
# passed
username = clear_load.pop(u'username', u'UNKNOWN')
clear_load.pop(u'password', None)
# No error occurred, consume sensitive settings from the clear_load if passed.
for item in sensitive_load_keys:
clear_load.pop(item, None)
else:
if not self.loadauth.authenticate_key(clear_load, self.key):
return dict(error=dict(name=u'UserAuthenticationError',
message=u'Authentication failure of type "user" occurred'))
if u'user' in clear_load:
username = clear_load[u'user']
if salt.auth.AuthUser(username).is_sudo():
@ -1722,52 +1714,45 @@ class ClearFuncs(object):
username)
except Exception as exc:
log.error(u'Exception occurred while introspecting %s: %s', fun, exc)
return dict(error=dict(name=exc.__class__.__name__,
args=exc.args,
message=str(exc)))
return {u'error': {u'name': exc.__class__.__name__,
u'args': exc.args,
u'message': str(exc)}}
def wheel(self, clear_load):
'''
Send a master control function back to the wheel system
'''
# All wheel ops pass through eauth
username = None
if u'token' in clear_load:
# Authenticate
token = self.loadauth.authenticate_token(clear_load)
if not token:
return dict(error=dict(name=u'TokenAuthenticationError',
message=u'Authentication failure of type "token" occurred.'))
auth_type, err_name, key, sensitive_load_keys = self._prep_auth_info(clear_load)
# Authorize
auth_list = self.loadauth.get_auth_list(clear_load, token)
if not self.ckminions.wheel_check(auth_list, clear_load[u'fun'], clear_load.get(u'kwarg', {})):
return dict(error=dict(name=u'TokenAuthenticationError',
message=(u'Authentication failure of type "token" occurred for '
u'user {0}.').format(token[u'name'])))
clear_load.pop(u'token')
username = token[u'name']
elif u'eauth' in clear_load:
if not self.loadauth.authenticate_eauth(clear_load):
return dict(error=dict(name=u'EauthAuthenticationError',
message=(u'Authentication failure of type "eauth" occurred for '
u'user {0}.').format(clear_load.get(u'username', u'UNKNOWN'))))
# Authenticate
auth_check = self.loadauth.check_authentication(clear_load, auth_type, key=key)
error = auth_check.get(u'error')
auth_list = self.loadauth.get_auth_list(clear_load)
if not self.ckminions.wheel_check(auth_list, clear_load[u'fun'], clear_load.get(u'kwarg', {})):
return dict(error=dict(name=u'EauthAuthenticationError',
message=(u'Authentication failure of type "eauth" occurred for '
u'user {0}.').format(clear_load.get(u'username', u'UNKNOWN'))))
if error:
# Authentication error occurred: do not continue.
return {u'error': error}
# No error occurred, consume the password from the clear_load if
# passed
clear_load.pop(u'password', None)
username = clear_load.pop(u'username', u'UNKNOWN')
# Authorize
username = auth_check.get(u'username')
if auth_type != u'user':
wheel_check = self.ckminions.wheel_check(
auth_check.get(u'auth_list', []),
clear_load[u'fun'],
clear_load.get(u'kwarg', {})
)
if not wheel_check:
return {u'error': {u'name': err_name,
u'message': u'Authentication failure of type "{0}" occurred for '
u'user {1}.'.format(auth_type, username)}}
elif isinstance(wheel_check, dict) and u'error' in wheel_check:
# A dictionary with an error name/message was handled by ckminions.wheel_check
return wheel_check
# No error occurred, consume sensitive settings from the clear_load if passed.
for item in sensitive_load_keys:
clear_load.pop(item, None)
else:
if not self.loadauth.authenticate_key(clear_load, self.key):
return dict(error=dict(name=u'UserAuthenticationError',
message=u'Authentication failure of type "user" occurred'))
if u'user' in clear_load:
username = clear_load[u'user']
if salt.auth.AuthUser(username).is_sudo():
@ -1963,6 +1948,24 @@ class ClearFuncs(object):
}
}
def _prep_auth_info(self, clear_load):
sensitive_load_keys = []
key = None
if u'token' in clear_load:
auth_type = u'token'
err_name = u'TokenAuthenticationError'
sensitive_load_keys = [u'token']
elif u'eauth' in clear_load:
auth_type = u'eauth'
err_name = u'EauthAuthenticationError'
sensitive_load_keys = [u'username', u'password']
else:
auth_type = u'user'
err_name = u'UserAuthenticationError'
key = self.key
return auth_type, err_name, key, sensitive_load_keys
def _prep_jid(self, clear_load, extra):
'''
Return a jid for this publication

View file

@ -985,7 +985,11 @@ class CkMinions(object):
if form != 'cloud':
comps = fun.split('.')
if len(comps) != 2:
return False
# Hint at a syntax error when command is passed improperly,
# rather than returning an authentication error of some kind.
# See Issue #21969 for more information.
return {'error': {'name': 'SaltInvocationError',
'message': 'A command invocation error occurred: Check syntax.'}}
mod_name = comps[0]
fun_name = comps[1]
else:

View file

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View file

@ -0,0 +1,201 @@
# -*- coding: utf-8 -*-
# Import Python libs
from __future__ import absolute_import
# Import Salt libs
import salt.config
import salt.daemons.masterapi as masterapi
# Import Salt Testing Libs
from tests.support.unit import TestCase
from tests.support.mock import (
patch,
MagicMock,
)
class LocalFuncsTestCase(TestCase):
'''
TestCase for salt.daemons.masterapi.LocalFuncs class
'''
def setUp(self):
opts = salt.config.master_config(None)
self.local_funcs = masterapi.LocalFuncs(opts, 'test-key')
def test_runner_token_not_authenticated(self):
'''
Asserts that a TokenAuthenticationError is returned when the token can't authenticate.
'''
mock_ret = {u'error': {u'name': u'TokenAuthenticationError',
u'message': u'Authentication failure of type "token" occurred.'}}
ret = self.local_funcs.runner({u'token': u'asdfasdfasdfasdf'})
self.assertDictEqual(mock_ret, ret)
def test_runner_token_authorization_error(self):
'''
Asserts that a TokenAuthenticationError is returned when the token authenticates, but is
not authorized.
'''
token = u'asdfasdfasdfasdf'
load = {u'token': token, u'fun': u'test.arg', u'kwarg': {}}
mock_token = {u'token': token, u'eauth': u'foo', u'name': u'test'}
mock_ret = {u'error': {u'name': u'TokenAuthenticationError',
u'message': u'Authentication failure of type "token" occurred '
u'for user test.'}}
with patch('salt.auth.LoadAuth.authenticate_token', MagicMock(return_value=mock_token)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.local_funcs.runner(load)
self.assertDictEqual(mock_ret, ret)
def test_runner_token_salt_invocation_error(self):
'''
Asserts that a SaltInvocationError is returned when the token authenticates, but the
command is malformed.
'''
token = u'asdfasdfasdfasdf'
load = {u'token': token, u'fun': u'badtestarg', u'kwarg': {}}
mock_token = {u'token': token, u'eauth': u'foo', u'name': u'test'}
mock_ret = {u'error': {u'name': u'SaltInvocationError',
u'message': u'A command invocation error occurred: Check syntax.'}}
with patch('salt.auth.LoadAuth.authenticate_token', MagicMock(return_value=mock_token)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.local_funcs.runner(load)
self.assertDictEqual(mock_ret, ret)
def test_runner_eauth_not_authenticated(self):
'''
Asserts that an EauthAuthenticationError is returned when the user can't authenticate.
'''
mock_ret = {u'error': {u'name': u'EauthAuthenticationError',
u'message': u'Authentication failure of type "eauth" occurred for '
u'user UNKNOWN.'}}
ret = self.local_funcs.runner({u'eauth': u'foo'})
self.assertDictEqual(mock_ret, ret)
def test_runner_eauth_authorization_error(self):
'''
Asserts that an EauthAuthenticationError is returned when the user authenticates, but is
not authorized.
'''
load = {u'eauth': u'foo', u'username': u'test', u'fun': u'test.arg', u'kwarg': {}}
mock_ret = {u'error': {u'name': u'EauthAuthenticationError',
u'message': u'Authentication failure of type "eauth" occurred for '
u'user test.'}}
with patch('salt.auth.LoadAuth.authenticate_eauth', MagicMock(return_value=True)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.local_funcs.runner(load)
self.assertDictEqual(mock_ret, ret)
def test_runner_eauth_salt_invocation_errpr(self):
'''
Asserts that an EauthAuthenticationError is returned when the user authenticates, but the
command is malformed.
'''
load = {u'eauth': u'foo', u'username': u'test', u'fun': u'bad.test.arg.func', u'kwarg': {}}
mock_ret = {u'error': {u'name': u'SaltInvocationError',
u'message': u'A command invocation error occurred: Check syntax.'}}
with patch('salt.auth.LoadAuth.authenticate_eauth', MagicMock(return_value=True)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.local_funcs.runner(load)
self.assertDictEqual(mock_ret, ret)
def test_wheel_token_not_authenticated(self):
'''
Asserts that a TokenAuthenticationError is returned when the token can't authenticate.
'''
mock_ret = {u'error': {u'name': u'TokenAuthenticationError',
u'message': u'Authentication failure of type "token" occurred.'}}
ret = self.local_funcs.wheel({u'token': u'asdfasdfasdfasdf'})
self.assertDictEqual(mock_ret, ret)
def test_wheel_token_authorization_error(self):
'''
Asserts that a TokenAuthenticationError is returned when the token authenticates, but is
not authorized.
'''
token = u'asdfasdfasdfasdf'
load = {u'token': token, u'fun': u'test.arg', u'kwarg': {}}
mock_token = {u'token': token, u'eauth': u'foo', u'name': u'test'}
mock_ret = {u'error': {u'name': u'TokenAuthenticationError',
u'message': u'Authentication failure of type "token" occurred '
u'for user test.'}}
with patch('salt.auth.LoadAuth.authenticate_token', MagicMock(return_value=mock_token)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.local_funcs.wheel(load)
self.assertDictEqual(mock_ret, ret)
def test_wheel_token_salt_invocation_error(self):
'''
Asserts that a SaltInvocationError is returned when the token authenticates, but the
command is malformed.
'''
token = u'asdfasdfasdfasdf'
load = {u'token': token, u'fun': u'badtestarg', u'kwarg': {}}
mock_token = {u'token': token, u'eauth': u'foo', u'name': u'test'}
mock_ret = {u'error': {u'name': u'SaltInvocationError',
u'message': u'A command invocation error occurred: Check syntax.'}}
with patch('salt.auth.LoadAuth.authenticate_token', MagicMock(return_value=mock_token)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.local_funcs.wheel(load)
self.assertDictEqual(mock_ret, ret)
def test_wheel_eauth_not_authenticated(self):
'''
Asserts that an EauthAuthenticationError is returned when the user can't authenticate.
'''
mock_ret = {u'error': {u'name': u'EauthAuthenticationError',
u'message': u'Authentication failure of type "eauth" occurred for '
u'user UNKNOWN.'}}
ret = self.local_funcs.wheel({u'eauth': u'foo'})
self.assertDictEqual(mock_ret, ret)
def test_wheel_eauth_authorization_error(self):
'''
Asserts that an EauthAuthenticationError is returned when the user authenticates, but is
not authorized.
'''
load = {u'eauth': u'foo', u'username': u'test', u'fun': u'test.arg', u'kwarg': {}}
mock_ret = {u'error': {u'name': u'EauthAuthenticationError',
u'message': u'Authentication failure of type "eauth" occurred for '
u'user test.'}}
with patch('salt.auth.LoadAuth.authenticate_eauth', MagicMock(return_value=True)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.local_funcs.wheel(load)
self.assertDictEqual(mock_ret, ret)
def test_wheel_eauth_salt_invocation_errpr(self):
'''
Asserts that an EauthAuthenticationError is returned when the user authenticates, but the
command is malformed.
'''
load = {u'eauth': u'foo', u'username': u'test', u'fun': u'bad.test.arg.func', u'kwarg': {}}
mock_ret = {u'error': {u'name': u'SaltInvocationError',
u'message': u'A command invocation error occurred: Check syntax.'}}
with patch('salt.auth.LoadAuth.authenticate_eauth', MagicMock(return_value=True)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.local_funcs.wheel(load)
self.assertDictEqual(mock_ret, ret)
def test_wheel_user_not_authenticated(self):
'''
Asserts that an UserAuthenticationError is returned when the user can't authenticate.
'''
mock_ret = {u'error': {u'name': u'UserAuthenticationError',
u'message': u'Authentication failure of type "user" occurred for '
u'user UNKNOWN.'}}
ret = self.local_funcs.wheel({})
self.assertDictEqual(mock_ret, ret)

209
tests/unit/test_master.py Normal file
View file

@ -0,0 +1,209 @@
# -*- coding: utf-8 -*-
# Import Python libs
from __future__ import absolute_import
# Import Salt libs
import salt.config
import salt.master
# Import Salt Testing Libs
from tests.support.unit import TestCase
from tests.support.mock import (
patch,
MagicMock,
)
class ClearFuncsTestCase(TestCase):
'''
TestCase for salt.master.ClearFuncs class
'''
def setUp(self):
opts = salt.config.master_config(None)
self.clear_funcs = salt.master.ClearFuncs(opts, {})
def test_runner_token_not_authenticated(self):
'''
Asserts that a TokenAuthenticationError is returned when the token can't authenticate.
'''
mock_ret = {u'error': {u'name': u'TokenAuthenticationError',
u'message': u'Authentication failure of type "token" occurred.'}}
ret = self.clear_funcs.runner({u'token': u'asdfasdfasdfasdf'})
self.assertDictEqual(mock_ret, ret)
def test_runner_token_authorization_error(self):
'''
Asserts that a TokenAuthenticationError is returned when the token authenticates, but is
not authorized.
'''
token = u'asdfasdfasdfasdf'
clear_load = {u'token': token, u'fun': u'test.arg'}
mock_token = {u'token': token, u'eauth': u'foo', u'name': u'test'}
mock_ret = {u'error': {u'name': u'TokenAuthenticationError',
u'message': u'Authentication failure of type "token" occurred '
u'for user test.'}}
with patch('salt.auth.LoadAuth.authenticate_token', MagicMock(return_value=mock_token)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.clear_funcs.runner(clear_load)
self.assertDictEqual(mock_ret, ret)
def test_runner_token_salt_invocation_error(self):
'''
Asserts that a SaltInvocationError is returned when the token authenticates, but the
command is malformed.
'''
token = u'asdfasdfasdfasdf'
clear_load = {u'token': token, u'fun': u'badtestarg'}
mock_token = {u'token': token, u'eauth': u'foo', u'name': u'test'}
mock_ret = {u'error': {u'name': u'SaltInvocationError',
u'message': u'A command invocation error occurred: Check syntax.'}}
with patch('salt.auth.LoadAuth.authenticate_token', MagicMock(return_value=mock_token)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.clear_funcs.runner(clear_load)
self.assertDictEqual(mock_ret, ret)
def test_runner_eauth_not_authenticated(self):
'''
Asserts that an EauthAuthenticationError is returned when the user can't authenticate.
'''
mock_ret = {u'error': {u'name': u'EauthAuthenticationError',
u'message': u'Authentication failure of type "eauth" occurred for '
u'user UNKNOWN.'}}
ret = self.clear_funcs.runner({u'eauth': u'foo'})
self.assertDictEqual(mock_ret, ret)
def test_runner_eauth_authorization_error(self):
'''
Asserts that an EauthAuthenticationError is returned when the user authenticates, but is
not authorized.
'''
clear_load = {u'eauth': u'foo', u'username': u'test', u'fun': u'test.arg'}
mock_ret = {u'error': {u'name': u'EauthAuthenticationError',
u'message': u'Authentication failure of type "eauth" occurred for '
u'user test.'}}
with patch('salt.auth.LoadAuth.authenticate_eauth', MagicMock(return_value=True)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.clear_funcs.runner(clear_load)
self.assertDictEqual(mock_ret, ret)
def test_runner_eauth_salt_invocation_errpr(self):
'''
Asserts that an EauthAuthenticationError is returned when the user authenticates, but the
command is malformed.
'''
clear_load = {u'eauth': u'foo', u'username': u'test', u'fun': u'bad.test.arg.func'}
mock_ret = {u'error': {u'name': u'SaltInvocationError',
u'message': u'A command invocation error occurred: Check syntax.'}}
with patch('salt.auth.LoadAuth.authenticate_eauth', MagicMock(return_value=True)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.clear_funcs.runner(clear_load)
self.assertDictEqual(mock_ret, ret)
def test_runner_user_not_authenticated(self):
'''
Asserts that an UserAuthenticationError is returned when the user can't authenticate.
'''
mock_ret = {u'error': {u'name': u'UserAuthenticationError',
u'message': u'Authentication failure of type "user" occurred'}}
ret = self.clear_funcs.runner({})
self.assertDictEqual(mock_ret, ret)
def test_wheel_token_not_authenticated(self):
'''
Asserts that a TokenAuthenticationError is returned when the token can't authenticate.
'''
mock_ret = {u'error': {u'name': u'TokenAuthenticationError',
u'message': u'Authentication failure of type "token" occurred.'}}
ret = self.clear_funcs.wheel({u'token': u'asdfasdfasdfasdf'})
self.assertDictEqual(mock_ret, ret)
def test_wheel_token_authorization_error(self):
'''
Asserts that a TokenAuthenticationError is returned when the token authenticates, but is
not authorized.
'''
token = u'asdfasdfasdfasdf'
clear_load = {u'token': token, u'fun': u'test.arg'}
mock_token = {u'token': token, u'eauth': u'foo', u'name': u'test'}
mock_ret = {u'error': {u'name': u'TokenAuthenticationError',
u'message': u'Authentication failure of type "token" occurred '
u'for user test.'}}
with patch('salt.auth.LoadAuth.authenticate_token', MagicMock(return_value=mock_token)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.clear_funcs.wheel(clear_load)
self.assertDictEqual(mock_ret, ret)
def test_wheel_token_salt_invocation_error(self):
'''
Asserts that a SaltInvocationError is returned when the token authenticates, but the
command is malformed.
'''
token = u'asdfasdfasdfasdf'
clear_load = {u'token': token, u'fun': u'badtestarg'}
mock_token = {u'token': token, u'eauth': u'foo', u'name': u'test'}
mock_ret = {u'error': {u'name': u'SaltInvocationError',
u'message': u'A command invocation error occurred: Check syntax.'}}
with patch('salt.auth.LoadAuth.authenticate_token', MagicMock(return_value=mock_token)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.clear_funcs.wheel(clear_load)
self.assertDictEqual(mock_ret, ret)
def test_wheel_eauth_not_authenticated(self):
'''
Asserts that an EauthAuthenticationError is returned when the user can't authenticate.
'''
mock_ret = {u'error': {u'name': u'EauthAuthenticationError',
u'message': u'Authentication failure of type "eauth" occurred for '
u'user UNKNOWN.'}}
ret = self.clear_funcs.wheel({u'eauth': u'foo'})
self.assertDictEqual(mock_ret, ret)
def test_wheel_eauth_authorization_error(self):
'''
Asserts that an EauthAuthenticationError is returned when the user authenticates, but is
not authorized.
'''
clear_load = {u'eauth': u'foo', u'username': u'test', u'fun': u'test.arg'}
mock_ret = {u'error': {u'name': u'EauthAuthenticationError',
u'message': u'Authentication failure of type "eauth" occurred for '
u'user test.'}}
with patch('salt.auth.LoadAuth.authenticate_eauth', MagicMock(return_value=True)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.clear_funcs.wheel(clear_load)
self.assertDictEqual(mock_ret, ret)
def test_wheel_eauth_salt_invocation_errpr(self):
'''
Asserts that an EauthAuthenticationError is returned when the user authenticates, but the
command is malformed.
'''
clear_load = {u'eauth': u'foo', u'username': u'test', u'fun': u'bad.test.arg.func'}
mock_ret = {u'error': {u'name': u'SaltInvocationError',
u'message': u'A command invocation error occurred: Check syntax.'}}
with patch('salt.auth.LoadAuth.authenticate_eauth', MagicMock(return_value=True)), \
patch('salt.auth.LoadAuth.get_auth_list', MagicMock(return_value=[])):
ret = self.clear_funcs.wheel(clear_load)
self.assertDictEqual(mock_ret, ret)
def test_wheel_user_not_authenticated(self):
'''
Asserts that an UserAuthenticationError is returned when the user can't authenticate.
'''
mock_ret = {u'error': {u'name': u'UserAuthenticationError',
u'message': u'Authentication failure of type "user" occurred'}}
ret = self.clear_funcs.wheel({})
self.assertDictEqual(mock_ret, ret)

View file

@ -57,7 +57,9 @@ class CkMinionsTestCase(TestCase):
ret = self.ckminions.spec_check(auth_list, 'test.arg', {}, 'wheel')
self.assertFalse(ret)
ret = self.ckminions.spec_check(auth_list, 'testarg', {}, 'runner')
self.assertFalse(ret)
mock_ret = {'error': {'name': 'SaltInvocationError',
'message': 'A command invocation error occurred: Check syntax.'}}
self.assertDictEqual(mock_ret, ret)
# Test spec in plural form
auth_list = ['@runners']