From 5ac2c4970ae2e2bceee09c290ffc8e8fe8e6a55f Mon Sep 17 00:00:00 2001 From: Joseph Schorr <joseph.schorr@coreos.com> Date: Thu, 8 Jan 2015 13:56:17 -0500 Subject: [PATCH] Add Google auth validation and fix the case where no config is specified at all for Google auth or Github auth --- static/js/core-config-setup.js | 4 ++++ util/config/validator.py | 30 +++++++++++++++++++++++++++--- util/oauth.py | 22 ++++++++++++++++++---- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/static/js/core-config-setup.js b/static/js/core-config-setup.js index 6950ebe68..78483ab5d 100644 --- a/static/js/core-config-setup.js +++ b/static/js/core-config-setup.js @@ -31,6 +31,10 @@ angular.module("core-config-setup", ['angularFileUpload']) return config.FEATURE_GITHUB_LOGIN; }}, + {'id': 'google-login', 'title': 'Google Authentication', 'condition': function(config) { + return config.FEATURE_GOOGLE_LOGIN; + }}, + {'id': 'github-trigger', 'title': 'Github (Enterprise) Build Triggers', 'condition': function(config) { return config.FEATURE_GITHUB_BUILD; }} diff --git a/util/config/validator.py b/util/config/validator.py index 7be8657df..990c69c36 100644 --- a/util/config/validator.py +++ b/util/config/validator.py @@ -79,17 +79,21 @@ def _validate_github(config_key): def _validate_github_with_key(config_key, config): """ Validates the OAuth credentials and API endpoint for a Github service. """ - endpoint = config[config_key].get('GITHUB_ENDPOINT') + github_config = config.get(config_key) + if not github_config: + raise Exception('Missing Github client id and client secret') + + endpoint = github_config.get('GITHUB_ENDPOINT') if not endpoint: raise Exception('Missing Github Endpoint') if endpoint.find('http://') != 0 and endpoint.find('https://') != 0: raise Exception('Github Endpoint must start with http:// or https://') - if not config[config_key].get('CLIENT_ID'): + if not github_config.get('CLIENT_ID'): raise Exception('Missing Client ID') - if not config[config_key].get('CLIENT_SECRET'): + if not github_config.get('CLIENT_SECRET'): raise Exception('Missing Client Secret') client = app.config['HTTPCLIENT'] @@ -99,6 +103,25 @@ def _validate_github_with_key(config_key, config): raise Exception('Invalid client id or client secret') +def _validate_google_login(config): + """ Validates the Google Login client ID and secret. """ + google_login_config = config.get('GOOGLE_LOGIN_CONFIG') + if not google_login_config: + raise Exception('Missing client ID and client secret') + + if not google_login_config.get('CLIENT_ID'): + raise Exception('Missing Client ID') + + if not google_login_config.get('CLIENT_SECRET'): + raise Exception('Missing Client Secret') + + client = app.config['HTTPCLIENT'] + oauth = GoogleOAuthConfig(config, 'GOOGLE_LOGIN_CONFIG') + result = oauth.validate_client_id_and_secret(client) + if not result: + raise Exception('Invalid client id or client secret') + + def _validate_ssl(config): """ Validates the SSL configuration (if enabled). """ if config.get('PREFERRED_URL_SCHEME', 'http') != 'https': @@ -141,6 +164,7 @@ _VALIDATORS = { 'mail': _validate_mailing, 'github-login': _validate_github('GITHUB_LOGIN_CONFIG'), 'github-trigger': _validate_github('GITHUB_TRIGGER_CONFIG'), + 'google-login': _validate_google_login, 'ssl': _validate_ssl, 'ldap': _validate_ldap, } \ No newline at end of file diff --git a/util/oauth.py b/util/oauth.py index 2405423ea..ede8823aa 100644 --- a/util/oauth.py +++ b/util/oauth.py @@ -70,7 +70,7 @@ class GithubOAuthConfig(OAuthConfig): # First: Verify that the github endpoint is actually Github by checking for the # X-GitHub-Request-Id here. api_endpoint = self._api_endpoint() - result = http_client.get(api_endpoint, auth=(self.client_id(), self.client_secret())) + result = http_client.get(api_endpoint, auth=(self.client_id(), self.client_secret()), timeout=5) if not 'X-GitHub-Request-Id' in result.headers: raise Exception('Endpoint is not a Github (Enterprise) installation') @@ -87,7 +87,8 @@ class GithubOAuthConfig(OAuthConfig): # - If the {client_id, client_secret} pair is invalid in some way, we get a 401 error. # - If the pair is valid, then we get a 404 because the 'foo' token does not exists. validate_endpoint = self._get_url(api_endpoint, 'applications/%s/tokens/foo' % self.client_id()) - result = http_client.get(validate_endpoint, auth=(self.client_id(), self.client_secret())) + result = http_client.get(validate_endpoint, auth=(self.client_id(), self.client_secret()), + timeout=5) return result.status_code == 404 def get_public_config(self): @@ -116,8 +117,21 @@ class GoogleOAuthConfig(OAuthConfig): return 'https://www.googleapis.com/oauth2/v1/userinfo' def validate_client_id_and_secret(self, http_client): - # No validation supported at this time. - return None + # To verify the Google client ID and secret, we hit the + # https://www.googleapis.com/oauth2/v3/token endpoint with an invalid request. If the client + # ID or secret are invalid, we get returned a 403 Unauthorized. Otherwise, we get returned + # another response code. + url = 'https://www.googleapis.com/oauth2/v3/token' + data = { + 'code': 'fakecode', + 'client_id': self.client_id(), + 'client_secret': self.client_secret(), + 'grant_type': 'authorization_code', + 'redirect_uri': 'http://example.com' + } + + result = http_client.post(url, data=data, timeout=5) + return result.status_code != 401 def get_public_config(self): return {