summaryrefslogtreecommitdiffstats
path: root/keystone/common/wsgi.py
diff options
context:
space:
mode:
authorJamie Lennox <jlennox@redhat.com>2013-06-17 04:22:06 +0000
committerJamie Lennox <jamielennox@gmail.com>2013-07-17 15:37:14 +1000
commit2667c772a30c16ca147f8e38143b59ac53ec5b0c (patch)
treea0765296b56be440847fa856382f79eed216714f /keystone/common/wsgi.py
parent53a03b53e7541367c07df6d4f6739173330f5353 (diff)
downloadkeystone-2667c772a30c16ca147f8e38143b59ac53ec5b0c.tar.gz
keystone-2667c772a30c16ca147f8e38143b59ac53ec5b0c.tar.xz
keystone-2667c772a30c16ca147f8e38143b59ac53ec5b0c.zip
Implement Token Binding.
Brings token binding to keystone server. There are a number of places where the location or hardcoding of binding checks are not optimal however fixing them will require having a proper authentication plugin scheme so just assume that they will be moved when that happens. DocImpact Implements: blueprint authentication-tied-to-token Change-Id: Ib34e5e0b6bd83837f6addbd45d4c5b828ce2f3bd
Diffstat (limited to 'keystone/common/wsgi.py')
-rw-r--r--keystone/common/wsgi.py64
1 files changed, 60 insertions, 4 deletions
diff --git a/keystone/common/wsgi.py b/keystone/common/wsgi.py
index d22e61b9..c7e30576 100644
--- a/keystone/common/wsgi.py
+++ b/keystone/common/wsgi.py
@@ -73,6 +73,55 @@ def mask_password(message, is_unicode=False, secret="***"):
return result
+def validate_token_bind(context, token_ref):
+ bind_mode = CONF.token.enforce_token_bind
+
+ if bind_mode == 'disabled':
+ return
+
+ bind = token_ref.get('bind', {})
+
+ # permissive and strict modes don't require there to be a bind
+ permissive = bind_mode in ('permissive', 'strict')
+
+ # get the named mode if bind_mode is not one of the known
+ name = None if permissive or bind_mode == 'required' else bind_mode
+
+ if not bind:
+ if permissive:
+ # no bind provided and none required
+ return
+ else:
+ LOG.info(_("No bind information present in token"))
+ raise exception.Unauthorized()
+
+ if name and name not in bind:
+ LOG.info(_("Named bind mode %s not in bind information"), name)
+ raise exception.Unauthorized()
+
+ for bind_type, identifier in bind.iteritems():
+ if bind_type == 'kerberos':
+ if not context.get('AUTH_TYPE', '').lower() == 'negotiate':
+ LOG.info(_("Kerberos credentials required and not present"))
+ raise exception.Unauthorized()
+
+ if not context.get('REMOTE_USER') == identifier:
+ LOG.info(_("Kerberos credentials do not match those in bind"))
+ raise exception.Unauthorized()
+
+ LOG.info(_("Kerberos bind authentication successful"))
+
+ elif bind_mode == 'permissive':
+ LOG.debug(_("Ignoring unknown bind for permissive mode: "
+ "{%(bind_type)s: %(identifier)s}"),
+ {'bind_type': bind_type, 'identifier': identifier})
+ else:
+ LOG.info(_("Couldn't verify unknown bind: "
+ "{%(bind_type)s: %(identifier)s}"),
+ {'bind_type': bind_type, 'identifier': identifier})
+ raise exception.Unauthorized()
+
+
class WritableLogger(object):
"""A thin wrapper that responds to `write` and logs."""
@@ -167,10 +216,16 @@ class Application(BaseApplication):
context['headers'] = dict(req.headers.iteritems())
context['path'] = req.environ['PATH_INFO']
params = req.environ.get(PARAMS_ENV, {})
- if 'REMOTE_USER' in req.environ:
- context['REMOTE_USER'] = req.environ['REMOTE_USER']
- elif context.get('REMOTE_USER', None) is not None:
- del context['REMOTE_USER']
+
+ for name in ['REMOTE_USER', 'AUTH_TYPE']:
+ try:
+ context[name] = req.environ[name]
+ except KeyError:
+ try:
+ del context[name]
+ except KeyError:
+ pass
+
params.update(arg_dict)
context.setdefault('is_admin', False)
@@ -233,6 +288,7 @@ class Application(BaseApplication):
except exception.TokenNotFound as e:
raise exception.Unauthorized(e)
+ validate_token_bind(context, user_token_ref)
creds = user_token_ref['metadata'].copy()
try: