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:
parent
4e773aa9c9
commit
0548ee4df1
|
@ -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():
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 = (
|
||||
|
|
Loading…
Reference in New Issue