summaryrefslogtreecommitdiffstats
path: root/keystone/token
diff options
context:
space:
mode:
authorSteve Martinelli <stevemar@ca.ibm.com>2013-03-20 20:02:18 -0700
committerDolph Mathews <dolph.mathews@gmail.com>2013-08-16 13:02:24 -0500
commitbcaa3072f37d3af3f9d526f18f311411ceeae160 (patch)
tree8c08bffaabf6c8f195f3d87b9a26edcdaf287371 /keystone/token
parent81534a182a4986d838591395aee8590ef61c599d (diff)
downloadkeystone-bcaa3072f37d3af3f9d526f18f311411ceeae160.tar.gz
keystone-bcaa3072f37d3af3f9d526f18f311411ceeae160.tar.xz
keystone-bcaa3072f37d3af3f9d526f18f311411ceeae160.zip
Add delegated_auth support for keystone
Implements an OAuth 1.0a service provider. blueprint: delegated-auth-via-oauth DocImpact SecurityImpact Change-Id: Ib5561593ab608f3b22fbcd7196e2171f95b735e8
Diffstat (limited to 'keystone/token')
-rw-r--r--keystone/token/backends/kvs.py28
-rw-r--r--keystone/token/backends/memcache.py10
-rw-r--r--keystone/token/backends/sql.py37
-rw-r--r--keystone/token/core.py20
-rw-r--r--keystone/token/providers/uuid.py31
5 files changed, 112 insertions, 14 deletions
diff --git a/keystone/token/backends/kvs.py b/keystone/token/backends/kvs.py
index 171d77df..b2c6ed30 100644
--- a/keystone/token/backends/kvs.py
+++ b/keystone/token/backends/kvs.py
@@ -90,6 +90,29 @@ class Token(kvs.Base, token.Driver):
tokens.append(token.split('-', 1)[1])
return tokens
+ def _consumer_matches(self, consumer_id, token_ref_dict):
+ if consumer_id is None:
+ return True
+ else:
+ if 'token_data' in token_ref_dict:
+ token_data = token_ref_dict.get('token_data')
+ if 'token' in token_data:
+ token = token_data.get('token')
+ oauth = token.get('OS-OAUTH1')
+ if oauth and oauth.get('consumer_id') == consumer_id:
+ return True
+ return False
+
+ def _list_tokens_for_consumer(self, consumer_id):
+ tokens = []
+ now = timeutils.utcnow()
+ for token, ref in self.db.items():
+ if not token.startswith('token-') or self.is_expired(now, ref):
+ continue
+ if self._consumer_matches(consumer_id, ref):
+ tokens.append(token.split('-', 1)[1])
+ return tokens
+
def _list_tokens_for_user(self, user_id, tenant_id=None):
def user_matches(user_id, ref):
return ref.get('user') and ref['user'].get('id') == user_id
@@ -110,9 +133,12 @@ class Token(kvs.Base, token.Driver):
tokens.append(token.split('-', 1)[1])
return tokens
- def list_tokens(self, user_id, tenant_id=None, trust_id=None):
+ def list_tokens(self, user_id, tenant_id=None, trust_id=None,
+ consumer_id=None):
if trust_id:
return self._list_tokens_for_trust(trust_id)
+ if consumer_id:
+ return self._list_tokens_for_consumer(consumer_id)
else:
return self._list_tokens_for_user(user_id, tenant_id)
diff --git a/keystone/token/backends/memcache.py b/keystone/token/backends/memcache.py
index d0d59eef..b80d01bc 100644
--- a/keystone/token/backends/memcache.py
+++ b/keystone/token/backends/memcache.py
@@ -178,7 +178,8 @@ class Token(token.Driver):
self._add_to_revocation_list(data)
return result
- def list_tokens(self, user_id, tenant_id=None, trust_id=None):
+ def list_tokens(self, user_id, tenant_id=None, trust_id=None,
+ consumer_id=None):
tokens = []
user_key = self._prefix_user_id(user_id)
user_record = self.client.get(user_key) or ""
@@ -199,6 +200,13 @@ class Token(token.Driver):
continue
if trust != trust_id:
continue
+ if consumer_id is not None:
+ try:
+ oauth = token_ref['token_data']['token']['OS-OAUTH1']
+ if oauth.get('consumer_id') != consumer_id:
+ continue
+ except KeyError:
+ continue
tokens.append(token_id)
return tokens
diff --git a/keystone/token/backends/sql.py b/keystone/token/backends/sql.py
index 82eab651..5d24fb4f 100644
--- a/keystone/token/backends/sql.py
+++ b/keystone/token/backends/sql.py
@@ -78,7 +78,8 @@ class Token(sql.Base, token.Driver):
token_ref.valid = False
session.flush()
- def delete_tokens(self, user_id, tenant_id=None, trust_id=None):
+ def delete_tokens(self, user_id, tenant_id=None, trust_id=None,
+ consumer_id=None):
"""Deletes all tokens in one session
The user_id will be ignored if the trust_id is specified. user_id
@@ -103,6 +104,11 @@ class Token(sql.Base, token.Driver):
token_ref_dict = token_ref.to_dict()
if not self._tenant_matches(tenant_id, token_ref_dict):
continue
+ if consumer_id:
+ token_ref_dict = token_ref.to_dict()
+ if not self._consumer_matches(consumer_id, token_ref_dict):
+ continue
+
token_ref.valid = False
session.flush()
@@ -112,6 +118,13 @@ class Token(sql.Base, token.Driver):
(token_ref_dict.get('tenant') and
token_ref_dict['tenant'].get('id') == tenant_id))
+ def _consumer_matches(self, consumer_id, token_ref_dict):
+ if consumer_id is None:
+ return True
+ else:
+ oauth = token_ref_dict['token_data']['token'].get('OS-OAUTH1', {})
+ return oauth and oauth['consumer_id'] == consumer_id
+
def _list_tokens_for_trust(self, trust_id):
session = self.get_session()
tokens = []
@@ -141,9 +154,29 @@ class Token(sql.Base, token.Driver):
tokens.append(token_ref['id'])
return tokens
- def list_tokens(self, user_id, tenant_id=None, trust_id=None):
+ def _list_tokens_for_consumer(self, user_id, consumer_id):
+ tokens = []
+ session = self.get_session()
+ with session.begin():
+ now = timeutils.utcnow()
+ query = session.query(TokenModel)
+ query = query.filter(TokenModel.expires > now)
+ query = query.filter(TokenModel.user_id == user_id)
+ token_references = query.filter_by(valid=True)
+
+ for token_ref in token_references:
+ token_ref_dict = token_ref.to_dict()
+ if self._consumer_matches(consumer_id, token_ref_dict):
+ tokens.append(token_ref_dict['id'])
+ session.flush()
+ return tokens
+
+ def list_tokens(self, user_id, tenant_id=None, trust_id=None,
+ consumer_id=None):
if trust_id:
return self._list_tokens_for_trust(trust_id)
+ if consumer_id:
+ return self._list_tokens_for_consumer(user_id, consumer_id)
else:
return self._list_tokens_for_user(user_id, tenant_id)
diff --git a/keystone/token/core.py b/keystone/token/core.py
index e8d04a7e..7eadbe63 100644
--- a/keystone/token/core.py
+++ b/keystone/token/core.py
@@ -174,41 +174,51 @@ class Driver(object):
"""
raise exception.NotImplemented()
- def delete_tokens(self, user_id, tenant_id=None, trust_id=None):
+ def delete_tokens(self, user_id, tenant_id=None, trust_id=None,
+ consumer_id=None):
"""Deletes tokens by user.
If the tenant_id is not None, only delete the tokens by user id under
the specified tenant.
If the trust_id is not None, it will be used to query tokens and the
user_id will be ignored.
+ If the consumer_id is not None, only delete the tokens by consumer id
+ that match the specified consumer id
:param user_id: identity of user
:type user_id: string
:param tenant_id: identity of the tenant
:type tenant_id: string
- :param trust_id: identified of the trust
+ :param trust_id: identity of the trust
:type trust_id: string
+ :param consumer_id: identity of the consumer
+ :type consumer_id: string
:returns: None.
:raises: keystone.exception.TokenNotFound
"""
token_list = self.list_tokens(user_id,
tenant_id=tenant_id,
- trust_id=trust_id)
+ trust_id=trust_id,
+ consumer_id=consumer_id)
+
for token in token_list:
try:
self.delete_token(token)
except exception.NotFound:
pass
- def list_tokens(self, user_id, tenant_id=None, trust_id=None):
+ def list_tokens(self, user_id, tenant_id=None, trust_id=None,
+ consumer_id=None):
"""Returns a list of current token_id's for a user
:param user_id: identity of the user
:type user_id: string
:param tenant_id: identity of the tenant
:type tenant_id: string
- :param trust_id: identified of the trust
+ :param trust_id: identity of the trust
:type trust_id: string
+ :param consumer_id: identity of the consumer
+ :type consumer_id: string
:returns: list of token_id's
"""
diff --git a/keystone/token/providers/uuid.py b/keystone/token/providers/uuid.py
index acfa9372..612df999 100644
--- a/keystone/token/providers/uuid.py
+++ b/keystone/token/providers/uuid.py
@@ -18,6 +18,7 @@
from __future__ import absolute_import
+import json
import sys
import uuid
@@ -206,12 +207,23 @@ class V3TokenDataHelper(object):
'domain': self._get_filtered_domain(user_ref['domain_id'])}
token_data['user'] = filtered_user
+ def _populate_oauth_section(self, token_data, access_token):
+ if access_token:
+ access_token_id = access_token['id']
+ consumer_id = access_token['consumer_id']
+ token_data['OS-OAUTH1'] = ({'access_token_id': access_token_id,
+ 'consumer_id': consumer_id})
+
def _populate_roles(self, token_data, user_id, domain_id, project_id,
- trust):
+ trust, access_token):
if 'roles' in token_data:
# no need to repopulate roles
return
+ if access_token:
+ token_data['roles'] = json.loads(access_token['requested_roles'])
+ return
+
if CONF.trust.enabled and trust:
token_user_id = trust['trustor_user_id']
token_project_id = trust['project_id']
@@ -288,7 +300,7 @@ class V3TokenDataHelper(object):
def get_token_data(self, user_id, method_names, extras,
domain_id=None, project_id=None, expires=None,
trust=None, token=None, include_catalog=True,
- bind=None):
+ bind=None, access_token=None):
token_data = {'methods': method_names,
'extras': extras}
@@ -307,15 +319,17 @@ class V3TokenDataHelper(object):
self._populate_scope(token_data, domain_id, project_id)
self._populate_user(token_data, user_id, domain_id, project_id, trust)
- self._populate_roles(token_data, user_id, domain_id, project_id, trust)
+ self._populate_roles(token_data, user_id, domain_id, project_id, trust,
+ access_token)
if include_catalog:
self._populate_service_catalog(token_data, user_id, domain_id,
project_id, trust)
self._populate_token_dates(token_data, expires=expires, trust=trust)
+ self._populate_oauth_section(token_data, access_token)
return {'token': token_data}
-@dependency.requires('token_api', 'identity_api', 'catalog_api')
+@dependency.requires('token_api', 'identity_api', 'catalog_api', 'oauth_api')
class Provider(token.provider.Provider):
def __init__(self, *args, **kwargs):
super(Provider, self).__init__(*args, **kwargs)
@@ -380,6 +394,12 @@ class Provider(token.provider.Provider):
if (CONF.trust.enabled and not trust and metadata_ref and
'trust_id' in metadata_ref):
trust = self.trust_api.get_trust(metadata_ref['trust_id'])
+
+ access_token = None
+ if 'oauth1' in method_names:
+ access_token_id = auth_context['access_token_id']
+ access_token = self.oauth_api.get_access_token(access_token_id)
+
token_data = self.v3_token_data_helper.get_token_data(
user_id,
method_names,
@@ -389,7 +409,8 @@ class Provider(token.provider.Provider):
expires=expires_at,
trust=trust,
bind=auth_context.get('bind') if auth_context else None,
- include_catalog=include_catalog)
+ include_catalog=include_catalog,
+ access_token=access_token)
token_id = self._get_token_id(token_data)
try: