在需要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