Merge "Unpythonic code in redux in auth_token.py"
This commit is contained in:
commit
7c2ad0a583
|
@ -120,9 +120,9 @@ class AuthProtocol(object):
|
|||
# where to tell clients to find the auth service (default to url
|
||||
# constructed based on endpoint we have for the service to use)
|
||||
self.auth_location = conf.get('auth_uri',
|
||||
'%s://%s:%s' % (self.auth_protocol,
|
||||
self.auth_host,
|
||||
self.auth_port))
|
||||
'%s://%s:%s' % (self.auth_protocol,
|
||||
self.auth_host,
|
||||
self.auth_port))
|
||||
|
||||
# Credentials used to verify this component with the Auth service since
|
||||
# validating tokens is a privileged call
|
||||
|
@ -143,7 +143,7 @@ class AuthProtocol(object):
|
|||
#Prep headers to forward request to local or remote downstream service
|
||||
proxy_headers = env.copy()
|
||||
for header in proxy_headers.iterkeys():
|
||||
if header[0:5] == 'HTTP_':
|
||||
if header.startswith('HTTP_'):
|
||||
proxy_headers[header[5:]] = proxy_headers[header]
|
||||
del proxy_headers[header]
|
||||
|
||||
|
@ -155,7 +155,9 @@ class AuthProtocol(object):
|
|||
#Configured to allow downstream service to make final decision.
|
||||
#So mark status as Invalid and forward the request downstream
|
||||
self._decorate_request('X_IDENTITY_STATUS',
|
||||
'Invalid', env, proxy_headers)
|
||||
'Invalid',
|
||||
env,
|
||||
proxy_headers)
|
||||
else:
|
||||
#Respond to client as appropriate for this auth protocol
|
||||
return self._reject_request(env, start_response)
|
||||
|
@ -167,13 +169,17 @@ class AuthProtocol(object):
|
|||
if self.delay_auth_decision:
|
||||
# Downstream service will receive call still and decide
|
||||
self._decorate_request('X_IDENTITY_STATUS',
|
||||
'Invalid', env, proxy_headers)
|
||||
'Invalid',
|
||||
env,
|
||||
proxy_headers)
|
||||
else:
|
||||
#Respond to client as appropriate for this auth protocol
|
||||
return self._reject_claims(env, start_response)
|
||||
else:
|
||||
self._decorate_request('X_IDENTITY_STATUS',
|
||||
'Confirmed', env, proxy_headers)
|
||||
'Confirmed',
|
||||
env,
|
||||
proxy_headers)
|
||||
|
||||
#Collect information about valid claims
|
||||
if valid:
|
||||
|
@ -181,34 +187,44 @@ class AuthProtocol(object):
|
|||
|
||||
# Store authentication data
|
||||
if claims:
|
||||
self._decorate_request('X_AUTHORIZATION', 'Proxy %s' %
|
||||
claims['user'], env, proxy_headers)
|
||||
self._decorate_request('X_AUTHORIZATION',
|
||||
'Proxy %s' % claims['user'],
|
||||
env,
|
||||
proxy_headers)
|
||||
|
||||
# For legacy compatibility before we had ID and Name
|
||||
self._decorate_request('X_TENANT',
|
||||
claims['tenant'], env, proxy_headers)
|
||||
claims['tenant'],
|
||||
env,
|
||||
proxy_headers)
|
||||
|
||||
# Services should use these
|
||||
self._decorate_request('X_TENANT_NAME',
|
||||
claims.get('tenantName', claims['tenant']),
|
||||
env, proxy_headers)
|
||||
claims.get('tenantName',
|
||||
claims['tenant']),
|
||||
env,
|
||||
proxy_headers)
|
||||
self._decorate_request('X_TENANT_ID',
|
||||
claims['tenant'], env, proxy_headers)
|
||||
claims['tenant'],
|
||||
env,
|
||||
proxy_headers)
|
||||
|
||||
self._decorate_request('X_USER',
|
||||
claims['userName'], env, proxy_headers)
|
||||
claims['userName'],
|
||||
env,
|
||||
proxy_headers)
|
||||
self._decorate_request('X_USER_ID',
|
||||
claims['user'], env, proxy_headers)
|
||||
claims['user'],
|
||||
env,
|
||||
proxy_headers)
|
||||
|
||||
if 'roles' in claims and len(claims['roles']) > 0:
|
||||
if claims['roles'] != None:
|
||||
roles = ''
|
||||
for role in claims['roles']:
|
||||
if len(roles) > 0:
|
||||
roles += ','
|
||||
roles += role
|
||||
self._decorate_request('X_ROLE',
|
||||
roles, env, proxy_headers)
|
||||
# NOTE(lzyeval): claims has a key 'roles' which is
|
||||
# guaranteed to be a list (see note below)
|
||||
roles = ','.join(filter(lambda x: x, claims['roles']))
|
||||
self._decorate_request('X_ROLE',
|
||||
roles,
|
||||
env,
|
||||
proxy_headers)
|
||||
|
||||
# NOTE(todd): unused
|
||||
self.expanded = True
|
||||
|
@ -223,15 +239,15 @@ class AuthProtocol(object):
|
|||
|
||||
def _reject_request(self, env, start_response):
|
||||
"""Redirect client to auth server"""
|
||||
return webob.exc.HTTPUnauthorized('Authentication required',
|
||||
[('WWW-Authenticate',
|
||||
"Keystone uri='%s'" % self.auth_location)])(env,
|
||||
start_response)
|
||||
headers = [('WWW-Authenticate',
|
||||
"Keystone uri='%s'" % self.auth_location)]
|
||||
resp = webob.exc.HTTPUnauthorized('Authentication required', headers)
|
||||
return resp(env, start_response)
|
||||
|
||||
def _reject_claims(self, env, start_response):
|
||||
"""Client sent bad claims"""
|
||||
return webob.exc.HTTPUnauthorized()(env,
|
||||
start_response)
|
||||
resp = webob.exc.HTTPUnauthorized()
|
||||
return resp(env, start_response)
|
||||
|
||||
def _get_admin_auth_token(self, username, password):
|
||||
"""
|
||||
|
@ -241,23 +257,27 @@ class AuthProtocol(object):
|
|||
"""
|
||||
headers = {
|
||||
"Content-type": "application/json",
|
||||
"Accept": "application/json"}
|
||||
"Accept": "application/json",
|
||||
}
|
||||
params = {
|
||||
"auth": {
|
||||
"passwordCredentials": {
|
||||
"auth": {
|
||||
"passwordCredentials": {
|
||||
"username": username,
|
||||
"password": password,
|
||||
},
|
||||
"tenantName": ADMIN_TENANTNAME,
|
||||
}
|
||||
}
|
||||
"tenantName": ADMIN_TENANTNAME,
|
||||
}
|
||||
}
|
||||
if self.auth_protocol == "http":
|
||||
conn = httplib.HTTPConnection(self.auth_host, self.auth_port)
|
||||
else:
|
||||
conn = httplib.HTTPSConnection(self.auth_host, self.auth_port,
|
||||
cert_file=self.cert_file)
|
||||
conn.request("POST", '/v2.0/tokens', json.dumps(params),
|
||||
headers=headers)
|
||||
conn = httplib.HTTPSConnection(self.auth_host,
|
||||
self.auth_port,
|
||||
cert_file=self.cert_file)
|
||||
conn.request("POST",
|
||||
'/v2.0/tokens',
|
||||
json.dumps(params),
|
||||
headers=headers)
|
||||
response = conn.getresponse()
|
||||
data = response.read()
|
||||
conn.close()
|
||||
|
@ -278,16 +298,21 @@ class AuthProtocol(object):
|
|||
# Step 2: validate the user's token with the auth service
|
||||
# since this is a priviledged op,m we need to auth ourselves
|
||||
# by using an admin token
|
||||
headers = {'Content-type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'X-Auth-Token': self.admin_token}
|
||||
##TODO(ziad):we need to figure out how to auth to keystone
|
||||
#since validate_token is a priviledged call
|
||||
#Khaled's version uses creds to get a token
|
||||
# 'X-Auth-Token': admin_token}
|
||||
# we're using a test token from the ini file for now
|
||||
conn = http_connect(self.auth_host, self.auth_port, 'GET',
|
||||
'/v2.0/tokens/%s' % claims, headers=headers)
|
||||
headers = {
|
||||
'Content-type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'X-Auth-Token': self.admin_token,
|
||||
}
|
||||
##TODO(ziad):we need to figure out how to auth to keystone
|
||||
#since validate_token is a priviledged call
|
||||
#Khaled's version uses creds to get a token
|
||||
# 'X-Auth-Token': admin_token}
|
||||
# we're using a test token from the ini file for now
|
||||
conn = http_connect(self.auth_host,
|
||||
self.auth_port,
|
||||
'GET',
|
||||
'/v2.0/tokens/%s' % claims,
|
||||
headers=headers)
|
||||
resp = conn.getresponse()
|
||||
# data = resp.read()
|
||||
conn.close()
|
||||
|
@ -307,16 +332,21 @@ class AuthProtocol(object):
|
|||
def _expound_claims(self, claims):
|
||||
# Valid token. Get user data and put it in to the call
|
||||
# so the downstream service can use it
|
||||
headers = {'Content-type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'X-Auth-Token': self.admin_token}
|
||||
##TODO(ziad):we need to figure out how to auth to keystone
|
||||
#since validate_token is a priviledged call
|
||||
#Khaled's version uses creds to get a token
|
||||
# 'X-Auth-Token': admin_token}
|
||||
# we're using a test token from the ini file for now
|
||||
conn = http_connect(self.auth_host, self.auth_port, 'GET',
|
||||
'/v2.0/tokens/%s' % claims, headers=headers)
|
||||
headers = {
|
||||
'Content-type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'X-Auth-Token': self.admin_token,
|
||||
}
|
||||
##TODO(ziad):we need to figure out how to auth to keystone
|
||||
#since validate_token is a priviledged call
|
||||
#Khaled's version uses creds to get a token
|
||||
# 'X-Auth-Token': admin_token}
|
||||
# we're using a test token from the ini file for now
|
||||
conn = http_connect(self.auth_host,
|
||||
self.auth_port,
|
||||
'GET',
|
||||
'/v2.0/tokens/%s' % claims,
|
||||
headers=headers)
|
||||
resp = conn.getresponse()
|
||||
data = resp.read()
|
||||
conn.close()
|
||||
|
@ -325,28 +355,28 @@ class AuthProtocol(object):
|
|||
raise LookupError('Unable to locate claims: %s' % resp.status)
|
||||
|
||||
token_info = json.loads(data)
|
||||
roles = []
|
||||
role_refs = token_info['access']['user']['roles']
|
||||
if role_refs != None:
|
||||
for role_ref in role_refs:
|
||||
# Nova looks for the non case-sensitive role 'admin'
|
||||
# to determine admin-ness
|
||||
roles.append(role_ref['name'])
|
||||
access_user = token_info['access']['user']
|
||||
access_token = token_info['access']['token']
|
||||
# Nova looks for the non case-sensitive role 'admin'
|
||||
# to determine admin-ness
|
||||
# NOTE(lzyeval): roles is always a list
|
||||
roles = map(lambda y: y['name'], access_user.get('roles', []))
|
||||
|
||||
try:
|
||||
tenant = token_info['access']['token']['tenant']['id']
|
||||
tenant_name = token_info['access']['token']['tenant']['name']
|
||||
tenant = access_token['tenant']['id']
|
||||
tenant_name = access_token['tenant']['name']
|
||||
except:
|
||||
tenant = None
|
||||
tenant_name = None
|
||||
if not tenant:
|
||||
tenant = token_info['access']['user'].get('tenantId')
|
||||
tenant_name = token_info['access']['user'].get('tenantName')
|
||||
tenant = access_user.get('tenantId')
|
||||
tenant_name = access_user.get('tenantName')
|
||||
verified_claims = {
|
||||
'user': token_info['access']['user']['id'],
|
||||
'userName': token_info['access']['user']['username'],
|
||||
'tenant': tenant,
|
||||
'roles': roles}
|
||||
'user': access_user['id'],
|
||||
'userName': access_user['username'],
|
||||
'tenant': tenant,
|
||||
'roles': roles,
|
||||
}
|
||||
if tenant_name:
|
||||
verified_claims['tenantName'] = tenant_name
|
||||
return verified_claims
|
||||
|
@ -385,7 +415,7 @@ class AuthProtocol(object):
|
|||
if resp.status == 401 or resp.status == 305:
|
||||
# Add our own headers to the list
|
||||
headers = [('WWW_AUTHENTICATE',
|
||||
"Keystone uri='%s'" % self.auth_location)]
|
||||
"Keystone uri='%s'" % self.auth_location)]
|
||||
return webob.Response(status=resp.status,
|
||||
body=data,
|
||||
headerlist=headers)(env, start_response)
|
||||
|
@ -410,10 +440,10 @@ def app_factory(global_conf, **local_conf):
|
|||
return AuthProtocol(None, conf)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = deploy.loadapp('config:' + \
|
||||
os.path.join(os.path.abspath(os.path.dirname(__file__)),
|
||||
os.pardir,
|
||||
os.pardir,
|
||||
'examples/paste/auth_token.ini'),
|
||||
global_conf={'log_name': 'auth_token.log'})
|
||||
app_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
|
||||
os.pardir,
|
||||
os.pardir,
|
||||
'examples/paste/auth_token.ini')
|
||||
app = deploy.loadapp('config:%s' % app_path,
|
||||
global_conf={'log_name': 'auth_token.log'})
|
||||
wsgi.server(eventlet.listen(('', 8090)), app)
|
||||
|
|
Loading…
Reference in New Issue