diff options
author | Jamie Lennox <jlennox@redhat.com> | 2013-06-17 04:22:06 +0000 |
---|---|---|
committer | Jamie Lennox <jamielennox@gmail.com> | 2013-07-17 15:37:14 +1000 |
commit | 2667c772a30c16ca147f8e38143b59ac53ec5b0c (patch) | |
tree | a0765296b56be440847fa856382f79eed216714f /keystone/common/wsgi.py | |
parent | 53a03b53e7541367c07df6d4f6739173330f5353 (diff) | |
download | keystone-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.py | 64 |
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: |