在需要project继承domain的管理权限之时,需要首先在keystone.conf中将os_inherit:enable置于true,这样在做role的grant的时候,就可以以此作为判断是否需要继承domain的管理权限,看看router的定义:
# keystone\keystone\assignment\routers.pyif CONF.os_inherit.enabled:
self._add_resource(
mapper, grant_controller,
path='/OS-INHERIT/domains/{domain_id}/users/{user_id}/roles/'
'{role_id}/inherited_to_projects',
get_head_action='check_grant',
put_action='create_grant',
delete_action='revoke_grant',
rel=build_os_inherit_relation(
resource_name='domain_user_role_inherited_to_projects'),
path_vars={
'domain_id': json_home.Parameters.DOMAIN_ID,
'role_id': json_home.Parameters.ROLE_ID,
'user_id': json_home.Parameters.USER_ID,
})
path以OS-INHERIT开头并以inherited_to_projects结尾,assignment将会被置为1。
# keystone\keystone\assignment\controllers.py
@controller.protected(callback=_check_grant_protection)
def create_grant(self, context, role_id, user_id=None,
group_id=None, domain_id=None, project_id=None):
"""Grants a role to a user or group on either a domain or project."""
self._require_domain_xor_project(domain_id, project_id)
self._require_user_xor_group(user_id, group_id)
self.assignment_api.create_grant(
role_id, user_id, group_id, domain_id, project_id,
self._check_if_inherited(context), context)
def _check_if_inherited(self, context):
return (CONF.os_inherit.enabled and
context['path'].startswith('/OS-INHERIT') and
context['path'].endswith('/inherited_to_projects'))
# keystone\keystone\assignment\core.py
@notifications.role_assignment('created')
def create_grant(self, role_id, user_id=None, group_id=None,
domain_id=None, project_id=None,
inherited_to_projects=False, context=None):
self.role_api.get_role(role_id)
if domain_id:
self.resource_api.get_domain(domain_id)
if project_id:
self.resource_api.get_project(project_id)
self.driver.create_grant(role_id, user_id, group_id, domain_id,
project_id, <strong>inherited_to_projects</strong>)
# keystone\assignment\backends\sql.py
def create_grant(self, role_id, user_id=None, group_id=None,
domain_id=None, project_id=None,
inherited_to_projects=False):
assignment_type = AssignmentType.calculate_type(
user_id, group_id, project_id, domain_id)
try:
with sql.transaction() as session:
session.add(RoleAssignment(
type=assignment_type,
actor_id=user_id or group_id,
target_id=project_id or domain_id,
role_id=role_id,
inherited=<strong>inherited_to_projects</strong>))
except sql.DBDuplicateEntry:
# The v3 grant APIs are silent if the assignment already exists
pass
在做角色验证的时候,会根据配置CONF.os_inherit.enabled是否被置为true来判断是否从project对应的domain中获取权限。
# keystone\keystone\token\providers\common.py
def _populate_roles(self, token_data, user_id, domain_id, project_id,
trust, access_token):
...
if token_domain_id or token_project_id:
roles = self._get_roles_for_user(token_user_id,
token_domain_id,
token_project_id)
# user has no project or domain roles, therefore access denied
if not filtered_roles:
if token_project_id:
msg = _('User %(user_id)s has no access '
'to project %(project_id)s') % {
'user_id': user_id,
'project_id': token_project_id}
然后会根据keystone的配置来看是否需要从domain中获取权限。
# keystone\keystone\assignment\core.py
这里role list则为用户所具有的角色的一个列表。
def _get_user_project_roles(user_id, project_ref):
role_list = []
try:
metadata_ref = self._get_metadata(user_id=user_id,
tenant_id=project_ref['id'])
role_list = self._roles_from_role_dicts(
metadata_ref.get('roles', {}), False)
except exception.MetadataNotFound:
pass
if CONF.os_inherit.enabled:
# Now get any inherited roles for the owning domain
try:
metadata_ref = self._get_metadata(
user_id=user_id, domain_id=project_ref['domain_id'])
role_list += self._roles_from_role_dicts(
metadata_ref.get('roles', {}), True)
except (exception.MetadataNotFound, exception.NotImplemented):
pass
# As well inherited roles from parent projects
for p in self.list_project_parents(project_ref['id']):
p_roles = self.list_grants(
user_id=user_id, project_id=p['id'],
inherited_to_projects=True)
role_list += [x['id'] for x in p_roles]
return role_list