diff --git a/data/database.py b/data/database.py index b1ea970fa..28fb2ff8e 100644 --- a/data/database.py +++ b/data/database.py @@ -84,10 +84,11 @@ db_random_func = CallableProxy() db_for_update = CallableProxy() -def validate_database_url(url, connect_timeout=5): - driver = _db_from_url(url, { - 'connect_timeout': connect_timeout - }) +def validate_database_url(url, db_kwargs, connect_timeout=5): + db_kwargs = db_kwargs.copy() + db_kwargs['connect_timeout'] = connect_timeout + + driver = _db_from_url(url, db_kwargs) driver.connect() driver.close() diff --git a/endpoints/api/suconfig.py b/endpoints/api/suconfig.py index de9d74029..dcbac9458 100644 --- a/endpoints/api/suconfig.py +++ b/endpoints/api/suconfig.py @@ -243,7 +243,9 @@ class SuperUserConfigFile(ApiResource): if not filename in CONFIG_FILENAMES: abort(404) - if SuperUserPermission().can(): + # Note: This method can be called before the configuration exists + # to upload the database SSL cert. + if not CONFIG_PROVIDER.yaml_exists() or SuperUserPermission().can(): uploaded_file = request.files['file'] if not uploaded_file: abort(400) diff --git a/static/directives/config/config-file-field.html b/static/directives/config/config-file-field.html index 7e4710905..cdb1b6df4 100644 --- a/static/directives/config/config-file-field.html +++ b/static/directives/config/config-file-field.html @@ -1,7 +1,7 @@
{{ filename }} - {{ filename }} not found in mounted config directory: + {{ filename }} not found in mounted config directory: diff --git a/static/js/core-config-setup.js b/static/js/core-config-setup.js index 0679e3759..2027d76cb 100644 --- a/static/js/core-config-setup.js +++ b/static/js/core-config-setup.js @@ -591,13 +591,18 @@ angular.module("core-config-setup", ['angularFileUpload']) transclude: false, restrict: 'C', scope: { - 'filename': '@filename' + 'filename': '@filename', + 'skipCheckFile': '@skipCheckFile', + 'hasFile': '=hasFile' }, controller: function($scope, $element, Restangular, $upload) { $scope.hasFile = false; $scope.onFileSelect = function(files) { - if (files.length < 1) { return; } + if (files.length < 1) { + $scope.hasFile = false; + return; + } $scope.uploadProgress = 0; $scope.upload = $upload.upload({ @@ -623,7 +628,7 @@ angular.module("core-config-setup", ['angularFileUpload']) }); }; - if ($scope.filename) { + if ($scope.filename && $scope.skipCheckFile != "true") { loadStatus($scope.filename); } } diff --git a/static/js/pages/setup.js b/static/js/pages/setup.js index 21a036350..349e71eeb 100644 --- a/static/js/pages/setup.js +++ b/static/js/pages/setup.js @@ -96,6 +96,9 @@ $scope.stepProgress = []; $scope.hasSSL = false; $scope.hostname = null; + $scope.currentState = { + 'hasDatabaseSSLCert': false + }; $scope.$watch('currentStep', function(currentStep) { $scope.stepProgress = $scope.getProgress(currentStep); @@ -268,6 +271,14 @@ 'hostname': window.location.host }; + if ($scope.currentState.hasDatabaseSSLCert) { + data['config']['DB_CONNECTION_ARGS'] = { + 'ssl': { + 'ca': 'conf/stack/database.pem' + } + }; + } + var params = { 'service': 'database' }; diff --git a/static/partials/setup.html b/static/partials/setup.html index 3556c6fcc..50e507ad4 100644 --- a/static/partials/setup.html +++ b/static/partials/setup.html @@ -192,6 +192,14 @@ placeholder="registry-database"> + + SSL Certificate: + + +
Optional SSL certicate (in PEM format) to use to connect to the database
+ +
diff --git a/test/test_suconfig_api.py b/test/test_suconfig_api.py index ca05d8705..7e049f610 100644 --- a/test/test_suconfig_api.py +++ b/test/test_suconfig_api.py @@ -47,7 +47,13 @@ class TestSuperUserConfigFile(ApiTestCase): def test_post_non_superuser(self): with ConfigForTesting(): - # No user. + # 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. diff --git a/util/config/validator.py b/util/config/validator.py index 1fc5b2b62..f1b05d551 100644 --- a/util/config/validator.py +++ b/util/config/validator.py @@ -20,7 +20,7 @@ from app import app, CONFIG_PROVIDER, get_app_url, OVERRIDE_CONFIG_DIRECTORY logger = logging.getLogger(__name__) -SSL_FILENAMES = ['ssl.cert', 'ssl.key'] +SSL_FILENAMES = ['ssl.cert', 'ssl.key', 'database.pem'] JWT_FILENAMES = ['jwt-authn.cert'] CONFIG_FILENAMES = SSL_FILENAMES + JWT_FILENAMES @@ -54,7 +54,7 @@ def validate_service_for_config(service, config, password=None): def _validate_database(config, _): """ Validates connecting to the database. """ try: - validate_database_url(config['DB_URI']) + validate_database_url(config['DB_URI'], config.get('DB_CONNECTION_ARGS', {})) except peewee.OperationalError as ex: if ex.args and len(ex.args) > 1: raise Exception(ex.args[1])