Pass Full Credentials to Engine
In order to support HA operations, eg restarting an instance, we need to have full credentials in the engine. This patch passes in the credential information into the engine and uses it to validate the the user. A future patch will have this information stored in database and associated with each stack. It also assigns the username in the case of EC2 style authentication allowing us to support per-user stacks with EC2 auth. Change-Id: I4b92f83d4d10a2bfebd4ddedc8a4f53b3e1217fe Signed-off-by: Ian Main <imain@redhat.com>
This commit is contained in:
parent
709cf56ef7
commit
91352c012b
@ -104,8 +104,10 @@ class EC2Token(wsgi.Middleware):
|
||||
raise webob.exc.HTTPBadRequest()
|
||||
|
||||
# Authenticated!
|
||||
req.headers['X-Auth-EC2-Creds'] = creds_json
|
||||
req.headers['X-Auth-Token'] = token_id
|
||||
req.headers['X-Auth-URL'] = self.conf['auth_uri']
|
||||
req.headers['X-Auth-EC2_URL'] = self.conf['keystone_ec2_uri']
|
||||
return self.application
|
||||
|
||||
|
||||
|
@ -19,6 +19,7 @@ from heat.common import wsgi
|
||||
from heat.openstack.common import cfg
|
||||
from heat.openstack.common import importutils
|
||||
from heat.common import utils as heat_utils
|
||||
import json
|
||||
|
||||
|
||||
def generate_request_id():
|
||||
@ -32,8 +33,10 @@ class RequestContext(object):
|
||||
"""
|
||||
|
||||
def __init__(self, auth_token=None, username=None, password=None,
|
||||
tenant=None, tenant_id=None, auth_url=None, roles=None,
|
||||
is_admin=False, read_only=False, show_deleted=False,
|
||||
aws_creds=None, aws_auth_uri=None,
|
||||
service_user=None, service_password=None, tenant=None,
|
||||
tenant_id=None, auth_url=None, roles=None, is_admin=False,
|
||||
read_only=False, show_deleted=False,
|
||||
owner_is_tenant=True, overwrite=True, **kwargs):
|
||||
"""
|
||||
:param overwrite: Set to False to ensure that the greenthread local
|
||||
@ -46,6 +49,10 @@ class RequestContext(object):
|
||||
self.auth_token = auth_token
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.aws_creds = aws_creds
|
||||
self.aws_auth_uri = aws_auth_uri
|
||||
self.service_user = service_user
|
||||
self.service_password = service_password
|
||||
self.tenant = tenant
|
||||
self.tenant_id = tenant_id
|
||||
self.auth_url = auth_url
|
||||
@ -64,6 +71,10 @@ class RequestContext(object):
|
||||
return {'auth_token': self.auth_token,
|
||||
'username': self.username,
|
||||
'password': self.password,
|
||||
'aws_creds': self.aws_creds,
|
||||
'aws_auth_uri': self.aws_auth_uri,
|
||||
'service_user': self.service_user,
|
||||
'service_password': self.service_password,
|
||||
'tenant': self.tenant,
|
||||
'tenant_id': self.tenant_id,
|
||||
'auth_url': self.auth_url,
|
||||
@ -148,9 +159,27 @@ class ContextMiddleware(wsgi.Middleware):
|
||||
the username.
|
||||
"""
|
||||
|
||||
username = None
|
||||
password = None
|
||||
aws_creds = None
|
||||
aws_auth_uri = None
|
||||
|
||||
if headers.get('X-Auth-EC2-Creds') is not None:
|
||||
aws_creds = headers.get('X-Auth-EC2-Creds')
|
||||
aws_auth_uri = headers.get('X-Auth-EC2-Url')
|
||||
else:
|
||||
# XXX: The eval here is a bit scary, it's possible someone
|
||||
# could put something malicious in here I would think.
|
||||
# I Haven't tested to see if WSGI stuff would escape
|
||||
# everything to make this safe. However, I haven't found
|
||||
# a better way to do this either.
|
||||
creds = eval(req.params['KeyStoneCreds'])
|
||||
username = creds['username']
|
||||
password = creds['password']
|
||||
|
||||
token = headers.get('X-Auth-Token')
|
||||
username = headers.get('X-Admin-User')
|
||||
password = headers.get('X-Admin-Pass')
|
||||
service_user = headers.get('X-Admin-User')
|
||||
service_password = headers.get('X-Admin-Pass')
|
||||
tenant = headers.get('X-Tenant')
|
||||
tenant_id = headers.get('X-Tenant-Id')
|
||||
auth_url = headers.get('X-Auth-Url')
|
||||
@ -160,7 +189,11 @@ class ContextMiddleware(wsgi.Middleware):
|
||||
|
||||
req.context = self.make_context(auth_token=token,
|
||||
tenant=tenant, tenant_id=tenant_id,
|
||||
aws_creds=aws_creds,
|
||||
aws_auth_uri=aws_auth_uri,
|
||||
username=username,
|
||||
password=password,
|
||||
service_user=service_user,
|
||||
service_password=service_password,
|
||||
auth_url=auth_url, roles=roles,
|
||||
is_admin=True)
|
||||
|
@ -18,6 +18,10 @@ from copy import deepcopy
|
||||
import datetime
|
||||
import logging
|
||||
import webob
|
||||
import json
|
||||
import urlparse
|
||||
import httplib
|
||||
|
||||
from heat import manager
|
||||
from heat.db import api as db_api
|
||||
from heat.common import config
|
||||
@ -29,6 +33,7 @@ from heat.openstack.common import timeutils
|
||||
from novaclient.v1_1 import client
|
||||
from novaclient.exceptions import BadRequest
|
||||
from novaclient.exceptions import NotFound
|
||||
from novaclient.exceptions import AuthorizationFailure
|
||||
|
||||
logger = logging.getLogger('heat.engine.manager')
|
||||
|
||||
@ -53,15 +58,54 @@ class EngineManager(manager.Manager):
|
||||
the first call made in an endpoint call. I like to see this
|
||||
done explicitly so that it is clear there is an authentication
|
||||
request at the entry to the call.
|
||||
|
||||
In the case of EC2 style authentication this will also set the
|
||||
username in the context so we can use it to key in the database.
|
||||
"""
|
||||
|
||||
nova = client.Client(con.username, con.password,
|
||||
con.tenant, con.auth_url,
|
||||
proxy_token=con.auth_token,
|
||||
proxy_tenant_id=con.tenant_id,
|
||||
service_type='heat',
|
||||
service_name='heat')
|
||||
nova.authenticate()
|
||||
if con.password is not None:
|
||||
nova = client.Client(con.username, con.password,
|
||||
con.tenant, con.auth_url,
|
||||
service_type='heat',
|
||||
service_name='heat')
|
||||
nova.authenticate()
|
||||
else:
|
||||
# We'll have to do AWS style auth which is more complex.
|
||||
# First step is to get a token from the AWS creds.
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
o = urlparse.urlparse(con.aws_auth_uri)
|
||||
if o.scheme == 'http':
|
||||
conn = httplib.HTTPConnection(o.netloc)
|
||||
else:
|
||||
conn = httplib.HTTPSConnection(o.netloc)
|
||||
conn.request('POST', o.path, body=con.aws_creds, headers=headers)
|
||||
response = conn.getresponse().read()
|
||||
conn.close()
|
||||
|
||||
result = json.loads(response)
|
||||
try:
|
||||
token_id = result['access']['token']['id']
|
||||
# We grab the username here because with token auth and EC2
|
||||
# we never get it normally. We could pass it in but then We
|
||||
# are relying on user input to give us the correct username.
|
||||
# This one is the result of the authentication and is verified.
|
||||
username = result['access']['user']['username']
|
||||
con.username = username
|
||||
|
||||
logger.info("AWS authentication successful.")
|
||||
except (AttributeError, KeyError):
|
||||
# FIXME: Should be 404 I think.
|
||||
logger.info("AWS authentication failure.")
|
||||
raise exception.AuthorizationFailure()
|
||||
|
||||
nova = client.Client(con.service_user, con.service_password,
|
||||
con.tenant, con.auth_url,
|
||||
proxy_token=token_id,
|
||||
proxy_tenant_id=con.tenant_id,
|
||||
service_type='heat',
|
||||
service_name='heat')
|
||||
nova.authenticate()
|
||||
|
||||
def list_stacks(self, context, params):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user