keystone/keystone/contrib/ec2/core.py

158 lines
6.3 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
"""Main entry point into the EC2 Credentials service."""
from keystone import catalog
from keystone import config
from keystone import identity
from keystone import policy
from keystone import token
from keystone.common import manager
from keystone.common import wsgi
CONF = config.CONF
class Manager(manager.Manager):
"""Default pivot point for the EC2 Credentials backend.
See :mod:`keystone.manager.Manager` for more details on how this
dynamically calls the backend.
See :mod:`keystone.backends.base.Ec2` for more details on the
interface provided by backends.
"""
def __init__(self):
super(Manager, self).__init__(CONF.ec2.driver)
class Ec2Extension(wsgi.ExtensionRouter):
def add_routes(self, mapper):
ec2_controller = Ec2Controller()
# validation
mapper.connect('/ec2tokens',
controller=ec2_controller,
action='authenticate_ec2',
conditions=dict(method=['POST']))
# crud
mapper.connect('/users/{user_id}/credentials/OS-EC2',
controller=ec2_controller,
action='create_credential',
conditions=dict(method=['POST']))
mapper.connect('/users/{user_id}/credentials/OS-EC2',
controller=ec2_controller,
action='get_credentials',
conditions=dict(method=['GET']))
mapper.connect('/users/{user_id}/credentials/OS-EC2/{credential_id}',
controller=ec2_controller,
action='get_credential',
conditions=dict(method=['GET']))
mapper.connect('/users/{user_id}/credentials/OS-EC2/{credential_id}',
controller=ec2_controller,
action='delete_credential',
conditions=dict(method=['DELETE']))
class Ec2Controller(wsgi.Application):
def __init__(self):
self.catalog_api = catalog.Manager()
self.identity_api = identity.Manager()
self.token_api = token.Manager()
self.policy_api = policy.Manager()
self.ec2_api = Manager()
super(Ec2Controller, self).__init__()
def authenticate_ec2(self, context, credentials=None,
ec2Credentials=None):
"""Validate a signed EC2 request and provide a token."""
# NOTE(termie): backwards compat hack
if not credentials and ec2Credentials:
credentials = ec2Credentials
creds_ref = self.ec2_api.get_credential(context,
credentials['access'])
signer = utils.Signer(creds_ref['secret'])
signature = signer.generate(credentials)
if signature == credentials['signature']:
pass
# NOTE(vish): Some libraries don't use the port when signing
# requests, so try again without port.
elif ':' in credentials['signature']:
hostname, _port = credentials['host'].split(":")
credentials['host'] = hostname
signature = signer.generate(credentials)
if signature != credentials.signature:
# TODO(termie): proper exception
raise Exception("Not Authorized")
else:
raise Exception("Not Authorized")
# TODO(termie): don't create new tokens every time
# TODO(termie): this is copied from TokenController.authenticate
token_id = uuid.uuid4().hex
tenant_ref = self.identity_api.get_tenant(creds_ref['tenant_id'])
user_ref = self.identity_api.get_user(creds_ref['user_id'])
metadata_ref = self.identity_api.get_metadata(
context=context,
user_id=user_ref['id'],
tenant_id=tenant_ref['id'])
catalog_ref = self.catalog_api.get_catalog(
context=context,
user_id=user_ref['id'],
tenant_id=tenant_ref['id'],
metadata=metadata_ref)
token_ref = self.token_api.create_token(
context, token_id, dict(expires='',
id=token_id,
user=user_ref,
tenant=tenant_ref,
metadata=metadata_ref))
# TODO(termie): optimize this call at some point and put it into the
# the return for metadata
# fill out the roles in the metadata
roles_ref = []
for role_id in metadata_ref.get('roles', []):
roles_ref.append(self.identity_api.get_role(context, role_id))
# TODO(termie): make this a util function or something
# TODO(termie): i don't think the ec2 middleware currently expects a
# full return, but it contains a note saying that it
# would be better to expect a full return
return TokenController._format_authenticate(
self, token_ref, roles_ref, catalog_ref)
def create_credential(self, context, user_id, tenant_id):
# TODO(termie): validate that this request is valid for given user
# tenant
cred_ref = {'user_id': user_id,
'tenant_id': tenant_id,
'access': uuid.uuid4().hex,
'secret': uuid.uuid4().hex}
self.ec2_api.create_credential(context, cred_ref['access'], cred_ref)
return {'credential': cred_ref}
def get_credentials(self, context, user_id):
"""List credentials for the given user_id."""
# TODO(termie): validate that this request is valid for given user
# tenant
return {'credentials': self.ec2_api.list_credentials(context, user_id)}
def get_credential(self, context, user_id, credential_id):
# TODO(termie): validate that this request is valid for given user
# tenant
return {'credential': self.ec2_api.get_credential(context,
credential_id)}
def delete_credential(self, context, user_id, credential_id):
# TODO(termie): validate that this request is valid for given user
# tenant
return self.ec2_api.delete_credential(context, credential_id)