mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #51152 from garethgreenaway/50433_handle_grants_better
[2018.3] Fixes to mysql module to handle ALL PRIVILEGES grant
This commit is contained in:
commit
8bb589dbc1
2 changed files with 191 additions and 31 deletions
|
@ -81,7 +81,11 @@ __grants__ = [
|
|||
'ALL PRIVILEGES',
|
||||
'ALTER',
|
||||
'ALTER ROUTINE',
|
||||
'BACKUP_ADMIN',
|
||||
'BINLOG_ADMIN',
|
||||
'CONNECTION_ADMIN',
|
||||
'CREATE',
|
||||
'CREATE ROLE',
|
||||
'CREATE ROUTINE',
|
||||
'CREATE TABLESPACE',
|
||||
'CREATE TEMPORARY TABLES',
|
||||
|
@ -89,26 +93,37 @@ __grants__ = [
|
|||
'CREATE VIEW',
|
||||
'DELETE',
|
||||
'DROP',
|
||||
'DROP ROLE',
|
||||
'ENCRYPTION_KEY_ADMIN',
|
||||
'EVENT',
|
||||
'EXECUTE',
|
||||
'FILE',
|
||||
'GRANT OPTION',
|
||||
'GROUP_REPLICATION_ADMIN',
|
||||
'INDEX',
|
||||
'INSERT',
|
||||
'LOCK TABLES',
|
||||
'PERSIST_RO_VARIABLES_ADMIN',
|
||||
'PROCESS',
|
||||
'REFERENCES',
|
||||
'RELOAD',
|
||||
'REPLICATION CLIENT',
|
||||
'REPLICATION SLAVE',
|
||||
'REPLICATION_SLAVE_ADMIN',
|
||||
'RESOURCE_GROUP_ADMIN',
|
||||
'RESOURCE_GROUP_USER',
|
||||
'ROLE_ADMIN',
|
||||
'SELECT',
|
||||
'SET_USER_ID',
|
||||
'SHOW DATABASES',
|
||||
'SHOW VIEW',
|
||||
'SHUTDOWN',
|
||||
'SUPER',
|
||||
'SYSTEM_VARIABLES_ADMIN',
|
||||
'TRIGGER',
|
||||
'UPDATE',
|
||||
'USAGE'
|
||||
'USAGE',
|
||||
'XA_RECOVER_ADMIN'
|
||||
]
|
||||
|
||||
__ssl_options_parameterized__ = [
|
||||
|
@ -121,6 +136,52 @@ __ssl_options__ = __ssl_options_parameterized__ + [
|
|||
'X509'
|
||||
]
|
||||
|
||||
__all_privileges__ = [
|
||||
'ALTER',
|
||||
'ALTER ROUTINE',
|
||||
'BACKUP_ADMIN',
|
||||
'BINLOG_ADMIN',
|
||||
'CONNECTION_ADMIN',
|
||||
'CREATE',
|
||||
'CREATE ROLE',
|
||||
'CREATE ROUTINE',
|
||||
'CREATE TABLESPACE',
|
||||
'CREATE TEMPORARY TABLES',
|
||||
'CREATE USER',
|
||||
'CREATE VIEW',
|
||||
'DELETE',
|
||||
'DROP',
|
||||
'DROP ROLE',
|
||||
'ENCRYPTION_KEY_ADMIN',
|
||||
'EVENT',
|
||||
'EXECUTE',
|
||||
'FILE',
|
||||
'GROUP_REPLICATION_ADMIN',
|
||||
'INDEX',
|
||||
'INSERT',
|
||||
'LOCK TABLES',
|
||||
'PERSIST_RO_VARIABLES_ADMIN',
|
||||
'PROCESS',
|
||||
'REFERENCES',
|
||||
'RELOAD',
|
||||
'REPLICATION CLIENT',
|
||||
'REPLICATION SLAVE',
|
||||
'REPLICATION_SLAVE_ADMIN',
|
||||
'RESOURCE_GROUP_ADMIN',
|
||||
'RESOURCE_GROUP_USER',
|
||||
'ROLE_ADMIN',
|
||||
'SELECT',
|
||||
'SET_USER_ID',
|
||||
'SHOW DATABASES',
|
||||
'SHOW VIEW',
|
||||
'SHUTDOWN',
|
||||
'SUPER',
|
||||
'SYSTEM_VARIABLES_ADMIN',
|
||||
'TRIGGER',
|
||||
'UPDATE',
|
||||
'XA_RECOVER_ADMIN'
|
||||
]
|
||||
|
||||
r'''
|
||||
DEVELOPER NOTE: ABOUT arguments management, escapes, formats, arguments and
|
||||
security of SQL.
|
||||
|
@ -1789,12 +1850,12 @@ def user_grants(user,
|
|||
|
||||
|
||||
def grant_exists(grant,
|
||||
database,
|
||||
user,
|
||||
host='localhost',
|
||||
grant_option=False,
|
||||
escape=True,
|
||||
**connection_args):
|
||||
database,
|
||||
user,
|
||||
host='localhost',
|
||||
grant_option=False,
|
||||
escape=True,
|
||||
**connection_args):
|
||||
'''
|
||||
Checks to see if a grant exists in the database
|
||||
|
||||
|
@ -1805,6 +1866,14 @@ def grant_exists(grant,
|
|||
salt '*' mysql.grant_exists \
|
||||
'SELECT,INSERT,UPDATE,...' 'database.*' 'frank' 'localhost'
|
||||
'''
|
||||
|
||||
server_version = version(**connection_args)
|
||||
if 'ALL' in grant:
|
||||
if salt.utils.versions.version_cmp(server_version, '8.0') >= 0:
|
||||
grant = ','.join([i for i in __all_privileges__])
|
||||
else:
|
||||
grant = 'ALL PRIVILEGES'
|
||||
|
||||
try:
|
||||
target = __grant_generate(
|
||||
grant, database, user, host, grant_option, escape
|
||||
|
@ -1820,15 +1889,27 @@ def grant_exists(grant,
|
|||
'this could also indicate a connection error. Check your configuration.')
|
||||
return False
|
||||
|
||||
target_tokens = None
|
||||
# Combine grants that match the same database
|
||||
_grants = {}
|
||||
for grant in grants:
|
||||
try:
|
||||
if not target_tokens: # Avoid the overhead of re-calc in loop
|
||||
target_tokens = _grant_to_tokens(target)
|
||||
grant_tokens = _grant_to_tokens(grant)
|
||||
grant_token = _grant_to_tokens(grant)
|
||||
if grant_token['database'] not in _grants:
|
||||
_grants[grant_token['database']] = {'user': grant_token['user'],
|
||||
'database': grant_token['database'],
|
||||
'host': grant_token['host'],
|
||||
'grant': grant_token['grant']}
|
||||
else:
|
||||
_grants[grant_token['database']]['grant'].extend(grant_token['grant'])
|
||||
|
||||
target_tokens = _grant_to_tokens(target)
|
||||
for database, grant_tokens in _grants.items():
|
||||
try:
|
||||
_grant_tokens = {}
|
||||
_target_tokens = {}
|
||||
|
||||
_grant_matches = [True if i in grant_tokens['grant']
|
||||
else False for i in target_tokens['grant']]
|
||||
|
||||
for item in ['user', 'database', 'host']:
|
||||
_grant_tokens[item] = grant_tokens[item].replace('"', '').replace('\\', '').replace('`', '')
|
||||
_target_tokens[item] = target_tokens[item].replace('"', '').replace('\\', '').replace('`', '')
|
||||
|
@ -1836,7 +1917,7 @@ def grant_exists(grant,
|
|||
if _grant_tokens['user'] == _target_tokens['user'] and \
|
||||
_grant_tokens['database'] == _target_tokens['database'] and \
|
||||
_grant_tokens['host'] == _target_tokens['host'] and \
|
||||
set(grant_tokens['grant']) >= set(target_tokens['grant']):
|
||||
all(_grant_matches):
|
||||
return True
|
||||
else:
|
||||
log.debug('grants mismatch \'%s\'<>\'%s\'', grant_tokens, target_tokens)
|
||||
|
|
|
@ -24,6 +24,52 @@ try:
|
|||
except Exception:
|
||||
NO_MYSQL = True
|
||||
|
||||
__all_privileges__ = [
|
||||
'ALTER',
|
||||
'ALTER ROUTINE',
|
||||
'BACKUP_ADMIN',
|
||||
'BINLOG_ADMIN',
|
||||
'CONNECTION_ADMIN',
|
||||
'CREATE',
|
||||
'CREATE ROLE',
|
||||
'CREATE ROUTINE',
|
||||
'CREATE TABLESPACE',
|
||||
'CREATE TEMPORARY TABLES',
|
||||
'CREATE USER',
|
||||
'CREATE VIEW',
|
||||
'DELETE',
|
||||
'DROP',
|
||||
'DROP ROLE',
|
||||
'ENCRYPTION_KEY_ADMIN',
|
||||
'EVENT',
|
||||
'EXECUTE',
|
||||
'FILE',
|
||||
'GROUP_REPLICATION_ADMIN',
|
||||
'INDEX',
|
||||
'INSERT',
|
||||
'LOCK TABLES',
|
||||
'PERSIST_RO_VARIABLES_ADMIN',
|
||||
'PROCESS',
|
||||
'REFERENCES',
|
||||
'RELOAD',
|
||||
'REPLICATION CLIENT',
|
||||
'REPLICATION SLAVE',
|
||||
'REPLICATION_SLAVE_ADMIN',
|
||||
'RESOURCE_GROUP_ADMIN',
|
||||
'RESOURCE_GROUP_USER',
|
||||
'ROLE_ADMIN',
|
||||
'SELECT',
|
||||
'SET_USER_ID',
|
||||
'SHOW DATABASES',
|
||||
'SHOW VIEW',
|
||||
'SHUTDOWN',
|
||||
'SUPER',
|
||||
'SYSTEM_VARIABLES_ADMIN',
|
||||
'TRIGGER',
|
||||
'UPDATE',
|
||||
'XA_RECOVER_ADMIN'
|
||||
]
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@skipIf(NO_MYSQL, 'Install MySQL bindings before running MySQL unit tests.')
|
||||
|
@ -256,15 +302,16 @@ class MySQLTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"GRANT SELECT ON `testdb`.`testtabletwo` TO 'testuer'@'%'",
|
||||
"GRANT SELECT ON `testdb`.`testtablethree` TO 'testuser'@'%'",
|
||||
]
|
||||
mock = MagicMock(return_value=mock_grants)
|
||||
with patch.object(mysql, 'user_grants', return_value=mock_grants) as mock_user_grants:
|
||||
ret = mysql.grant_exists(
|
||||
'SELECT, INSERT, UPDATE',
|
||||
'testdb.testtableone',
|
||||
'testuser',
|
||||
'%'
|
||||
)
|
||||
self.assertEqual(ret, True)
|
||||
with patch.object(mysql, 'version', return_value='5.6.41'):
|
||||
mock = MagicMock(return_value=mock_grants)
|
||||
with patch.object(mysql, 'user_grants', return_value=mock_grants) as mock_user_grants:
|
||||
ret = mysql.grant_exists(
|
||||
'SELECT, INSERT, UPDATE',
|
||||
'testdb.testtableone',
|
||||
'testuser',
|
||||
'%'
|
||||
)
|
||||
self.assertEqual(ret, True)
|
||||
|
||||
def test_grant_exists_false(self):
|
||||
'''
|
||||
|
@ -275,15 +322,47 @@ class MySQLTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"GRANT SELECT, INSERT, UPDATE ON `testdb`.`testtableone` TO 'testuser'@'%'",
|
||||
"GRANT SELECT ON `testdb`.`testtablethree` TO 'testuser'@'%'",
|
||||
]
|
||||
mock = MagicMock(return_value=mock_grants)
|
||||
with patch.object(mysql, 'user_grants', return_value=mock_grants) as mock_user_grants:
|
||||
ret = mysql.grant_exists(
|
||||
'SELECT',
|
||||
'testdb.testtabletwo',
|
||||
'testuser',
|
||||
'%'
|
||||
)
|
||||
self.assertEqual(ret, False)
|
||||
with patch.object(mysql, 'version', return_value='5.6.41'):
|
||||
mock = MagicMock(return_value=mock_grants)
|
||||
with patch.object(mysql, 'user_grants', return_value=mock_grants) as mock_user_grants:
|
||||
ret = mysql.grant_exists(
|
||||
'SELECT',
|
||||
'testdb.testtabletwo',
|
||||
'testuser',
|
||||
'%'
|
||||
)
|
||||
self.assertEqual(ret, False)
|
||||
|
||||
def test_grant_exists_all(self):
|
||||
'''
|
||||
Test to ensure that we can find a grant that exists
|
||||
'''
|
||||
mock_grants = [
|
||||
"GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, CREATE ROLE, DROP ROLE ON testdb.testtableone TO `testuser`@`%`",
|
||||
"GRANT BACKUP_ADMIN,BINLOG_ADMIN,CONNECTION_ADMIN,ENCRYPTION_KEY_ADMIN,GROUP_REPLICATION_ADMIN,PERSIST_RO_VARIABLES_ADMIN,REPLICATION_SLAVE_ADMIN,RESOURCE_GROUP_ADMIN,RESOURCE_GROUP_USER,ROLE_ADMIN,SET_USER_ID,SYSTEM_VARIABLES_ADMIN,XA_RECOVER_ADMIN ON testdb.testtableone TO `testuser`@`%`"
|
||||
]
|
||||
with patch.object(mysql, 'version', return_value='8.0.10'):
|
||||
mock = MagicMock(return_value=mock_grants)
|
||||
with patch.object(mysql, 'user_grants', return_value=mock_grants) as mock_user_grants:
|
||||
ret = mysql.grant_exists(
|
||||
'ALL',
|
||||
'testdb.testtableone',
|
||||
'testuser',
|
||||
'%'
|
||||
)
|
||||
self.assertEqual(ret, True)
|
||||
|
||||
mock_grants = ["GRANT ALL PRIVILEGES ON testdb.testtableone TO `testuser`@`%`"]
|
||||
with patch.object(mysql, 'version', return_value='5.6.41'):
|
||||
mock = MagicMock(return_value=mock_grants)
|
||||
with patch.object(mysql, 'user_grants', return_value=mock_grants) as mock_user_grants:
|
||||
ret = mysql.grant_exists(
|
||||
'ALL PRIVILEGES',
|
||||
'testdb.testtableone',
|
||||
'testuser',
|
||||
'%'
|
||||
)
|
||||
self.assertEqual(ret, True)
|
||||
|
||||
@skipIf(True, 'TODO: Mock up user_grants()')
|
||||
def test_grant_add(self):
|
||||
|
|
Loading…
Add table
Reference in a new issue