diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-02-14 22:26:49 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-02-14 22:26:49 +0000 |
| commit | fa9b949b5947dd1163e5321bef8a279fb90faa93 (patch) | |
| tree | dec9b6a484c28279dfeae554a4c34f916a152537 /keystone | |
| parent | 988a5850d1f1ea7f2db4b179a2fab22a878e7bfe (diff) | |
| parent | 71436dbf188b3ff1c576fcd54b992530aac98b6c (diff) | |
Merge "Add token expiration" into redux
Diffstat (limited to 'keystone')
| -rw-r--r-- | keystone/common/sql/core.py | 1 | ||||
| -rw-r--r-- | keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py | 1 | ||||
| -rw-r--r-- | keystone/common/utils.py | 24 | ||||
| -rw-r--r-- | keystone/contrib/ec2/core.py | 3 | ||||
| -rw-r--r-- | keystone/identity/backends/sql.py | 4 | ||||
| -rw-r--r-- | keystone/service.py | 12 | ||||
| -rw-r--r-- | keystone/token/backends/kvs.py | 18 | ||||
| -rw-r--r-- | keystone/token/backends/memcache.py | 13 | ||||
| -rw-r--r-- | keystone/token/backends/sql.py | 33 | ||||
| -rw-r--r-- | keystone/token/core.py | 12 |
10 files changed, 96 insertions, 25 deletions
diff --git a/keystone/common/sql/core.py b/keystone/common/sql/core.py index 2bd24f48..cb621865 100644 --- a/keystone/common/sql/core.py +++ b/keystone/common/sql/core.py @@ -26,6 +26,7 @@ ModelBase = declarative.declarative_base() Column = sql.Column String = sql.String ForeignKey = sql.ForeignKey +DateTime = sql.DateTime # Special Fields diff --git a/keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py b/keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py index 5875817e..ae54b476 100644 --- a/keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py +++ b/keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py @@ -5,6 +5,7 @@ from keystone.common import sql # these are to make sure all the models we care about are defined import keystone.identity.backends.sql +import keystone.token.backends.sql import keystone.contrib.ec2.backends.sql diff --git a/keystone/common/utils.py b/keystone/common/utils.py index b5269bed..96e595bb 100644 --- a/keystone/common/utils.py +++ b/keystone/common/utils.py @@ -23,6 +23,7 @@ import hmac import json import subprocess import sys +import time import urllib import passlib.hash @@ -35,6 +36,9 @@ CONF = config.CONF config.register_int('crypt_strength', default=40000) +ISO_TIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ' + + def import_class(import_str): """Returns a class from a string including module and class.""" mod_str, _sep, class_str = import_str.rpartition('.') @@ -201,3 +205,23 @@ def check_output(*popenargs, **kwargs): def git(*args): return check_output(['git'] + list(args)) + + +def isotime(dt_obj): + """Format datetime object as ISO compliant string. + + :param dt_obj: datetime.datetime object + :returns: string representation of datetime object + + """ + return dt_obj.strftime(ISO_TIME_FORMAT) + + +def unixtime(dt_obj): + """Format datetime object as unix timestamp + + :param dt_obj: datetime.datetime object + :returns: float + + """ + return time.mktime(dt_obj.utctimetuple()) diff --git a/keystone/contrib/ec2/core.py b/keystone/contrib/ec2/core.py index c8ad4425..08a286cc 100644 --- a/keystone/contrib/ec2/core.py +++ b/keystone/contrib/ec2/core.py @@ -163,8 +163,7 @@ class Ec2Controller(wsgi.Application): metadata=metadata_ref) token_ref = self.token_api.create_token( - context, token_id, dict(expires='', - id=token_id, + context, token_id, dict(id=token_id, user=user_ref, tenant=tenant_ref, metadata=metadata_ref)) diff --git a/keystone/identity/backends/sql.py b/keystone/identity/backends/sql.py index 8a3db422..4918a942 100644 --- a/keystone/identity/backends/sql.py +++ b/keystone/identity/backends/sql.py @@ -1,5 +1,7 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 +import copy + from keystone import identity from keystone.common import sql from keystone.common import utils @@ -64,7 +66,7 @@ class Tenant(sql.ModelBase, sql.DictBase): return cls(**tenant_dict) def to_dict(self): - extra_copy = self.extra.copy() + extra_copy = copy.deepcopy(self.extra) extra_copy['id'] = self.id extra_copy['name'] = self.name return extra_copy diff --git a/keystone/service.py b/keystone/service.py index 5be853c1..2c361e40 100644 --- a/keystone/service.py +++ b/keystone/service.py @@ -12,6 +12,7 @@ from keystone import identity from keystone import policy from keystone import token from keystone.common import logging +from keystone.common import utils from keystone.common import wsgi @@ -226,8 +227,7 @@ class TokenController(wsgi.Application): raise webob.exc.HTTPForbidden(e.message) token_ref = self.token_api.create_token( - context, token_id, dict(expires='', - id=token_id, + context, token_id, dict(id=token_id, user=user_ref, tenant=tenant_ref, metadata=metadata_ref)) @@ -283,8 +283,7 @@ class TokenController(wsgi.Application): catalog_ref = {} token_ref = self.token_api.create_token( - context, token_id, dict(expires='', - id=token_id, + context, token_id, dict(id=token_id, user=user_ref, tenant=tenant_ref, metadata=metadata_ref)) @@ -351,8 +350,11 @@ class TokenController(wsgi.Application): def _format_token(self, token_ref, roles_ref): user_ref = token_ref['user'] metadata_ref = token_ref['metadata'] + expires = token_ref['expires'] + if expires is not None: + expires = utils.isotime(expires) o = {'access': {'token': {'id': token_ref['id'], - 'expires': token_ref['expires'] + 'expires': expires, }, 'user': {'id': user_ref['id'], 'name': user_ref['name'], diff --git a/keystone/token/backends/kvs.py b/keystone/token/backends/kvs.py index 84604ac5..990e107b 100644 --- a/keystone/token/backends/kvs.py +++ b/keystone/token/backends/kvs.py @@ -1,5 +1,8 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 +import copy +import datetime + from keystone.common import kvs from keystone import exception from keystone import token @@ -8,14 +11,19 @@ from keystone import token class Token(kvs.Base, token.Driver): # Public interface def get_token(self, token_id): - try: - return self.db['token-%s' % token_id] - except KeyError: + token = self.db.get('token-%s' % token_id) + if (token and (token['expires'] is None + or token['expires'] > datetime.datetime.now())): + return token + else: raise exception.TokenNotFound(token_id=token_id) def create_token(self, token_id, data): - self.db.set('token-%s' % token_id, data) - return data + data_copy = copy.deepcopy(data) + if 'expires' not in data: + data_copy['expires'] = self._get_default_expire_time() + self.db.set('token-%s' % token_id, data_copy) + return copy.deepcopy(data_copy) def delete_token(self, token_id): try: diff --git a/keystone/token/backends/memcache.py b/keystone/token/backends/memcache.py index 8dfb3731..b9c2cbe1 100644 --- a/keystone/token/backends/memcache.py +++ b/keystone/token/backends/memcache.py @@ -1,12 +1,14 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 from __future__ import absolute_import +import copy import memcache from keystone import config from keystone import exception from keystone import token +from keystone.common import utils CONF = config.CONF @@ -38,9 +40,16 @@ class Token(token.Driver): return token def create_token(self, token_id, data): + data_copy = copy.deepcopy(data) ptk = self._prefix_token_id(token_id) - self.client.set(ptk, data) - return data + if 'expires' not in data_copy: + data_copy['expires'] = self._get_default_expire_time() + kwargs = {} + if data_copy['expires'] is not None: + expires_ts = utils.unixtime(data_copy['expires']) + kwargs['time'] = expires_ts + self.client.set(ptk, data_copy, **kwargs) + return copy.deepcopy(data_copy) def delete_token(self, token_id): # Test for existence diff --git a/keystone/token/backends/sql.py b/keystone/token/backends/sql.py index 090a3600..b57f32a8 100644 --- a/keystone/token/backends/sql.py +++ b/keystone/token/backends/sql.py @@ -1,5 +1,8 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 +import copy +import datetime + from keystone.common import sql from keystone import exception from keystone import token @@ -8,21 +11,24 @@ from keystone import token class TokenModel(sql.ModelBase, sql.DictBase): __tablename__ = 'token' id = sql.Column(sql.String(64), primary_key=True) + expires = sql.Column(sql.DateTime(), default=None) extra = sql.Column(sql.JsonBlob()) @classmethod def from_dict(cls, token_dict): # shove any non-indexed properties into extra + extra = copy.deepcopy(token_dict) data = {} - token_dict_copy = token_dict.copy() - data['id'] = token_dict_copy.pop('id') - data['extra'] = token_dict_copy + for k in ('id', 'expires'): + data[k] = extra.pop(k, None) + data['extra'] = extra return cls(**data) def to_dict(self): - extra_copy = self.extra.copy() - extra_copy['id'] = self.id - return extra_copy + out = copy.deepcopy(self.extra) + out['id'] = self.id + out['expires'] = self.expires + return out class Token(sql.Base, token.Driver): @@ -30,15 +36,22 @@ class Token(sql.Base, token.Driver): def get_token(self, token_id): session = self.get_session() token_ref = session.query(TokenModel).filter_by(id=token_id).first() - if not token_ref: + now = datetime.datetime.now() + if token_ref and (not token_ref.expires or now < token_ref.expires): + return token_ref.to_dict() + else: raise exception.TokenNotFound(token_id=token_id) - return token_ref.to_dict() def create_token(self, token_id, data): - data['id'] = token_id + data_copy = copy.deepcopy(data) + if 'expires' not in data_copy: + data_copy['expires'] = self._get_default_expire_time() + + token_ref = TokenModel.from_dict(data_copy) + token_ref.id = token_id + session = self.get_session() with session.begin(): - token_ref = TokenModel.from_dict(data) session.add(token_ref) session.flush() return token_ref.to_dict() diff --git a/keystone/token/core.py b/keystone/token/core.py index 7183c179..8c816efe 100644 --- a/keystone/token/core.py +++ b/keystone/token/core.py @@ -2,11 +2,14 @@ """Main entry point into the Token service.""" +import datetime + from keystone import config from keystone.common import manager CONF = config.CONF +config.register_int('expiration', group='token', default=86400) class Manager(manager.Manager): @@ -68,3 +71,12 @@ class Driver(object): """ raise NotImplementedError() + + def _get_default_expire_time(self): + """Determine when a token should expire based on the config. + + :returns: datetime.datetime object + + """ + expire_delta = datetime.timedelta(seconds=CONF.token.expiration) + return datetime.datetime.now() + expire_delta |
