mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 00:55:19 +00:00
Merge pull request #13680 from pass-by-value/file_perms_no_exit
File perms no exit
This commit is contained in:
commit
50ee9dd5af
@ -57,7 +57,14 @@ class SaltCMD(parsers.SaltCMDOptionParser):
|
||||
self.setup_logfile_logger()
|
||||
|
||||
try:
|
||||
local = salt.client.get_local_client(self.get_config_file_path())
|
||||
# We don't need to bail on config file permission errors
|
||||
# if the CLI
|
||||
# process is run with the -a flag
|
||||
skip_perm_errors = self.options.eauth != ''
|
||||
|
||||
local = salt.client.get_local_client(
|
||||
self.get_config_file_path(),
|
||||
skip_perm_errors=skip_perm_errors)
|
||||
except SaltClientError as exc:
|
||||
self.exit(2, '{0}\n'.format(exc))
|
||||
return
|
||||
|
@ -55,7 +55,8 @@ log = logging.getLogger(__name__)
|
||||
|
||||
def get_local_client(
|
||||
c_path=os.path.join(syspaths.CONFIG_DIR, 'master'),
|
||||
mopts=None):
|
||||
mopts=None,
|
||||
skip_perm_errors=False):
|
||||
'''
|
||||
.. versionadded:: Helium
|
||||
|
||||
@ -71,7 +72,7 @@ def get_local_client(
|
||||
import salt.client.raet
|
||||
return salt.client.raet.LocalClient(mopts=opts)
|
||||
elif opts['transport'] == 'zeromq':
|
||||
return LocalClient(mopts=opts)
|
||||
return LocalClient(mopts=opts, skip_perm_errors=skip_perm_errors)
|
||||
|
||||
|
||||
class LocalClient(object):
|
||||
@ -96,7 +97,7 @@ class LocalClient(object):
|
||||
'''
|
||||
def __init__(self,
|
||||
c_path=os.path.join(syspaths.CONFIG_DIR, 'master'),
|
||||
mopts=None):
|
||||
mopts=None, skip_perm_errors=False):
|
||||
if mopts:
|
||||
self.opts = mopts
|
||||
else:
|
||||
@ -110,6 +111,7 @@ class LocalClient(object):
|
||||
self.opts = salt.config.client_config(c_path)
|
||||
self.serial = salt.payload.Serial(self.opts)
|
||||
self.salt_user = self.__get_user()
|
||||
self.skip_perm_errors = skip_perm_errors
|
||||
self.key = self.__read_master_key()
|
||||
self.event = salt.utils.event.get_event(
|
||||
'master',
|
||||
@ -132,7 +134,9 @@ class LocalClient(object):
|
||||
keyfile = os.path.join(self.opts['cachedir'],
|
||||
'.{0}_key'.format(key_user))
|
||||
# Make sure all key parent directories are accessible
|
||||
salt.utils.verify.check_path_traversal(self.opts['cachedir'], key_user)
|
||||
salt.utils.verify.check_path_traversal(self.opts['cachedir'],
|
||||
key_user,
|
||||
self.skip_perm_errors)
|
||||
|
||||
try:
|
||||
with salt.utils.fopen(keyfile, 'r') as key:
|
||||
@ -1350,6 +1354,11 @@ class LocalClient(object):
|
||||
# Make sure the publisher is running by checking the unix socket
|
||||
if not os.path.exists(os.path.join(self.opts['sock_dir'],
|
||||
'publish_pull.ipc')):
|
||||
log.error(
|
||||
'Unable to connect to the publisher! '
|
||||
'You do not have permissions to access '
|
||||
'{0}'.format(self.opts['sock_dir'])
|
||||
)
|
||||
return {'jid': '0', 'minions': []}
|
||||
|
||||
payload_kwargs = self._prep_pub(
|
||||
|
@ -241,6 +241,8 @@ VALID_OPTS = {
|
||||
'ping_interval': int,
|
||||
'cli_summary': bool,
|
||||
'max_minions': int,
|
||||
'username': str,
|
||||
'password': str,
|
||||
}
|
||||
|
||||
# default configurations
|
||||
@ -360,6 +362,8 @@ DEFAULT_MINION_OPTS = {
|
||||
'raet_port': 4510,
|
||||
'restart_on_error': False,
|
||||
'ping_interval': 0,
|
||||
'username': None,
|
||||
'password': None,
|
||||
}
|
||||
|
||||
DEFAULT_MASTER_OPTS = {
|
||||
|
@ -1653,6 +1653,18 @@ class SaltCMDOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
action='store_true',
|
||||
help=('Display summary information about a salt command')
|
||||
)
|
||||
self.add_option(
|
||||
'--username',
|
||||
dest='username',
|
||||
nargs=1,
|
||||
help=('Username for external authentication')
|
||||
)
|
||||
self.add_option(
|
||||
'--password',
|
||||
dest='password',
|
||||
nargs=1,
|
||||
help=('Password for external authentication')
|
||||
)
|
||||
|
||||
def _mixin_after_parsed(self):
|
||||
if len(self.args) <= 1 and not self.options.doc:
|
||||
|
@ -341,7 +341,7 @@ def list_path_traversal(path):
|
||||
return out
|
||||
|
||||
|
||||
def check_path_traversal(path, user='root'):
|
||||
def check_path_traversal(path, user='root', skip_perm_errors=False):
|
||||
'''
|
||||
Walk from the root up to a directory and verify that the current
|
||||
user has access to read each directory. This is used for making
|
||||
@ -362,6 +362,12 @@ def check_path_traversal(path, user='root'):
|
||||
else:
|
||||
msg += ' Please give {0} read permissions.'.format(user,
|
||||
tpath)
|
||||
|
||||
# We don't need to bail on config file permission errors
|
||||
# if the CLI
|
||||
# process is run with the -a flag
|
||||
if skip_perm_errors:
|
||||
return
|
||||
# Propagate this exception up so there isn't a sys.exit()
|
||||
# in the middle of code that could be imported elsewhere.
|
||||
raise SaltClientError(msg)
|
||||
|
@ -28,7 +28,7 @@ config_opt:
|
||||
yaml_utf8: True
|
||||
|
||||
external_auth:
|
||||
auto:
|
||||
pam:
|
||||
saltdev:
|
||||
- '@wheel'
|
||||
- '@runner'
|
||||
|
82
tests/integration/shell/auth.py
Normal file
82
tests/integration/shell/auth.py
Normal file
@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
tests.integration.shell.auth
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
import os
|
||||
import yaml
|
||||
import pipes
|
||||
import shutil
|
||||
|
||||
# Import Salt Testing libs
|
||||
from salttesting.helpers import (
|
||||
ensure_in_syspath,
|
||||
destructiveTest,
|
||||
with_system_user)
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
# Import salt libs
|
||||
import integration
|
||||
import salt.utils
|
||||
|
||||
from salttesting import skipIf
|
||||
|
||||
import random
|
||||
|
||||
|
||||
class AuthTest(integration.ShellCase):
|
||||
'''
|
||||
Test auth mechanisms
|
||||
'''
|
||||
|
||||
_call_binary_ = 'salt'
|
||||
|
||||
is_root = os.geteuid() != 0
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(is_root, 'You must be logged in as root to run this test')
|
||||
# @with_system_user('saltdev') - doesn't work with ShellCase
|
||||
def test_pam_auth_valid_user(self):
|
||||
'''
|
||||
test pam auth mechanism is working with a valid user
|
||||
'''
|
||||
alphabet = ('abcdefghijklmnopqrstuvwxyz'
|
||||
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||
self.password = ''
|
||||
# generate password
|
||||
for _ in range(20):
|
||||
next_index = random.randrange(len(alphabet))
|
||||
self.password = self.password + alphabet[next_index]
|
||||
|
||||
# hash the password
|
||||
from salt.utils.pycrypto import gen_hash
|
||||
|
||||
pwd = gen_hash('salt', self.password, 'sha512')
|
||||
self.run_call("shadow.set_password saltdev '{0}'".format(pwd))
|
||||
cmd = ('-a pam "*"'
|
||||
' test.ping --username {0}'
|
||||
' --password {1}'.format('saltdev', self.password))
|
||||
|
||||
resp = self.run_salt(cmd)
|
||||
self.assertTrue(
|
||||
'minion:' in resp
|
||||
)
|
||||
|
||||
@skipIf(is_root, 'You must be logged in as root to run this test')
|
||||
def test_pam_auth_invalid_user(self):
|
||||
'''
|
||||
test pam auth mechanism errors for an invalid user
|
||||
'''
|
||||
cmd = ('-a pam'
|
||||
' * test.ping --username nouser'
|
||||
' --password {0}'.format('abcd1234'))
|
||||
resp = self.run_salt(cmd)
|
||||
self.assertTrue(
|
||||
'Failed to authenticate' in ''.join(resp)
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(AuthTest)
|
Loading…
Reference in New Issue
Block a user