From e0c1c11bf36ce6d4b3b15bba56413934f568c27d Mon Sep 17 00:00:00 2001 From: Michael Krotscheck Date: Mon, 29 Dec 2014 12:00:25 -0800 Subject: [PATCH] Consolidated OAuth Configuration, added enable flag to oauth cleaner. The OAuth configuration elements were moved into a single block within storyboard.conf, so that relevant other components could add their own configuration. The OAuth Token Cleaner was then provided with its own configuration flag so that it can be disabled. Change-Id: I9c02ea913f184c0734e2b694469d36c5e96339b5 --- etc/storyboard.conf.sample | 24 +++++++++----- setup.cfg | 2 +- storyboard/api/auth/__init__.py | 33 +++++++++++++++++++ storyboard/api/auth/oauth_validator.py | 14 +------- storyboard/api/auth/openid_client.py | 14 ++------ .../api/auth/token_storage/db_storage.py | 2 +- storyboard/plugin/token_cleaner/__init__.py | 25 ++++++++++++++ .../{oauth => token_cleaner}/cleaner.py | 4 ++- storyboard/tests/plugin/cron/test_manager.py | 8 ++--- storyboard/tests/plugin/oauth/__init__.py | 0 .../plugin/token_cleaner}/__init__.py | 0 .../{oauth => token_cleaner}/test_cleaner.py | 13 ++++++-- 12 files changed, 97 insertions(+), 42 deletions(-) create mode 100644 storyboard/plugin/token_cleaner/__init__.py rename storyboard/plugin/{oauth => token_cleaner}/cleaner.py (93%) delete mode 100644 storyboard/tests/plugin/oauth/__init__.py rename storyboard/{plugin/oauth => tests/plugin/token_cleaner}/__init__.py (100%) rename storyboard/tests/plugin/{oauth => token_cleaner}/test_cleaner.py (86%) diff --git a/etc/storyboard.conf.sample b/etc/storyboard.conf.sample index 855caf52..ef49a1c4 100644 --- a/etc/storyboard.conf.sample +++ b/etc/storyboard.conf.sample @@ -37,6 +37,17 @@ lock_path = $state_path/lock # Port the bind the API server to # bind_port = 8080 +# List paging configuration options. +# page_size_maximum = 500 +# page_size_default = 20 + +# Enable notifications. This feature drives deferred processing, reporting, +# and subscriptions. +# enable_notifications = True + +[oauth] +# StoryBoard's oauth configuration. + # OpenId Authentication endpoint # openid_url = https://login.launchpad.net/+openid @@ -46,14 +57,6 @@ lock_path = $state_path/lock # Time in seconds before an refresh_token expires # refresh_token_ttl = 604800 -# List paging configuration options. -# page_size_maximum = 500 -# page_size_default = 20 - -# Enable notifications. This feature drives deferred processing, reporting, -# and subscriptions. -# enable_notifications = True - [cron] # Storyboard's cron management configuration @@ -137,3 +140,8 @@ lock_path = $state_path/lock # If set, use this value for pool_timeout with sqlalchemy # pool_timeout = 10 + +[plugin_token_cleaner] +# Enable/Disable the token cleaning cron plugin. This requires cron +# management to be enabled. +# enable = True \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 9c79842c..61fbda39 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,7 +42,7 @@ storyboard.worker.task = storyboard.plugin.user_preferences = storyboard.plugin.cron = cron-management = storyboard.plugin.cron.manager:CronManager - token-cleaner = storyboard.plugin.oauth.cleaner:TokenCleaner + token-cleaner = storyboard.plugin.token_cleaner.cleaner:TokenCleaner [build_sphinx] source-dir = doc/source diff --git a/storyboard/api/auth/__init__.py b/storyboard/api/auth/__init__.py index e69de29b..55cd14ce 100644 --- a/storyboard/api/auth/__init__.py +++ b/storyboard/api/auth/__init__.py @@ -0,0 +1,33 @@ +# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +from oslo.config import cfg + +CONF = cfg.CONF + +OAUTH_OPTS = [ + cfg.StrOpt('openid_url', + default='https://login.launchpad.net/+openid', + help='OpenId Authentication endpoint'), + + cfg.IntOpt("access_token_ttl", + default=60 * 60, # One hour + help="Time in seconds before an access_token expires"), + + cfg.IntOpt("refresh_token_ttl", + default=60 * 60 * 24 * 7, # One week + help="Time in seconds before an refresh_token expires") +] + +CONF.register_opts(OAUTH_OPTS, "oauth") diff --git a/storyboard/api/auth/oauth_validator.py b/storyboard/api/auth/oauth_validator.py index c02710e7..de993efb 100644 --- a/storyboard/api/auth/oauth_validator.py +++ b/storyboard/api/auth/oauth_validator.py @@ -26,18 +26,6 @@ from storyboard.openstack.common import log CONF = cfg.CONF LOG = log.getLogger(__name__) -TOKEN_OPTS = [ - cfg.IntOpt("access_token_ttl", - default=60 * 60, # One hour - help="Time in seconds before an access_token expires"), - - cfg.IntOpt("refresh_token_ttl", - default=60 * 60 * 24 * 7, # One week - help="Time in seconds before an refresh_token expires") -] - -CONF.register_opts(TOKEN_OPTS) - class SkeletonValidator(RequestValidator): """This is oauth skeleton for handling all kind of validations and storage @@ -259,7 +247,7 @@ class SkeletonValidator(RequestValidator): class OpenIdConnectServer(WebApplicationServer): def __init__(self, request_validator): - access_token_ttl = CONF.access_token_ttl + access_token_ttl = CONF.oauth.access_token_ttl super(OpenIdConnectServer, self).__init__( request_validator, token_expires_in=access_token_ttl) diff --git a/storyboard/api/auth/openid_client.py b/storyboard/api/auth/openid_client.py index b37875b0..5bba35ca 100644 --- a/storyboard/api/auth/openid_client.py +++ b/storyboard/api/auth/openid_client.py @@ -24,19 +24,10 @@ LOG = log.getLogger(__name__) CONF = cfg.CONF -OPENID_OPTS = [ - cfg.StrOpt('openid_url', - default='https://login.launchpad.net/+openid', - help='OpenId Authentication endpoint') -] - -CONF.register_opts(OPENID_OPTS) - - class OpenIdClient(object): def send_openid_redirect(self, request, response): - redirect_location = CONF.openid_url + redirect_location = CONF.oauth.openid_url response.status_code = 303 return_params = { @@ -91,7 +82,8 @@ class OpenIdClient(object): verify_params = dict(request.params.copy()) verify_params["openid.mode"] = "check_authentication" - verify_response = requests.post(CONF.openid_url, data=verify_params) + verify_response = requests.post(CONF.oauth.openid_url, + data=verify_params) verify_data_tokens = verify_response.content.split() verify_dict = dict((token.split(":")[0], token.split(":")[1]) for token in verify_data_tokens) diff --git a/storyboard/api/auth/token_storage/db_storage.py b/storyboard/api/auth/token_storage/db_storage.py index be498e1f..5ba57289 100644 --- a/storyboard/api/auth/token_storage/db_storage.py +++ b/storyboard/api/auth/token_storage/db_storage.py @@ -55,7 +55,7 @@ class DBTokenStorage(storage.StorageBase): # Oauthlib does not provide a separate expiration time for a # refresh_token so taking it from config directly. - refresh_expires_in = CONF.refresh_token_ttl + refresh_expires_in = CONF.oauth.refresh_token_ttl refresh_token_values = { "refresh_token": refresh_token, diff --git a/storyboard/plugin/token_cleaner/__init__.py b/storyboard/plugin/token_cleaner/__init__.py new file mode 100644 index 00000000..d806005e --- /dev/null +++ b/storyboard/plugin/token_cleaner/__init__.py @@ -0,0 +1,25 @@ +# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +from oslo.config import cfg + +CONF = cfg.CONF + +PLUGIN_OPTS = [ + cfg.BoolOpt("enable", + default=False, # By default, we don't scrub old oauth tokens. + help="Enable, or disable, the oauth token cleaner") +] + +CONF.register_opts(PLUGIN_OPTS, "plugin_token_cleaner") diff --git a/storyboard/plugin/oauth/cleaner.py b/storyboard/plugin/token_cleaner/cleaner.py similarity index 93% rename from storyboard/plugin/oauth/cleaner.py rename to storyboard/plugin/token_cleaner/cleaner.py index 6561fdd7..a91a20d9 100644 --- a/storyboard/plugin/oauth/cleaner.py +++ b/storyboard/plugin/token_cleaner/cleaner.py @@ -31,7 +31,9 @@ class TokenCleaner(CronPluginBase): """Indicate whether this plugin is enabled. This indicates whether this plugin alone is runnable, as opposed to the entire cron system. """ - return True + if 'plugin_token_cleaner' in self.config: + return self.config.plugin_token_cleaner.enable or False + return False def interval(self): """This plugin executes on startup, and once every hour after that. diff --git a/storyboard/tests/plugin/cron/test_manager.py b/storyboard/tests/plugin/cron/test_manager.py index 6c0ba9c8..e5db90aa 100644 --- a/storyboard/tests/plugin/cron/test_manager.py +++ b/storyboard/tests/plugin/cron/test_manager.py @@ -245,8 +245,8 @@ class TestCronManager(base.TestCase): manager = cronmanager.CronManager(CONF, tabfile=self.tabfile) manager.execute() - # We're expecting 2 in-branch plugins. - self.assertCronLength(2, command='storyboard-cron') + # We're expecting 1 enabled in-branch plugins. + self.assertCronLength(1, command='storyboard-cron') def test_execute_update(self): """Test that execute() method updates plugins.""" @@ -312,7 +312,7 @@ class TestCronManager(base.TestCase): # Check a new crontab to see what we find. self.assertCronLength(0, command=plugin_command) - self.assertCronLength(2, command='storyboard-cron') + self.assertCronLength(1, command='storyboard-cron') # Cleanup after ourselves. manager.remove() @@ -343,7 +343,7 @@ class TestCronManager(base.TestCase): manager.execute() # Check a new crontab to see what we find. - self.assertCronLength(2, command='storyboard-cron') + self.assertCronLength(1, command='storyboard-cron') # Cleanup after ourselves. manager.remove() diff --git a/storyboard/tests/plugin/oauth/__init__.py b/storyboard/tests/plugin/oauth/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/storyboard/plugin/oauth/__init__.py b/storyboard/tests/plugin/token_cleaner/__init__.py similarity index 100% rename from storyboard/plugin/oauth/__init__.py rename to storyboard/tests/plugin/token_cleaner/__init__.py diff --git a/storyboard/tests/plugin/oauth/test_cleaner.py b/storyboard/tests/plugin/token_cleaner/test_cleaner.py similarity index 86% rename from storyboard/tests/plugin/oauth/test_cleaner.py rename to storyboard/tests/plugin/token_cleaner/test_cleaner.py index d757b1a8..d91bf117 100644 --- a/storyboard/tests/plugin/oauth/test_cleaner.py +++ b/storyboard/tests/plugin/token_cleaner/test_cleaner.py @@ -18,7 +18,7 @@ from datetime import timedelta from oslo.config import cfg import storyboard.db.api.base as db_api from storyboard.db.models import AccessToken -from storyboard.plugin.oauth.cleaner import TokenCleaner +from storyboard.plugin.token_cleaner.cleaner import TokenCleaner import storyboard.tests.base as base from storyboard.tests.mock_data import load_data @@ -36,12 +36,19 @@ class TestTokenCleaner(base.FunctionalTest): super(TestTokenCleaner, self).tearDown() def test_enabled(self): - """This plugin must always be enabled. The only time it's not enabled - is when cron has been disabled. + """Assert that this plugin responds to the flag set in our + oauth configuration block. """ + CONF.set_override('enable', False, 'plugin_token_cleaner') + plugin = TokenCleaner(CONF) + self.assertFalse(plugin.enabled()) + + CONF.set_override('enable', True, 'plugin_token_cleaner') plugin = TokenCleaner(CONF) self.assertTrue(plugin.enabled()) + CONF.clear_override('enable', 'plugin_token_cleaner') + def test_interval(self): """Assert that the cron manager runs every 5 minutes.""" plugin = TokenCleaner(CONF)