Add db configuration to modifying config
Move more tests over
This commit is contained in:
parent
d44aa8f566
commit
d9f7c07f42
10 changed files with 530 additions and 406 deletions
|
@ -8,7 +8,6 @@ import re
|
|||
import json as py_json
|
||||
|
||||
from mock import patch
|
||||
from StringIO import StringIO
|
||||
from calendar import timegm
|
||||
from contextlib import contextmanager
|
||||
from httmock import urlmatch, HTTMock, all_requests
|
||||
|
@ -18,7 +17,6 @@ from urlparse import urlparse, urlunparse, parse_qs
|
|||
from playhouse.test_utils import assert_query_count, _QueryLogHandler
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from mockldap import MockLdap
|
||||
|
||||
from endpoints.api import api_bp, api
|
||||
from endpoints.building import PreparedBuild
|
||||
|
@ -70,16 +68,12 @@ from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPe
|
|||
RepositoryTeamPermissionList, RepositoryUserPermissionList)
|
||||
from endpoints.api.superuser import (
|
||||
SuperUserLogs, SuperUserManagement, SuperUserServiceKeyManagement,
|
||||
SuperUserServiceKey, SuperUserServiceKeyApproval, SuperUserTakeOwnership,
|
||||
SuperUserCustomCertificates, SuperUserCustomCertificate)
|
||||
SuperUserServiceKey, SuperUserServiceKeyApproval, SuperUserTakeOwnership)
|
||||
from endpoints.api.globalmessages import (
|
||||
GlobalUserMessage,
|
||||
GlobalUserMessages,)
|
||||
from endpoints.api.secscan import RepositoryImageSecurity, RepositoryManifestSecurity
|
||||
from endpoints.api.suconfig import (
|
||||
SuperUserRegistryStatus, SuperUserConfig, SuperUserConfigFile, SuperUserCreateInitialSuperUser)
|
||||
from endpoints.api.manifest import RepositoryManifestLabels, ManageRepositoryManifestLabel
|
||||
from util.security.test.test_ssl_util import generate_test_cert
|
||||
from util.morecollections import AttrDict
|
||||
|
||||
try:
|
||||
|
@ -3990,150 +3984,6 @@ class TestSuperUserLogs(ApiTestCase):
|
|||
assert len(json['logs']) > 0
|
||||
|
||||
|
||||
class TestSuperUserCreateInitialSuperUser(ApiTestCase):
|
||||
def test_create_superuser(self):
|
||||
data = {
|
||||
'username': 'newsuper',
|
||||
'password': 'password',
|
||||
'email': 'jschorr+fake@devtable.com',
|
||||
}
|
||||
|
||||
# Try to write before some config. Should 403.
|
||||
self.postResponse(SuperUserCreateInitialSuperUser, data=data, expected_code=403)
|
||||
|
||||
# Add some fake config.
|
||||
fake_config = {
|
||||
'AUTHENTICATION_TYPE': 'Database',
|
||||
'SECRET_KEY': 'fakekey',
|
||||
}
|
||||
|
||||
self.putJsonResponse(SuperUserConfig, data=dict(config=fake_config, hostname='fakehost'))
|
||||
|
||||
# Try to write with config. Should 403 since there are users in the DB.
|
||||
self.postResponse(SuperUserCreateInitialSuperUser, data=data, expected_code=403)
|
||||
|
||||
# Delete all users in the DB.
|
||||
for user in list(database.User.select()):
|
||||
model.user.delete_user(user, all_queues)
|
||||
|
||||
# Create the superuser.
|
||||
self.postJsonResponse(SuperUserCreateInitialSuperUser, data=data)
|
||||
|
||||
# Ensure the user exists in the DB.
|
||||
self.assertIsNotNone(model.user.get_user('newsuper'))
|
||||
|
||||
# Ensure that the current user is newsuper.
|
||||
json = self.getJsonResponse(User)
|
||||
self.assertEquals('newsuper', json['username'])
|
||||
|
||||
# Ensure that the current user is a superuser in the config.
|
||||
json = self.getJsonResponse(SuperUserConfig)
|
||||
self.assertEquals(['newsuper'], json['config']['SUPER_USERS'])
|
||||
|
||||
# Ensure that the current user is a superuser in memory by trying to call an API
|
||||
# that will fail otherwise.
|
||||
self.getResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'))
|
||||
|
||||
|
||||
class TestSuperUserConfig(ApiTestCase):
|
||||
def test_get_status_update_config(self):
|
||||
# With no config the status should be 'config-db'.
|
||||
json = self.getJsonResponse(SuperUserRegistryStatus)
|
||||
self.assertEquals('config-db', json['status'])
|
||||
|
||||
# And the config should 401.
|
||||
self.getResponse(SuperUserConfig, expected_code=401)
|
||||
|
||||
# Add some fake config.
|
||||
fake_config = {
|
||||
'AUTHENTICATION_TYPE': 'Database',
|
||||
'SECRET_KEY': 'fakekey',
|
||||
}
|
||||
|
||||
json = self.putJsonResponse(SuperUserConfig, data=dict(config=fake_config,
|
||||
hostname='fakehost'))
|
||||
self.assertEquals('fakekey', json['config']['SECRET_KEY'])
|
||||
self.assertEquals('fakehost', json['config']['SERVER_HOSTNAME'])
|
||||
self.assertEquals('Database', json['config']['AUTHENTICATION_TYPE'])
|
||||
|
||||
# With config the status should be 'setup-db'.
|
||||
json = self.getJsonResponse(SuperUserRegistryStatus)
|
||||
self.assertEquals('setup-db', json['status'])
|
||||
|
||||
def test_config_file(self):
|
||||
# Try without an account. Should 403.
|
||||
self.getResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'), expected_code=403)
|
||||
|
||||
# Login to a superuser.
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
|
||||
# Try for an invalid file. Should 404.
|
||||
self.getResponse(SuperUserConfigFile, params=dict(filename='foobar'), expected_code=404)
|
||||
|
||||
# Try for a valid filename. Should not exist.
|
||||
json = self.getJsonResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'))
|
||||
self.assertFalse(json['exists'])
|
||||
|
||||
# Add the file.
|
||||
self.postResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'),
|
||||
file=(StringIO('my file contents'), 'ssl.cert'))
|
||||
|
||||
# Should now exist.
|
||||
json = self.getJsonResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'))
|
||||
self.assertTrue(json['exists'])
|
||||
|
||||
def test_update_with_external_auth(self):
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
|
||||
# Run a mock LDAP.
|
||||
mockldap = MockLdap({
|
||||
'dc=quay,dc=io': {
|
||||
'dc': ['quay', 'io']
|
||||
},
|
||||
'ou=employees,dc=quay,dc=io': {
|
||||
'dc': ['quay', 'io'],
|
||||
'ou': 'employees'
|
||||
},
|
||||
'uid=' + ADMIN_ACCESS_USER + ',ou=employees,dc=quay,dc=io': {
|
||||
'dc': ['quay', 'io'],
|
||||
'ou': 'employees',
|
||||
'uid': [ADMIN_ACCESS_USER],
|
||||
'userPassword': ['password'],
|
||||
'mail': [ADMIN_ACCESS_EMAIL],
|
||||
},
|
||||
})
|
||||
|
||||
config = {
|
||||
'AUTHENTICATION_TYPE': 'LDAP',
|
||||
'LDAP_BASE_DN': ['dc=quay', 'dc=io'],
|
||||
'LDAP_ADMIN_DN': 'uid=devtable,ou=employees,dc=quay,dc=io',
|
||||
'LDAP_ADMIN_PASSWD': 'password',
|
||||
'LDAP_USER_RDN': ['ou=employees'],
|
||||
'LDAP_UID_ATTR': 'uid',
|
||||
'LDAP_EMAIL_ATTR': 'mail',
|
||||
}
|
||||
|
||||
mockldap.start()
|
||||
try:
|
||||
# Try writing some config with an invalid password.
|
||||
self.putResponse(SuperUserConfig, data={'config': config,
|
||||
'hostname': 'foo'}, expected_code=400)
|
||||
self.putResponse(SuperUserConfig,
|
||||
data={'config': config,
|
||||
'password': 'invalid',
|
||||
'hostname': 'foo'}, expected_code=400)
|
||||
|
||||
# Write the config with the valid password.
|
||||
self.putResponse(SuperUserConfig,
|
||||
data={'config': config,
|
||||
'password': 'password',
|
||||
'hostname': 'foo'}, expected_code=200)
|
||||
|
||||
# Ensure that the user row has been linked.
|
||||
self.assertEquals(ADMIN_ACCESS_USER,
|
||||
model.user.verify_federated_login('ldap', ADMIN_ACCESS_USER).username)
|
||||
finally:
|
||||
mockldap.stop()
|
||||
|
||||
|
||||
class TestRepositoryImageSecurity(ApiTestCase):
|
||||
|
@ -4207,80 +4057,6 @@ class TestRepositoryImageSecurity(ApiTestCase):
|
|||
vulnerabilities='true'), expected_code=200)
|
||||
|
||||
|
||||
class TestSuperUserCustomCertificates(ApiTestCase):
|
||||
def test_custom_certificates(self):
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
|
||||
# Upload a certificate.
|
||||
cert_contents, _ = generate_test_cert(hostname='somecoolhost', san_list=['DNS:bar', 'DNS:baz'])
|
||||
self.postResponse(SuperUserCustomCertificate, params=dict(certpath='testcert.crt'),
|
||||
file=(StringIO(cert_contents), 'testcert.crt'), expected_code=204)
|
||||
|
||||
# Make sure it is present.
|
||||
json = self.getJsonResponse(SuperUserCustomCertificates)
|
||||
self.assertEquals(1, len(json['certs']))
|
||||
|
||||
cert_info = json['certs'][0]
|
||||
self.assertEquals('testcert.crt', cert_info['path'])
|
||||
|
||||
self.assertEquals(set(['somecoolhost', 'bar', 'baz']), set(cert_info['names']))
|
||||
self.assertFalse(cert_info['expired'])
|
||||
|
||||
# Remove the certificate.
|
||||
self.deleteResponse(SuperUserCustomCertificate, params=dict(certpath='testcert.crt'))
|
||||
|
||||
# Make sure it is gone.
|
||||
json = self.getJsonResponse(SuperUserCustomCertificates)
|
||||
self.assertEquals(0, len(json['certs']))
|
||||
|
||||
def test_expired_custom_certificate(self):
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
|
||||
# Upload a certificate.
|
||||
cert_contents, _ = generate_test_cert(hostname='somecoolhost', expires=-10)
|
||||
self.postResponse(SuperUserCustomCertificate, params=dict(certpath='testcert.crt'),
|
||||
file=(StringIO(cert_contents), 'testcert.crt'), expected_code=204)
|
||||
|
||||
# Make sure it is present.
|
||||
json = self.getJsonResponse(SuperUserCustomCertificates)
|
||||
self.assertEquals(1, len(json['certs']))
|
||||
|
||||
cert_info = json['certs'][0]
|
||||
self.assertEquals('testcert.crt', cert_info['path'])
|
||||
|
||||
self.assertEquals(set(['somecoolhost']), set(cert_info['names']))
|
||||
self.assertTrue(cert_info['expired'])
|
||||
|
||||
def test_invalid_custom_certificate(self):
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
|
||||
# Upload an invalid certificate.
|
||||
self.postResponse(SuperUserCustomCertificate, params=dict(certpath='testcert.crt'),
|
||||
file=(StringIO('some contents'), 'testcert.crt'), expected_code=204)
|
||||
|
||||
# Make sure it is present but invalid.
|
||||
json = self.getJsonResponse(SuperUserCustomCertificates)
|
||||
self.assertEquals(1, len(json['certs']))
|
||||
|
||||
cert_info = json['certs'][0]
|
||||
self.assertEquals('testcert.crt', cert_info['path'])
|
||||
self.assertEquals('no start line', cert_info['error'])
|
||||
|
||||
def test_path_sanitization(self):
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
|
||||
# Upload a certificate.
|
||||
cert_contents, _ = generate_test_cert(hostname='somecoolhost', expires=-10)
|
||||
self.postResponse(SuperUserCustomCertificate, params=dict(certpath='testcert/../foobar.crt'),
|
||||
file=(StringIO(cert_contents), 'testcert/../foobar.crt'), expected_code=204)
|
||||
|
||||
# Make sure it is present.
|
||||
json = self.getJsonResponse(SuperUserCustomCertificates)
|
||||
self.assertEquals(1, len(json['certs']))
|
||||
|
||||
cert_info = json['certs'][0]
|
||||
self.assertEquals('foobar.crt', cert_info['path'])
|
||||
|
||||
|
||||
class TestSuperUserTakeOwnership(ApiTestCase):
|
||||
def test_take_ownership_superuser(self):
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
from test.test_api_usage import ApiTestCase, READ_ACCESS_USER, ADMIN_ACCESS_USER
|
||||
from endpoints.api.suconfig import (SuperUserRegistryStatus, SuperUserConfig, SuperUserConfigFile,
|
||||
SuperUserCreateInitialSuperUser, SuperUserConfigValidate)
|
||||
from app import config_provider, all_queues
|
||||
from data.database import User
|
||||
from data import model
|
||||
from test.test_api_usage import ApiTestCase
|
||||
from endpoints.api.suconfig import SuperUserRegistryStatus
|
||||
from app import config_provider
|
||||
|
||||
import unittest
|
||||
|
||||
|
@ -24,169 +21,5 @@ class TestSuperUserRegistryStatus(ApiTestCase):
|
|||
self.assertEquals('config-db', json['status'])
|
||||
|
||||
|
||||
class TestSuperUserConfigFile(ApiTestCase):
|
||||
def test_get_non_superuser(self):
|
||||
with FreshConfigProvider():
|
||||
# No user.
|
||||
self.getResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'), expected_code=403)
|
||||
|
||||
# Non-superuser.
|
||||
self.login(READ_ACCESS_USER)
|
||||
self.getResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'), expected_code=403)
|
||||
|
||||
def test_get_superuser_invalid_filename(self):
|
||||
with FreshConfigProvider():
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
self.getResponse(SuperUserConfigFile, params=dict(filename='somefile'), expected_code=404)
|
||||
|
||||
def test_get_superuser(self):
|
||||
with FreshConfigProvider():
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
result = self.getJsonResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'))
|
||||
self.assertFalse(result['exists'])
|
||||
|
||||
def test_post_non_superuser(self):
|
||||
with FreshConfigProvider():
|
||||
# No user, before config.yaml exists.
|
||||
self.postResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'), expected_code=400)
|
||||
|
||||
# Write some config.
|
||||
self.putJsonResponse(SuperUserConfig, data=dict(config={}, hostname='foobar'))
|
||||
|
||||
# No user, with config.yaml.
|
||||
self.postResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'), expected_code=403)
|
||||
|
||||
# Non-superuser.
|
||||
self.login(READ_ACCESS_USER)
|
||||
self.postResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'), expected_code=403)
|
||||
|
||||
def test_post_superuser_invalid_filename(self):
|
||||
with FreshConfigProvider():
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
self.postResponse(SuperUserConfigFile, params=dict(filename='somefile'), expected_code=404)
|
||||
|
||||
def test_post_superuser(self):
|
||||
with FreshConfigProvider():
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
self.postResponse(SuperUserConfigFile, params=dict(filename='ssl.cert'), expected_code=400)
|
||||
|
||||
|
||||
class TestSuperUserCreateInitialSuperUser(ApiTestCase):
|
||||
def test_no_config_file(self):
|
||||
with FreshConfigProvider():
|
||||
# If there is no config.yaml, then this method should security fail.
|
||||
data = dict(username='cooluser', password='password', email='fake@example.com')
|
||||
self.postResponse(SuperUserCreateInitialSuperUser, data=data, expected_code=403)
|
||||
|
||||
def test_config_file_with_db_users(self):
|
||||
with FreshConfigProvider():
|
||||
# Write some config.
|
||||
self.putJsonResponse(SuperUserConfig, data=dict(config={}, hostname='foobar'))
|
||||
|
||||
# If there is a config.yaml, but existing DB users exist, then this method should security
|
||||
# fail.
|
||||
data = dict(username='cooluser', password='password', email='fake@example.com')
|
||||
self.postResponse(SuperUserCreateInitialSuperUser, data=data, expected_code=403)
|
||||
|
||||
def test_config_file_with_no_db_users(self):
|
||||
with FreshConfigProvider():
|
||||
# Write some config.
|
||||
self.putJsonResponse(SuperUserConfig, data=dict(config={}, hostname='foobar'))
|
||||
|
||||
# Delete all the users in the DB.
|
||||
for user in list(User.select()):
|
||||
model.user.delete_user(user, all_queues)
|
||||
|
||||
# This method should now succeed.
|
||||
data = dict(username='cooluser', password='password', email='fake@example.com')
|
||||
result = self.postJsonResponse(SuperUserCreateInitialSuperUser, data=data)
|
||||
self.assertTrue(result['status'])
|
||||
|
||||
# Verify the superuser was created.
|
||||
User.get(User.username == 'cooluser')
|
||||
|
||||
# Verify the superuser was placed into the config.
|
||||
result = self.getJsonResponse(SuperUserConfig)
|
||||
self.assertEquals(['cooluser'], result['config']['SUPER_USERS'])
|
||||
|
||||
|
||||
class TestSuperUserConfigValidate(ApiTestCase):
|
||||
def test_nonsuperuser_noconfig(self):
|
||||
with FreshConfigProvider():
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
result = self.postJsonResponse(SuperUserConfigValidate, params=dict(service='someservice'),
|
||||
data=dict(config={}))
|
||||
|
||||
self.assertFalse(result['status'])
|
||||
|
||||
|
||||
def test_nonsuperuser_config(self):
|
||||
with FreshConfigProvider():
|
||||
# The validate config call works if there is no config.yaml OR the user is a superuser.
|
||||
# Add a config, and verify it breaks when unauthenticated.
|
||||
json = self.putJsonResponse(SuperUserConfig, data=dict(config={}, hostname='foobar'))
|
||||
self.assertTrue(json['exists'])
|
||||
|
||||
self.postResponse(SuperUserConfigValidate, params=dict(service='someservice'),
|
||||
data=dict(config={}),
|
||||
expected_code=403)
|
||||
|
||||
# Now login as a superuser.
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
result = self.postJsonResponse(SuperUserConfigValidate, params=dict(service='someservice'),
|
||||
data=dict(config={}))
|
||||
|
||||
self.assertFalse(result['status'])
|
||||
|
||||
|
||||
class TestSuperUserConfig(ApiTestCase):
|
||||
def test_get_non_superuser(self):
|
||||
with FreshConfigProvider():
|
||||
# No user.
|
||||
self.getResponse(SuperUserConfig, expected_code=401)
|
||||
|
||||
# Non-superuser.
|
||||
self.login(READ_ACCESS_USER)
|
||||
self.getResponse(SuperUserConfig, expected_code=403)
|
||||
|
||||
def test_get_superuser(self):
|
||||
with FreshConfigProvider():
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
json = self.getJsonResponse(SuperUserConfig)
|
||||
|
||||
# Note: We expect the config to be none because a config.yaml should never be checked into
|
||||
# the directory.
|
||||
self.assertIsNone(json['config'])
|
||||
|
||||
def test_put(self):
|
||||
with FreshConfigProvider() as config:
|
||||
# The update config call works if there is no config.yaml OR the user is a superuser. First
|
||||
# try writing it without a superuser present.
|
||||
json = self.putJsonResponse(SuperUserConfig, data=dict(config={}, hostname='foobar'))
|
||||
self.assertTrue(json['exists'])
|
||||
|
||||
# Verify the config file exists.
|
||||
self.assertTrue(config.config_exists())
|
||||
|
||||
# Try writing it again. This should now fail, since the config.yaml exists.
|
||||
self.putResponse(SuperUserConfig, data=dict(config={}, hostname='barbaz'), expected_code=403)
|
||||
|
||||
# Login as a non-superuser.
|
||||
self.login(READ_ACCESS_USER)
|
||||
|
||||
# Try writing it again. This should fail.
|
||||
self.putResponse(SuperUserConfig, data=dict(config={}, hostname='barbaz'), expected_code=403)
|
||||
|
||||
# Login as a superuser.
|
||||
self.login(ADMIN_ACCESS_USER)
|
||||
|
||||
# This should succeed.
|
||||
json = self.putJsonResponse(SuperUserConfig, data=dict(config={}, hostname='barbaz'))
|
||||
self.assertTrue(json['exists'])
|
||||
|
||||
json = self.getJsonResponse(SuperUserConfig)
|
||||
self.assertIsNotNone(json['config'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
Reference in a new issue