Correct 401, 305, and www-authenticate responses

Change-Id: I6205567e7b68917d5ecabcf336a4891802ab7381

Fixing memcache issues.Fixing pep8 changes.

Change-Id: I4e941efec2fad4b945481072b43334bf6477580f

Allow to parse roleRef without tenantId

Change-Id: I9171a73a8646afffba0f8bea67530dbdea7c4428

Return user's roles in response to tenants tenantId

Get tenant from token (if available) instead of user's default tenant

Change-Id: I9171a73a8646afffba0f8bea67530dbdea7c4428

Return endpoints for token without tenant

Change-Id: I9171a73a8646afffba0f8bea67530dbdea7c4428

Parse user roles for nova as csv

Change-Id: I9171a73a8646afffba0f8bea67530dbdea7c4428

Merged in pull request 128

Change-Id: I1e1e040dd5a18b1b70b5a14b01ba7400371e9308
This commit is contained in:
Ziad Sawalha 2011-08-11 02:03:26 -05:00
parent 4e773aa9c9
commit 0548ee4df1
11 changed files with 99 additions and 58 deletions

View File

@ -14,39 +14,49 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from keystone.backends.memcache import MEMCACHE_SERVER, models
from keystone.backends.api import BaseTokenAPI
class TokenAPI(BaseTokenAPI):
def create(self, token):
if not hasattr(token, 'tenant_id'):
token.tenant_id = None
if token.tenant_id != None:
tenant_user_key = token.tenant_id + "::" + token.user_id
else:
tenant_user_key = token.user_id
#Setting them for a day.
MEMCACHE_SERVER.set(token.id, token)
MEMCACHE_SERVER.set(tenant_user_key, token)
def get(self, id, session=None):
return MEMCACHE_SERVER.get(id)
def delete(self, id, session=None):
def get(self, id):
token = MEMCACHE_SERVER.get(id)
if token != None and not hasattr(token, 'tenant_id'):
token.tenant_id = None
return token
def delete(self, id):
token = self.get(id)
if token != None:
MEMCACHE_SERVER.delete(id)
if token.tenant_id != None:
MEMCACHE_SERVER.delete(token.tenant_id + "::" + token.user_id)
else:
MEMCACHE_SERVER.delete(token.id)
MEMCACHE_SERVER.delete(token.user_id)
def get_for_user(self, user_id, session=None):
return MEMCACHE_SERVER.get(user_id)
def get_for_user(self, user_id):
token = MEMCACHE_SERVER.get(user_id)
if token != None and not hasattr(token, 'tenant_id'):
token.tenant_id = None
return token
def get_for_user_by_tenant(self, user_id, tenant_id, session=None):
return MEMCACHE_SERVER.get(tenant_id + "::" + user_id)
def get_for_user_by_tenant(self, user_id, tenant_id):
token = MEMCACHE_SERVER.get(tenant_id + "::" + user_id)
if token != None and not hasattr(token, 'tenant_id'):
token.tenant_id = None
return token
def get():

View File

@ -181,15 +181,16 @@ class TenantAPI(BaseTenantAPI):
def get_all_endpoints(self, tenant_id, session=None):
if not session:
session = get_session()
ep = aliased(models.Endpoints)
endpointTemplates = aliased(models.EndpointTemplates)
q1 = session.query(endpointTemplates).join((ep,
ep.endpoint_template_id == endpointTemplates.id)).\
filter(ep.tenant_id == tenant_id)
q2 = session.query(endpointTemplates).\
q = session.query(endpointTemplates).\
filter(endpointTemplates.is_global == 1)
q3 = q1.union(q2)
return q3.all()
if tenant_id:
ep = aliased(models.Endpoints)
q1 = session.query(endpointTemplates).join((ep,
ep.endpoint_template_id == endpointTemplates.id)).\
filter(ep.tenant_id == tenant_id)
q = q.union(q1)
return q.all()
def get_role_assignments(self, tenant_id, session=None):
if not session:

View File

@ -256,6 +256,11 @@ class UserAPI(BaseUserAPI):
users = session.query(models.User).\
filter("id in ('%s')" % "','".join(user_ids)).\
all()
for usr in users:
usr.tenant_roles = set()
for role in usr.roles:
if role.tenant_id == tenant_id:
usr.tenant_roles.add(role.role_id)
return users
def users_get_by_tenant_get_page_markers(self, tenant_id, marker, limit, \

View File

@ -297,7 +297,9 @@ class IdentityService(object):
limit)
for dtenantuser in dtenantusers:
ts.append(User(None, dtenantuser.id, tenant_id,
dtenantuser.email, dtenantuser.enabled))
dtenantuser.email, dtenantuser.enabled,
dtenantuser.tenant_roles if hasattr(dtenantuser,
"tenant_roles") else None))
links = []
if ts.__len__():
prev, next = api.USER.users_get_by_tenant_get_page_markers(
@ -432,8 +434,10 @@ class IdentityService(object):
def __get_auth_data(self, dtoken, tenant_id):
"""return AuthData object for a token"""
endpoints = None
if tenant_id != None:
try:
endpoints = api.TENANT.get_all_endpoints(tenant_id)
except:
pass
token = auth.Token(dtoken.expires, dtoken.id, tenant_id)
return auth.AuthData(token, endpoints)

View File

@ -201,6 +201,8 @@ class User(object):
class AuthData(object):
"""Authentation Information returned upon successful login."""
url_kinds = ["internal", "public", "admin"]
def __init__(self, token, base_urls=None):
self.token = token
self.base_urls = base_urls
@ -224,18 +226,12 @@ class AuthData(object):
endpoint = etree.Element("endpoint")
if base_url.region:
endpoint.set("region", base_url.region)
if base_url.public_url:
endpoint.set("publicURL",
base_url.public_url.replace('%tenant_id%', \
self.token.tenant_id))
if base_url.admin_url:
endpoint.set("adminURL",
base_url.admin_url.replace('%tenant_id%', \
self.token.tenant_id))
if base_url.internal_url:
endpoint.set("internalURL",
base_url.internal_url.replace('%tenant_id%', \
self.token.tenant_id))
for url_kind in AuthData.url_kinds:
base_url_item = getattr(base_url, url_kind + "_url")
if base_url_item:
endpoint.set(url_kind + "URL",
base_url_item.replace('%tenant_id%', self.token.tenant_id) \
if self.token.tenant_id else base_url_item)
service.append(endpoint)
service_catalog.append(service)
dom.append(service_catalog)
@ -261,15 +257,12 @@ class AuthData(object):
endpoint = {}
if base_url.region:
endpoint["region"] = base_url.region
if base_url.public_url:
endpoint["publicURL"] = base_url.public_url.replace(\
'%tenant_id%', self.token.tenant_id)
if base_url.admin_url:
endpoint["adminURL"] = base_url.admin_url.replace(\
'%tenant_id%', self.token.tenant_id)
if base_url.internal_url:
endpoint["internalURL"] = base_url.internal_url.\
replace('%tenant_id%', self.token.tenant_id)
for url_kind in AuthData.url_kinds:
base_url_item = getattr(base_url, url_kind + "_url")
if base_url_item:
endpoint[url_kind + "URL"] = base_url_item.replace( \
'%tenant_id%', self.token.tenant_id) \
if self.token.tenant_id else base_url_item
endpoints.append(endpoint)
service_catalog[key] = endpoints
auth["serviceCatalog"] = service_catalog

View File

@ -144,8 +144,6 @@ class RoleRef(object):
tenant_id = root.get("tenantId")
if role_id == None:
raise fault.BadRequestFault("Expecting Role")
elif tenant_id == None:
raise fault.BadRequestFault("Expecting Tenant")
return RoleRef('', role_id, tenant_id)
except etree.LxmlError as e:
raise fault.BadRequestFault("Cannot parse RoleRef", str(e))

View File

@ -23,12 +23,13 @@ from keystone.logic.types import fault
class User(object):
"""Document me!"""
def __init__(self, password, user_id, tenant_id, email, enabled):
def __init__(self, password, user_id, tenant_id, email, enabled, tenant_roles=None):
self.user_id = user_id
self.tenant_id = tenant_id
self.password = password
self.email = email
self.enabled = enabled and True or False
self.tenant_roles = tenant_roles
@staticmethod
def from_xml(xml_str):
@ -113,6 +114,13 @@ class User(object):
dom.set("enabled", string.lower(str(self.enabled)))
if self.password:
dom.set("password", self.password)
if self.tenant_roles:
dom_roles = etree.Element("tenantRoles")
for role in self.tenant_roles:
dom_role = etree.Element("tenantRole")
dom_role.text = role
dom_roles.append(dom_role)
dom.append(dom_roles)
return dom
def to_xml(self):
@ -129,6 +137,8 @@ class User(object):
user["password"] = self.password
user["email"] = self.email
user["enabled"] = self.enabled
if self.tenant_roles:
user["tenantRoles"] = list(self.tenant_roles)
return {'user': user}
def to_json(self):

View File

@ -281,8 +281,14 @@ class AuthProtocol(object):
for role_ref in role_refs:
roles.append(role_ref["roleId"])
try:
tenant = token_info['auth']['token']['tenantId']
except:
tenant = None
if not tenant:
tenant = token_info['auth']['user']['tenantId']
verified_claims = {'user': token_info['auth']['user']['username'],
'tenant': token_info['auth']['user']['tenantId'],
'tenant': tenant,
'roles': roles}
return verified_claims

View File

@ -32,6 +32,7 @@ from nova import context
from nova import flags
from nova import utils
from nova import wsgi
from nova import exception
import webob.dec
import webob.exc
@ -65,19 +66,25 @@ class KeystoneAuthShim(wsgi.Middleware):
roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')]
# set user admin-ness to keystone admin-ness
if user_ref.is_admin() != ('Admin' in roles):
self.auth.modify_user(user_ref, ('Admin' in roles))
# FIXME: keystone-admin-role value from keystone.conf is not
# used neither here nor in glance_auth_token!
roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')]
is_admin = 'Admin' in roles
if user_ref.is_admin() != is_admin:
self.auth.modify_user(user_ref, admin=is_admin)
# create a project for tenant
project_id = req.headers['X_TENANT']
try:
self.auth.get_project(project_id)
except:
self.auth.create_project(project_id, user_id)
# ensure user is a member of project
if not self.auth.is_project_member(user_id, project_id):
self.auth.add_to_project(user_id, project_id)
if project_id:
try:
project_ref = self.auth.get_project(project_id)
except:
project_ref = self.auth.create_project(project_id, user_id)
# ensure user is a member of project
if not self.auth.is_project_member(user_id, project_id):
self.auth.add_to_project(user_id, project_id)
else:
project_ref = None
# Get the auth token
auth_token = req.headers.get('X_AUTH_TOKEN',

View File

@ -217,9 +217,16 @@ class AuthProtocol(object):
for role_ref in role_refs:
roles.append(role_ref["roleId"])
try:
tenant = identity_info['auth']['token']['tenantId']
except:
tenant = None
if not tenant:
tenant = identity_info['auth']['user']['tenantId']
# TODO(Ziad): add groups back in
identity = {'user': identity_info['auth']['user']['username'],
'tenant': identity_info['auth']['user']['tenantId'],
'roles': roles}
'tenant': tenant,
'roles':roles}
return identity

View File

@ -12,7 +12,7 @@ TEST_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)),
CONFIG_FILES = (
'sql.conf.template',
#'memcache.conf.template',
# not passing 'memcache.conf.template',
'ldap.conf.template')
TEST_FILES = (