Regular expression support for CORS and OAuth ACLs
Make it possible for allowed_origins and valid_oauth_clients to include regular expressions, for cases where part or all of the domain/URL cannot be predicted or easily enumerated. Change-Id: I9cfc729547560438e0fa1e47cc90cd5579168c73
This commit is contained in:
parent
4c1c7c0cfc
commit
3e4e956ff8
@ -277,7 +277,8 @@ whitespace at the start of the line.
|
||||
.. warning:: If you are running the API in a VM, and plan to access it
|
||||
remotely, ie. by its IP address or hostname, you also need to add
|
||||
that IP address or hostname to the ``valid_oauth_clients`` line in
|
||||
the ``oauth`` section. Uncomment this line too.
|
||||
the ``oauth`` section. Uncomment this line too. It can be a regular
|
||||
expression as well if started with a ``^`` character.
|
||||
|
||||
|
||||
5. Install tox
|
||||
@ -446,7 +447,8 @@ running on the same machine.
|
||||
|
||||
If your browser is on a different machine, the hostname or IP address of the
|
||||
machine running the API will need to be in the ``valid_oauth_clients`` key of
|
||||
``./etc/storyboard.conf`` for the API in order to log in.
|
||||
``./etc/storyboard.conf`` for the API in order to log in. It can be a regular
|
||||
expression as well if started with a ``^`` character.
|
||||
|
||||
By default, the API server uses port 8080, and so the API can be accessed
|
||||
at http://localhost:8080/. That will produce a 404 as the API doesn't
|
||||
|
@ -61,7 +61,7 @@ enable_notifications = True
|
||||
# refresh_token_ttl = 604800
|
||||
|
||||
# A list of valid client id's that may connect to StoryBoard.
|
||||
# valid_oauth_clients = storyboard.openstack.org, localhost
|
||||
# valid_oauth_clients = ^.*\.openstack\.org, localhost
|
||||
|
||||
[scheduler]
|
||||
# Storyboard's scheduled task management configuration
|
||||
@ -73,7 +73,7 @@ enable_notifications = True
|
||||
# W3C CORS configuration. For more information, see http://www.w3.org/TR/cors/
|
||||
|
||||
# List of permitted CORS domains.
|
||||
allowed_origins = https://storyboard.openstack.org, http://localhost:9000
|
||||
allowed_origins = ^https://.*\.openstack\.org, http://localhost:9000
|
||||
|
||||
# CORS browser options cache max age (in seconds)
|
||||
# max_age=3600
|
||||
|
@ -61,7 +61,7 @@ lock_path = $state_path/lock
|
||||
# refresh_token_ttl = 604800
|
||||
|
||||
# A list of valid client id's that may connect to StoryBoard.
|
||||
# valid_oauth_clients = storyboard.openstack.org, localhost
|
||||
# valid_oauth_clients = ^.*\.openstack\.org, localhost
|
||||
|
||||
[scheduler]
|
||||
# Storyboard's scheduled task management configuration
|
||||
@ -73,7 +73,7 @@ lock_path = $state_path/lock
|
||||
# W3C CORS configuration. For more information, see http://www.w3.org/TR/cors/
|
||||
|
||||
# List of permitted CORS domains.
|
||||
# allowed_origins = https://storyboard.openstack.org, http://localhost:9000
|
||||
# allowed_origins = ^https://.*\.openstack\.org, http://localhost:9000
|
||||
|
||||
# CORS browser options cache max age (in seconds)
|
||||
# max_age=3600
|
||||
|
@ -13,6 +13,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import re
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
import requests
|
||||
@ -62,7 +64,14 @@ class OpenIdClient(object):
|
||||
if not client_id:
|
||||
raise InvalidClient(redirect_uri=redirect_uri,
|
||||
message=e_msg.NO_CLIENT_ID)
|
||||
if client_id not in CONF.oauth.valid_oauth_clients:
|
||||
oauth_client_is_invalid = True
|
||||
for valid_oauth_client in CONF.oauth.valid_oauth_clients:
|
||||
if ((valid_oauth_client == client_id) or
|
||||
(valid_oauth_client.startswith('^') and
|
||||
re.match(valid_oauth_client, client_id))):
|
||||
oauth_client_is_invalid = False
|
||||
break
|
||||
if oauth_client_is_invalid:
|
||||
raise UnauthorizedClient(redirect_uri=redirect_uri,
|
||||
message=e_msg.INVALID_CLIENT_ID)
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
# implied. See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import re
|
||||
|
||||
# Default allowed headers
|
||||
|
||||
ALLOWED_HEADERS = [
|
||||
@ -97,18 +99,21 @@ class CORSMiddleware(object):
|
||||
return start_response(status, headers, exc_info)
|
||||
|
||||
# Does this request match one of our origin domains?
|
||||
if origin in self.allowed_origins:
|
||||
for allowed_origin in self.allowed_origins:
|
||||
if ((allowed_origin == origin) or
|
||||
(allowed_origin.startswith('^') and
|
||||
re.match(allowed_origin, origin))):
|
||||
|
||||
# Is this an OPTIONS request?
|
||||
if method == 'OPTIONS':
|
||||
options_headers = [('Content-Length', '0')]
|
||||
replacement_start_response('204 No Content', options_headers)
|
||||
return ''
|
||||
else:
|
||||
# Handle the request.
|
||||
return self.app(env, replacement_start_response)
|
||||
else:
|
||||
# This is not a request for a permitted CORS domain. Return
|
||||
# the response without the appropriate headers and let the browser
|
||||
# figure out the details.
|
||||
return self.app(env, start_response)
|
||||
# Is this an OPTIONS request?
|
||||
if method == 'OPTIONS':
|
||||
options_headers = [('Content-Length', '0')]
|
||||
replacement_start_response('204 No Content',
|
||||
options_headers)
|
||||
return ''
|
||||
else:
|
||||
# Handle the request.
|
||||
return self.app(env, replacement_start_response)
|
||||
# This is not a request for a permitted CORS domain. Return
|
||||
# the response without the appropriate headers and let the browser
|
||||
# figure out the details.
|
||||
return self.app(env, start_response)
|
||||
|
Loading…
Reference in New Issue
Block a user