keystone_admin_api

来源:互联网 发布:淘宝客服怎么自动回复 编辑:程序博客网 时间:2024/05/21 05:17
<paste_deploy function="业务流程分析">   <keystone-paste.ini path="/etc/keystone/">      # 我们分析admin      [composite: admin]      use = egg:Pate#urlmap      /v2.0 = admin_api      /v3 = api_v3      / = public_version_api      [pipeline:admin_api]      pipeline = sizelimit url_normalize request_id build_auth_context token_auth      admin_token_auth json_body ec2_extension s3_extension crud_extension admin_service      # 分析/v2.0 入口处理业务      1-[filter:sizelimit]      paste.filter_factory = oslo_middleware.sizelimit:RequestBodySizeLimiter.factory      <RequestBodySizeLimiter path="oslo_middle.sizelimit">         _opts = [            cfg.IntOpt('max_request_body_size',                     default=114688, # 默认为112k                     help='...',                     deprecated_opts=_oldopts)               ]         class RequestBodySizeLimiter(base.Middleware):            # 限制进入的多个请求body大小            def __init__(self, application, conf=None):               super(RequestBodySizeLimiter, self).__init__(application, conf)               <base.Middleware values="" path="oslo_middleware.base">                  # 最后会调用其factory方法                  class Middleware(object):                     # factory会调用子类的__call__方法,在调用前需要初始化                     @classmethod                     def factory(cls, global_conf, **local_conf):                        conf = global_conf.copy() if global_conf else {}                        conf.update(local_conf)                        def middleware_filter(app):                           return cls(app, conf)                        return middleware_filter                     def __init__(self, application, conf=None):                        if isinstance(conf, cfg.COnfigOPts):                           self.conf = []                           self.oslo_conf = conf                        else:                           self.conf = conf or []                           if 'oslo_config_project' in self.conf:                              if 'oslo_config_file' in self.conf:                                 default_config_files = [self.conf['oslo_config_fil']]                              else:                                 default_config_files = None                              self.oslo_conf = cfg.ConfigOpts()                              self.oslo_conf([], project=self.conf['oslo_config_project'],                                          default_config_files=default_config_files,                                          validate_default_values=True)                              # 上面的调用 ConfigOpts实例的__call__                           else:                              # 直接调用cfg.CONF                              self.oslo_conf = cfg.CONF                     def _conf_get(self, key, group='oslo_middleware'):                        if key in self.conf:                           self.oslo_conf.set_override(key, self.conf[key], group=group,                                                enfore_type=True)                           # 是配置有效                        return getattr(getattr(self.oslo_conf, group), key)                  @staticmethod                  def process_request(req):                     # 对每个请求进行处理                     return None                  @staticmethod                  def process_response(response, request=None):                     return response                  @webob.dec.wsgif                  def __call__(self, req):                     response = self.process_request(req)                     if response:                        return response                     response = req.get_response(self.application)                     # 这个get_response(self.application)不知道是哪里的                     (args, varargs, varkw, defaults) = getargspec(self.process_response)                     # getargsepc 是inspec库的函数,用来检测函数的参数                     # ArgSpec(args=['response', 'request'], varargs=None, keywords=None, defaults=(None,))                     if 'request' in args:                        return self.process_response(response, request=req)                     return self.process_response(response)               </base.Middleware>               # 继承的是base.Middleware               self.oslo_conf.register_opts(_opts, group='oslo_middleware')               # 将上面的选项注册进ConfigOpts实例中            @webob.dec.wsgif            # 这个装饰器会将func转变为app            def __call__(self, req):               max_size = self._conf_get('max_request_body_size')               if (req.content_length is not None and req.content_length > max_size):                  msg = _('Request is too large')                  raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)               if req.content_length is None and req.is_body_readable:                  limiter = LimitingRead(req.body_file, max_size)                  <LimitingRead values="(req.body_file, max_size)" path="." function="对单个请求大小进行限制">                     class LimitingReader(object):                        def __init__(self, data, limit):                           self.data = data                           self.limit = limit                           self.bytes_read = 0                        def __iter__(self):                           for chunk in self.data:                              self.bytes_read += len(chunk)                              if self.bytes_read > self.limit:                                 msg = _('Request too large')                                 raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)                              else:                                 yield chunk                        def read(self, i=None):                           # mod_wsgi 与 eventlet不同,所以不能简单的提高一个read                           if i is None:                              result = self.data.read()                           else:                              result = self.data.read(i)                           if self.bytes_read > self.limit:                              # read 加上limit判断                              msg = _('Request too large')                                 raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)                           return result                  </LimitingRead>                  req.body_file = limiter               return self.application      1.1流程->RequestBodySizeLimiter初始化后调用父类Middleware的factory函数继续调用RequestBodySizeLimter的__call__      </RequestBodySizeLimiter>      2-[filter:url_normalize]      paste.filter_factory = keystone.middleware:NormalizingFilter.factory      <NormalizingFIlter.factory values="" path="keystone.middleware.core">         class NormalizingFilter(wsgi.Middleware):            <wsgi.Middleware path="keystone.common.wsgi.core">               class Middleware(Application):                  <Application path=".">                  </Application>                  # 基础WSGI 中间件                  # 初始化需要app,然后才调用factory,只会调用__call__                  @classmethod                  def factory(cls, global_config, **local_config):                     #  配置文件如下                        # [filter:analytics]                        #  redis_host = 127.0.0.1                           # paste.filter_factory = keystone.analytics:Analytics.factory                       # 相当于如下,后返回call调用                        #  import keystone.analytics                        #  keystone.analytics.Analytics(app, redis_host='127.0.0.1')                     def _factory(app):                        conf = global_config.copy()                        conf.update(local)                        return cls(app, **local_config)                     return _factory                  def __init__(self, application)                     super(Middleware, self).__init__()                     self.application = application                  def process_requires(self, request):                     return None                  def process_response(self, request, response):                     return response                  @webob.dec.wsgify()                  # 初始化后调用wsgi().__call__                  def __call__(self, request):                     try:                        response = self.process_request(self.application)                        if response:                           return response                        response = request.get_response(self.application)                        # 通过get_response 可以返回一个webob response object                        return self.process_response(request, response)                     except                        ....                     # 这个__call__调用下面的process_request            </wsgi.Middleware>            # 中间件过滤处理url正常化            def process_request(request):               # 正常化 url               # 移除多余反斜杠               if (len(request.environ['PATH_INFO'])>1 and                  request.environ['PATH_INFO'][-1] == '/'):                  request.environ['PATH_INFO'] = request.environ['PATH_INFO'][:-1]               # 重写path,将其置为root               elif not request.environ['PATH_INFO']:                  request.environ['PATH_INFO'] = '/'      </NormalizingFIlter.factory>      3-[filter:request_id]      paste.filter_factory = oslo_middleware:RequestId.factory      <RequestId.factory path="oslo_middleware.request_id">         ENV_REQUEST_ID = 'openstack.request_id'         HTTP_RESP_HEADER_ID = 'x-openstack-request-id'         class RequestId(base.Middleware):            # 中间件确保request ID            # 确保分配ID对应每个API请求,将其置为request env,request ID同样被添加到API response            @webob.dec.wsgify            def __call__(self, req):               req_id = context.generate_request_id()               <get_response_id path="oslo_context.context.generate_request_id">                  def generate_request_id():                      return b'req-' + str(uuid.uuid4()).encode('ascii')               </get_response_id>               req.environ[ENV_REQUEST_ID] = req.id               response = req.get_response(self.application)               if HTTP_RESP_HEADER_REQUEST_ID not in response.headers:                  response.headers.add(HTTP_RESP_HEADER_REQUEST_ID, req_id)               return response      </RequestId.factory>      4-[filter:build_auth_context]      paste.filter_factory = keystone.middleware:AuthContextMiddleware.factory      <AuthContextMiddleware.factory path="keystone.middleware">         class AuthContextMiddleware(wsgi.Middleware):            # 从 request auth token 中构建 authentication context            def _build_auth_context(self, request):               token_id = request.headers.get(AUTH_TOKEN_HEADER).strip()               if token_id == CONF.admin_token:                  return {}               context = {'token_id': token_id}               context['environment'] = request.environ               try:                  token_ref = token_model.KeystoneToken(                        token_id=token_id,                        token_data=self.token_provider_api.validate_token(token_id) # Application 有token_provider_api                  )                  <token_model.KeystoneToken values="(token_id, token_data)" path="keystone.model.token_model">                     class KeystoneToken(dict):                        def __init__(self, token_id, token_data):                           self.token_data = token_data                           if 'access' in token_access:                              super(KeystoneToken, self).__init__(**token_data['access'])                           elif 'token' in token_data and 'methods' in token_data['token']:                              super(KeystoneToken, self).__init__(**token_data['token'])                           else:                              raise exception.UnsupportedTokenVersionException()                           self.token_id = token_id                           self.short_id = cms.cms_has_token(token_id, mode=CONF.token.has_algorithm) # mode = 'md5' return hash code                           if self.project_scoped and self.domain_scoped:                              raise exception.UnexpectedError(_('Found invalid token: scoped to '                                                      'both project and domain'))                  </token_model.KeystoneToken>                  wsgi.validate_token_bind(context, token_ref)                  <wsgi.validate_token_bind values="(context, token_ref)" path="keystone.common.wsgi">                     CONTEXT_ENV = 'openstack.context'                     PARAMS_ENV = 'openstack.params'                     JSON_ENCODE_CONTENT_TYPES = set(['application/json', 'application/json-home'])                     def validate_token_bind(context, token_ref):                        bind_mode = CONF.token.enforce_token_bind # permissive                        if not isinstance(token_ref, token_model.KeystoneToken):                           raise exception.UnexpectedError(_('token reference must be a KeystoneToken type, got: %s') % type(token_ref))                        bind = token_ref.bind                        permissive = bind_mode in ('permissive', 'strict')                        name = None if permissive or bind_name == 'required' else bind_mode                        if not bind:                           if permissive:                              # 需要绑定而且permissive不为空                              return                           else:                              LOG(_LI('No bind information present in token'))                              raise exception.Unauthorized()                        if name and name not in bind:                           raise exception.Unauthorized()                        for bind_type, identifier in bind.items():                           if bind_type == 'kerberos':                              if not (context['environment'].get('AUTH_TYPE', '').lower()                                      == 'negotiate'):                                     LOG.info(_LI("Kerberos credentials required and not present"))                                     raise exception.Unauthorized()                                 if not context['environment'].get('REMOTE_USER') == identifier:                                     LOG.info(_LI("Kerberos credentials do not match "                                              "those in bind"))                                     raise exception.Unauthorized()                                 LOG.info(_LI("Kerberos bind authentication successful"))                                elif bind_mode == 'permissive':                                    LOG.debug(("Ignoring unknown bind for permissive mode: "                                          "{%(bind_type)s: %(identifier)s}"),                                         {'bind_type': bind_type, 'identifier': identifier})                                else:                                    LOG.info(_LI("Couldn't verify unknown bind: "                                             "{%(bind_type)s: %(identifier)s}"),                                            {'bind_type': bind_type, 'identifier': identifier})                                    raise exception.Unauthorized()                  </wsgi.validate_token_bind>                  return authorization.token_to_auth_context(token_ref)                  <authorization.token_to_auth_context values="token_ref" path="keystone.common.authorization">                     AUTH_CONTEXT_ENV = 'KEYSTONE_AUTH_CONTEXT'                     def token_to_auth_context(token):                        if not isinstance(token, token_model.KeystoneToken):                           raise exception.UnexpectedError(_('token refernce must be a KeystoneToken type, got: %s') % type(token))                        auth_context = {'token': token, 'is_delegated_auth': False}                        try:                           auth_context['user_id'] = token.user_id                        except KeyError:                           LOG.warning(_LW('RBAC:Invalid user data in token'))                           raise exception.Unauthorized()                        if token.project_scoped:                           auth_context['project_id'] = token.project_id                        elif token.domain_scoped:                           auth_context['domain_id'] = token.domain_id                           auth_context['domain_name'] = token.domain_name                        else:                           LOG.debug('RBAC: proceeding without project or domain scope')                        if token.trust_scoped:                           auth_context['is_delegated_auth'] = True                           auth_context['trust_id'] = token.trust_id                           auth_context['trustor_id'] = token.trustor_user_id                           auth_conetxt['trustee_id'] = token.trustee_user_id                        else:                           auth_context['trust_id'] = None                           auth_context['trustor_id'] = None                           auth_context['trustee_id'] = None                        roles = token.role_names                        if roles:                           auth_context['roles'] = roles                        if token.oauth_scoped:                           auth_context['is_delegated_auth'] = True                        auth_context['consumer_id'] = token.oauth_consumer_id                        auth_context['access_token_id'] = token.oauth_access_token_id                        if token.is_federated_user:                           auth_context['group_ids'] = token.federation_group_ids                        return auth_context                  </authorization.token_to_auth_context>               except exception.TokenNotFound:                  LOG.warning(_LW('RBAC:Invalid token'))                  raise exception.Unauthorized            def process_request(self, request):               if AUTH_TOKEN_HEADER not in request.headers:                  LOG.debug(('Auth token not in the request header.'                           'will not build auth context'))                     return               if authorization.AUTH_CONTEXT_ENV in request.environ:                  # 已经存在,返回                  return               auth_context = self._build_auth_context(request)               request.environ[authorization.AUTH_CONTEXT_ENV] = auth_context               # request.environ['KEYSTONE_AUTH_CONTEXT'] = auth_context      </AuthContextMiddleware.factory>      5-[filter:token_auth]      paste.filter_factory = keystone.middleware:TokenAuthMiddleware.factory      <TokenAuthMiddleware.factory path="keystone.middleware.core">         AUTH_TOKEN_HEADER = 'X-Auth-Token'         CONTEXT_ENV = 'openstack.context'         PARAMS_ENV = 'openstack.params'         SUBJECT_TOKEN_HEADER = 'X-Subject-Token'         class TokenAuthMIddleware(wsgi.Middleware):            def process_request(self, request):               token = request.headers.get(AUTH_TOKEN_HEADER)               context = request.environ.get(CONTEXT_ENV, {})               context['token_id'] = token               if SUBJECT_TOKEN_HEADER in request.headers:                  context['subject_token_id'] = request.headers[SUBJECT_TOKEN_HEADER]               request.environ[CONTEXT_ENV] = context      </TokenAuthMiddleware.factory>      6-[filter:admin_token_auth]      paste.filter_factory = keystone.middleware:AdminTokenAuthMiddleware.factory      <AdminTokenAuthMIddleware.factory path="keystone.middleware.core">         class AdminAuthMiddleware(wsgi.Middleware):            def process_request(self, request):               token = request.headers.get(AUTH_TOKEN_HEADER)               context = request.environ.get(CONTEXT_ENV, {})               context['is_admin'] = (token == CONF.admin_token)               request.environ[CONTEXT_ENV] = context               # 验证token == CONF.admin_token,置is_admin的布尔值      </AdminTokenAuthMIddleware.factory>      7-[filter:json_body]      paste.filter_factory = keystone.middleware:JsonBodyMiddleware.factory      <JsonBodyMiddleware.factory path="keystone.middleware.core">         class JsonBodyMiddleware(wsgi.Middleware):            # 允许方法参数以序列化json形式通过            def process_request(self, request):               params_json = request.body:               # 如果为空,早早结束               if not params_json:                  return               # 识别context_type是否为json               if request.context_type not in ('application/json', ''):                  e = exception.ValidationError(attribute='application/json',                                          target='Content-Type header')                  return wsgi.render_exception(e, request=request)               params_parsed = {}               try:                  params_parsed = jsonutils.loads(params_json)               except ValueError:                  e = exception.ValidationError(attribute='valid JSON',                                          target='request body')                  return wsgi.render_exception(e, request=request)               finally:                  if not params_parsed:                     params_parsed = {}               if not isinstance(params_parsed, dict):                  e = exception.ValidationError(attribute='valid JSON object',                                          target='request body')                  return wsgi.render_exception(e, request=request)               params = {}               for k, v in params_parsed.items():                  if k in (self, 'context'):                     continue                  if k.startswith('_'):                     continue                  params[k] = v               request.environ[PARAMS_ENV] = params         # 将request.body json化 ,然后以字典形式 放到 request.environ['openstack.params']      </JsonBodyMiddleware.factory>      8-[filter:ec2_extension]      paste.filter_factory = keystone.contrib.ec2:Ec2Extension.factory      <EC2Extension.factory path="keystone.contrib/ec2/routers">         build_resource_relation = functools.partial(            json_home.build_v3_extension_resource_relation, extension_name='OS-EC2',            extension_version='1.0')         build_parameter_relation = functools.partial(            json_home.build_v3_extension_parameter_relation.extension_name='OS-EC2',            extension_version='1.0')         class EC2Extension(wsgi.ExtensionRouter):            <wsgi.ExtensionRouter values="" path="keystone.common.wsgi">               class ExtensionRouter(Router):                  <Router path="keystone.common.wsgi">                     class Router(object):                        def __init__(self, mapper):                           # 为给定的routes.Mapper创建一个router                           # 每个在Mapper里的router都需要指定一个controller,这就是要被调用的WSGI app                           # action 就是controller里面的方法                           self.map = mapper                           self._router = routes.middleware.RouterMiddleware(self._dispatch, self.map)                        @webob.dec.wsgify() # 下面就是调用的wsgfiy().__call__                        def __call__(self, req):                        @staticmethod                        @webob.dec.wsgify()                        def _dispatch(req):                           # 将请求转发到匹配的controller                           # self._router调用它, 匹配request,并将信息装入req.environ                           match  = req.environ['wsgiorg.routing_args'][1]                           if not match:                              msg = _('The resource could not be found.')                              return render_exception(exception.NotFound(msg),                                                request=req,                                                user_local=best_match_language(req))                           app = match['controller']                           return app                           return self._router                  </Router>                  def __init__(self, application, mapper=None):                     if mapper is None:                        mapper = routes.Mapper()                     self.application = application                     self.add_routes(mapper)                     mapper.connect('/{path_info:.*}', controller=self.application)                     super(ExtensionRouter, self).__init__(mapper)                  def add_router(self, mapper)# 需要覆写                     return pass                  @classmethod                  def factory(cls, global_config, **local_config):                     def _factory(app):                        conf = global_config.copy()                        conf.update(local_config)                        return cls(app, **local_config) # 调用类初始化                     return _factory            </wsgi.ExtensionRouter>            def add_routes(self, mapper):               ec2_controller = controllers.EC2Controller()               <EC2Controller values="" path="keystone.contrib.ec2.controller">                  @dependency.requires('policy_api', 'token_provider_api')                  class EC2Controller(Ec2ControllerCommon, controller.V2Controller):                     @controller.v2_deprecated                     def authenticate(self, context, credentials=None, ec2Credentials=None):                        (user_ref, tenant_ref, metadata_ref, role_ref, catalog_ref) =                        self._authenticate(credentials=credentials,                                       ec2credentials=ec2credentials)                        # 继承EC2ControllerCommon._authenticate                        <Ec2ControllerCommon._authenticate path="">                           def _authenticate(self, credentials=None, ec2credentials=None):                              # credentials: ec2 签名字典                              # ec2credentials : 丢弃的ec2 签名字典                              if not credentials and ec2credentials: 只要ec2credentials                                 credentials = ec2credentials                              if 'access' not in credentials:                                 raise exception.Unauthorized(message='EC2 signature not supplied.')                              creds_ref = self._get_credentials(credentials['access']) # credentials['access'] 是ID                              <EC2ControllerCommon._get_credentials values="(self, credential_id)" path="keystone.contrib.ec2.controller">                                 def _get_credentials(self, credentials):                                    # return: credentials ec2 credentials 字典                                    # utils 在 keystone.common                                    ec2_credentials_id = utils.hash_access_key(credential_id) # 对credential_id进行hash                                    creds = self.credential_api.get_credential(ec2_credential_id)                                    <credential_api.get_credential values="ec2_credential_id" path="keystone.credential.Credential">                                       self.credential_api 就是下面的类的实例                                       # Manager->Driver的过程                                       class Credential(credential.Driver):                                          def get_credential(self, credential_id):                                             session = sql.get_session()                                             return self._get_credential(session, credential_id).to_dict()                                             # self._get_credential(session, credential_id)返回的是CredentialModel                                          def _get_credential(self, session, credential_id):                                             ref = session.query(CredentialModel).get(credential_id)                                             # 查询表CredentialModel                                             if ref is None:                                                raise exception.CredentialNotFound(credential_id=credential_id)                                             return ref                                    </credential_api.get_credential>                                    if not creds:                                       raise exception.Unauthorized(message='EC2 access key not found.')                                    return self._convert_v3_to_ec2_credential(creds)                                    <self._convert_v3_to_ec2_credential values="creds" path="keystone.contrib.ec2.controllers.EC2ControllerCommon">                                       @staticmethod                                       def _convert_v3_to_ec2_credential(credential):                                          try:                                             blob = jsonutils.loads(credential['blob'])                                          except TYpeError:                                             blob = credential['blob']                                          return {'user_id': credential.get('user_id'),                                                'tenant_id': credential.get('project_id'),                                                'access': blob.get('access'),                                                'secret': blob.get('secret'),                                                'trust_id': blob.get('trust_id')}                                    </self._convert_v3_to_ec2_credential>                              </EC2ControllerCommon._get_credentials>                              self.check_signature(creds_ref, credentials)                              <self.check_signature values="(creds_ref, credentials)" path="keystone.contrib.ec2.controllers.EC2ControllerCommon">                                 signer = ec2_utils.Ec2Signer(creds_ref['secret'])                                 ...                              </self.check_signature>                              tenant_ref = self.resource_api.get_project(creds_ref['tenant_id'])                              <self.resource_api.get_project values="(creds_ref['tenant_id'])" path="keystone.resource.core.Manager">                                 @dependency.provider('resource_api')                                 @dependency.requires('assignment_api', 'credential_api', 'domain_config_qpi', 'identity_api', 'revoke_api')                                 class Manager(manager.Manager):                                    # main entry point into the resource service                                    _DOMAIN = 'domain'                                    _PROJECT = 'project'                                    def __init__(self):                                       # 没特别指定就用assignment的驱动                                       resource_driver = CONF.resource.driver                                       if resource_driver is None:                                          assignment_manager = dependency.get_provider('assignment_api')                                          resource_driver = assignment_manager.default_resource_driver()                                          # 返回的是'keystone.resource.backends.sql.Resource.'                                       super(Manger, self).__init__(resource_driver)                                       # 初始化驱动 传递的是entry_point                                    @MEMOIZE                                    def get_project(self, project_id):                                       return self.driver.get_project(project)                                    <self.driver.get_project values="project" path="keystone.resource.backends.sql.Resource">                                       # from keystone import resource as keystone_resource                                       class Resource(keystone_resource.Driver):                                          def get_project(self, tenant_id):                                             with sql.transaction() as session:                                                <sql.transaction values="" path="keystone.common.sql.core">                                                   @contextlib.contextmanager                                                   # contextlib.contextmanager 是装饰函数级别的with,保存上下文                                                   def transaction(expire_on_commit=False):                                                      # 返回SQLAlchemy session                                                      session = get_session(expire_on_commit=expire_on_commit):                                                      with session.begin():                                                         yield session                                                </sql.transaction>                                                return self._get_project(session, tenant_id).to_dict()                                                # _get_project 见下面                                                # 每次sql返回值都会进行一下to_dict()操作                                          def default_assignment_driver(self):                                             # 上面找驱动的返回 就是这里返回的字符串                                             return 'keystone.assignment.backends.sql.Assignment'                                          def _get_project(self, session, project):                                             project_ref = session.query(Project).get(project_id)                                             # 表Project                                             if project_ref is None:                                                raise exception.ProjectNotFound(project_id=project_id)                                             return project_ref                                    </self.driver.get_project>                              </self.resource_api.get_project>                              user_ref = self.identity_api.get_user(creds_ref['user_id'])                              <self.identity_api.get_user values="(creds_ref['user_id'])" path="keystone.identity.core.Manager">                                 MEMOIZE = cache.get_memoization_decorator(section='identity')                                 DOMAIN_CONF = 'keystone.'                                 DOMAIN_CONF_FIAIL = '.conf'                                 @dependency.provider('identity_api')                                 @dependency.requires('assignment_api', 'credential_api', 'id_mapping_api', 'resource_api', 'revoke_api')                                 class Manager(manager.Mnager):                                    _USER = 'user'                                    _GROUP = 'group'                                    def __init__(self):                                       super(Manager, self).__init__(CONF.identity.driver)                                       self.domain_configs = DomainConfigs()                                       self.event_callbacks = {                                          notification.ACTIONS.deleted: {                                             'domain': [self._domain_deleted]                                          }                                       }                                    @domain_configured                                    <domain_configured path="keystone.identity.core">                                       # 这边会启动domain的配置加载                                       def domains_configured(f):                                          @functools.wraps(f):                                          def wrapper(self, *args, **kwargs):                                             if (not self.domain_configs.configured and CONF.identity.domain_specific_drivers_enabled):                                                self.domain_configs.setup_domain_drivers(self.driver, self.resource_api)                                             return f(self, *args, **kwargs)                                          return wrapper                                    </domain_configured>                                    @exception_translated('user')                                    @MEMOIZE                                    def get_user(self, user_id):                                       domain_id, driver, entity_id = (self._get_domain_driver_and_entity_id(user_id))                                       <self._get_domain_driver_and_entity_id values="user_id" path="">                                          def _get_domain_driver_and_entity_id(self, public_id):                                             # 查询public_id详情                                             # 返回: domain_id ,可为空,支持多domain, driver根据domain获取,entity_id根据driver                                             # 使用映射表查找domain,driver以及local entity                                             # 单一driver无需映射表                                             conf = CONF.identiy                                             # 因为不知道entity,所以需要做映射                                             if conf.domain_specific_drivers_enabled:                                                local_id_ref = self.id_mapping_api.get_id_mapping(public_id)                                                return (local_id_ref['domain_id'], self._select_identity_driver(local_id_ref['domain_id']),                                                      local_id_ref['local_id'])                                             driver = self.driver                                             if driver.generates_uuids():                                                if driver.is_domain_aware:                                                   return (None, driver, public_id)                                                else:                                                   return (conf.default_domain_id, driver, public_id)                                             if not CONF.identity_mapping.backward_compatible_ids:                                                local_id_ref = self.id_mapping_api.get_id_mapping(public)                                                if local_id_ref:                                                   return (                                                      local_id_ref['domain_id'],                                                      driver,                                                      local_id_ref['local_id'],                                                      )                                                else:                                                   raise exception.PublicDNotFound(id=public_id)                                             return (conf.default_domain_id, driver, public_id)                                       </self._get_domain_driver_and_entity_id>                                       ref = driver.get_user(entity_id)                                       return self._set_domain_id_and_mapping(ref, domain_id, driver, mapping.EntityType.USER)                              </self.identity_api.get_user>                              metadata_ref = {}                              metadata_ref['roles'] = (                                 self.assignment_api.get_roles_for_user_and_project(user_ref['id'], tenant_ref['id'])                              <self.assignment_api.get_roles_for_user_and_project values="(user_ref['id'], tenant_ref['id'])" path="keystone.assignment.core">                                 @dependency.provider('assignment_api')                                 @dependency.requires('credential_api', 'identity_api', 'resource_api', 'revoke_api', 'role_api')                                 class Manager(manager.Manager):                                    _PROJECT = 'project'                                    _ROLE_REMOVED_FROM_USER = 'role_removed_from_user'                                    _INVALIDATION_USER_PROJECT_TOKENS = 'invalidate_user_project_tokens'                                    def __init__(self):                                       assignemnt = CONF.assignment.driver                                       # 以后identity将包括 identity、resource、assignment                                       super(Manager, self).__init__(assignment_driver)                                    def get_roles_for_user_and_project(self, user_id, tenant_id):                                       # 如果OS-INHERIT拓展可用,那么domain将包含role inherited                                       project_ref = self.resource_api.get_project(tenant_id)                                       user_role_list = _get_user_project_roles(user_id, project_ref)                                       group_role_list = _get_group_project_roles(user_id, project_ref)                                       return list(set(user_role_list + group_role_list))                              </self.assignment_api.get_roles_for_user_and_project>                              trust_id = creds_ref.get('trust_id')                              if trust_id:                                 metadata_trf['trust_id'] = trust_id                                 metadata_ref['trustee_user_id'] = user_ref['id']                              try:                                 self.identity_api.assert_user_enable(                                    user_id=user_ref['id'], user=user_ref)                                 <self.identity_api.assert_user_enable values="(user_id=user_ref['id'], user=user_ref)" path="keystone.identity.core">                                    def assert_user_enabled(self, user_id, user=None):                                       if user is None:                                          user = self.get_user(user_id)                                       self.resource_api.assert_domain_enabled(user['domain_id'])                                          <self.reouce_api.assert_domain_enbaled values="(user['domain_id'])" path="keystone.resource.core.Manager">                                             def assert_domain_enabled(self, domain_id, domain=None):                                                if domain is None:                                                   domain = self.get_domain(domain_id)                                                   <self.get_domain values="domain_id" path=".">                                                      @MEMOIZE                                                      def get_domain(self, domain_id):                                                         return self.driver.get_domain(domain_id)                                                      # 调用sql等后端驱动处理                                                   </self.get_domain>                                                if not domain.get('enabled', True):                                                   raise AssertionError(_('Domain is disabled: %s') % domain_id)                                          </self.reouce_api.assert_domain_enbaled>                                       if not user.get('enabled', True):                                          raise AssertionError(_('User is disabled: %s') % user_id)                                    # identity_api.assert_user_enabled(user_id, user)--->resource_api.assert_domain_enabled(user['domain_id'])                                 </self.identity_api.assert_user_enable>                                 self.resource_api.assert_domain_enabled(                                    domain_id=user_ref['domain_id'])                                    <self.resource_api.assert_domain_enabled values="(domain_id=user_ref['domain_id'])" path="keystone.resource.core">                                       # 就是上面的                                    </self.resource_api.assert_domain_enabled>                                 self.resource_api.assert_project_enabled(                                    project_id=tenant_ref['id'], project=tenant_ref)                                    # 跟assert_project_enabled 类似                              except AssertionError as e:                                 six.reraise(exception.Unauthorized, exception.Unauthorized(e),                                                sys.exc_info()[2])                              roles = metadata_ref.get('roles', [])                              if not roles:                                 raise exception.Unauthorized(message='User not valid for tenant.')                              roles_ref = [self.role_api.get_role(role_id) for role_id in roles]                              <self.role_api.get_role values="(role_id)" path="keystone.assignment.core.RoleManager">                                 @dependency.provider('role_api')                                 @dependency.requires('assignment_api')                                 class RoleManager(manager.Manager):                                    _ROLE = 'role'                                    def __init__(self):                                       role_driver = CONF.role.driver                                       if rle_driver is None:                                          assignment_manager = dependency.get_provider('assignment_api')                                          role_driver = assignment_manager.default_role_driver()                                       super(RoleManager, self).__init__(role_driver)                                    @MEMOIZE                                    def get_role(self, role_id):                                       return self.driver.get_role(role_id)                              </self.role_api.get_role>                              catalog_ref = self.catalog_api.get_catalog(user_ref['id'], tenant_ref['id'])                              return user_ref, tenant_ref, metadata_ref, roles_ref, catalog_ref                        </Ec2ControllerCommon._authenticate>                        user_ref = self.v3_to_v2_user(user_ref)                        <self.v3_to_v2_user values="user_ref" path="keystone.common.controller.v2Controller">                           # 上面EC2Controller类的继承                           @staticmethod                           def v3_to_v2_user(ref):                              # v3 转变为v2                              # v2 users 没有domain                              # v2 user 需要tenantId 而不是 default_project_id                              # v2 user 有username 属性                              def _format_default_project_id(ref):                                 # 将default_project_id 转变为 tenantId                                 default_project_id = ref.pop('default_project_id', None)                                 if default_project_id is not None:                                    ref['tenantId'] = default_project_id                                 elif 'tenantId' in ref:                                    del ref['tenantId']                              def _normalize_and_filter_user_properties(ref):                                 _format_default_project_ids(ref)                                 V2Controller.filter_domain(ref)                                 <V2Controller.filter_domain values="ref" path="keystone.contrib.ec2.core.V2Controller">                                    @staticmethod                                    def filter_domain(ref):                                       # 移除domain,这个方法确保v3 user创建时候属于默认domain                                       if 'domain' in ref:                                          if ref['domain'].get('id') != CONF.identity.default_domain_id:                                          # CONF.identity.default_domain_id = default 应该是008                                             raise exception.Unauthorized(                                                     _('Non-default domain is not supported'))                                          del ref['domain']                                       return ref                                 </V2Controller.filter_domain>                                 V2Controller.filter_domain_id(ref)                                 <V2Controller.filter_domain_id values="ref" path=".">                                    @staticmethod                                    def filter_domain_id(ref):                                       # 因为V2没有domain_id 所以移除                                       if 'domain_id' in ref:                                          if ref['domain_id'] != CONF.identity.default_domain_id:                                             raise exception.Unauthorized(                                                  _('Non-default domain is not supported'))                                          def ref['domain_id']                                       return ref                                 </V2Controller.filter_domain_id>                                 V2Controller.normalize_username_in_response(ref)                                 <V2Controller.normalize_username_in_response values="ref" path="">                                    @staticmethod                                    def normalize_username_in_response(ref):                                       # 在输出的ref中添加username                                       if 'username' not in ref nad 'name' in ref:                                          ref['username'] = ref['name']                                       return ref                                 </V2Controller.normalize_username_in_response>                                 return ref                              if isinstance(ref, dict):                                 return _normalize_and_filter_user_properties(ref)                              elif isinstance(ref, list):                                 [_normalize_and_filter_user_properties(x) for x in ref]                              else:                                    raise ValueError(_('Expected dict or list: %s') % type(ref))                        </self.v3_to_v2_user>                        auth_token_data = dict(user=user_ref, tenant_ref, metadata=metadata_ref, id='placeholder')                        (token_id, token_data) = self.token_provider_api.issue_v2_token(auth_token_data, roles_ref, catalog_ref)                        <self.token_provider_api.issue_v2_token values="(auth_token_data, roles_ref, catalog_ref)" path="keystone.token.provider.Manger">                           # token 总共会用到token_api , token_provider_api, 前者依赖于后者                           MEMOIZE = cache.get_memoization_decorator(section='token')                           UnsupportedTokenVersionException = exception.UnsupportedTokenVersionException                           # 防止某些依赖于旧版本的UnsupportedTokenVersionException,增强兼容                           V2 = token_model.V2                           V3 = token_model.V3                           VERSIONS = token_model.VERSIONS                           @dependency.provider(‘token_provider_api’)                           @dependency.requires('assignment_api', 'revoke_api')                           class Manager(manager.Manager):                              V2 = V2                              V3 = V3                              VERSIONS = VERSIONS                              INVALIDATE_PROJECT_TOKEN_PERSISTENCE = 'invalidate_project_tokens'                              INVALIDATE_USER_TOKEN_PERSISTENCE = 'invalidate_user_tokens'                              _persistence_manager = None                              def __init__(self):                                 super(Manager, self).__init__(CONF.token.provider)                                 self._register_callback_listeners()                              def issue_v2_token(self, token_ref, roles_ref=None, catalog_ref=None):                                 token_id, token_data = self.driver.issue_v2_token(token_ref, roles_ref, catalog_ref)                                 <self.driver.issue_v2_token values="(token_ref, roles_ref, catalog_ref)" path="keystone.token.providers.uuid">                                    # 看keystone.conf可知 provider使用uuid                                    # persistent使用sql                                    # uuid 继承common.BaseProvider                                    class Provider(common.BaseProvider):                                       def __init__(self, *args, **kwargs):                                          super(Provider, self).__init__(*args, **kwargs)                                       def _get_token_id(self, token_data):                                          return uuid.uuid4().hex                                       def needs_persistence(self):                                          return True                                    @dependency.requires('catalog_api', 'identity_api', 'oauth_api', 'resource_api', 'role_api', 'trust_api')                                    class BaseProvider(provider.Provider):                                       def __init__(self, *args, **kwargs):                                          super(BaeProvider, self).__init__(*args, **kwargs)                                          self.v3_token_data_helper = V3TokenDataHelper()                                          self.v2_token_data_helper = V2TokenDataHelper()                                       def issue_v2_token(self, token_ref, reolse_ref=None, catalog_ref=None):                                          metadata_ref = token_ref['metadata']                                          trust_ref = None                                          if CONF.trust.enabled and metadata_ref and 'trust_id' in metadata_ref:                                             trust_ref = self.trust_api.get_trust(metadata_ref['trust_id'])                                          token_data = self.v2_token_data_helper.format_token(token_ref, roles_ref, catalog_ref, trust_ref)                                          <self.v2_token_data_helper.format_token values="(token_ref, roles_ref, catalog_ref, trust_ref)" path=".">                                             @dependency.requires('catalog_api', 'resource_api')                                             class V2TokenDataHelper(object):                                                @classmethod                                                def format_token(cls, token_ref, roles_ref=None, catalog_ref=None):                                                   audit_info =None                                                   user_ref = token_ref['user']                                                   metadata_ref = token_ref['metadata']                                                   if roles_ref is None:                                                      roles_ref = []                                                   expires = token_ref.get('expires', provider.default_expire_time())                                                   # provider.default_expire_time() 是调用的keystone.token.provider                                                   <provider.default_expire_time values="" path="keystone.token.provider">                                                      def default_expire_time():                                                         expire_delta = datetime.timedelta(seconds=CONF.token.expiration)                                                         return timeutils.utcnow() + expire_delta                                                   </provider.default_expire_time>                                                   if expires is not None:                                                      if not isinstance(expires, six.text_type):                                                         expires = timeutils.isotime(expires)                                                   token_data = token_ref.get('token_data')                                                   if token_data:                                                      token_audit = token_data.get('access', token_data).get('token', {}).get('audit_ids')                                                      audit_info = token_audit                                                   if audit_info is None:                                                      audit_info = provider.audit_info(token_ref.get('parent_audit_id'))                                                      <provider.audit_info values="token_ref.get('parent_audit_id')" path="keystone.token.provider">                                                         def random_urlsafe_str():                                                            return base64.urlsafe_b64encode(uuid.uuid4().bytes)[:-2]                                                            # 生成随机的url                                                         def audit_info(parent_audit_id):                                                            audit_id = random_urlsafe_str()                                                            if parent_audit_id is not None:                                                               return [audit_id, parent_audit_id]                                                            return [audit_id]                                                      </provider.audit_info>                                                   o = {'access': {'id': token_ref['id'],                                                               'expires': expires,                                                               'issued_at': timeutils.strtime(),                                                               'audit_ids': audit_info                                                               },                                                         'user': {'id': user_ref['id'],                                                               'name': user_ref['name'],                                                               'username': user_ref['name'],                                                               'roles': roles_ref,                                                               'roles_links': metadata_ref.get('roles_links', [])                                                               }                                                         }                                                   if 'bind' in token_ref:                                                      o['access']['token']['bind'] = token_ref['bind']                                                   if 'tenant' in token_ref and token_ref['tenant']:                                                      token_ref['tenant']['enabled'] = True                                                      o['access']['token']['tenant'] = token_ref['tenant']                                                   if catalog_ref is not None:                                                      o['access']['serviceCatalog'] = V2TokenDataHelper.format_catalog(catalog_ref)                                                   if metadata_ref:                                                      if 'is_admin' in metadata_ref:                                                         o['access']['metadata'] = {'is_admin': metadata_ref['is_admin']}                                                      else:                                                         o['access']['metadata'] = {'is_admin': 0}                                                   if 'roles' in metadata_ref:                                                      o['access']['metadata']['roles'] = metadata_ref['roles']                                                   if CONF.trust.enabled and trust_ref:                                                      o['access']['trust'] = {'trustee_user_id':                                                                        trust_ref['trustee_user_id'],                                                                        'id':trust_ref['id'],                                                                        'trustor_user_id':                                                                        trust_ref['trustor_user_id'],                                                                        'impersonation':                                                                        trust_ref['impersonation']                                                                        }                                                   return o                                                @classmethod                                                def format_catalog(cls, catalog_ref):                                                   <!--# 输出形式:                                                   #  {$REGION: {                                                      #     {$SERVICE: {                                                       #        $key1: $value1,                                                       #                                                       #        }                                                   #     }                                                     #  }                                                   # 输入形式:                                                   #  [{'name': $SERVICE[name],                                                   #'type': $SERVICE,                                                      #     'endpoints': [{                                                       #     'tenantId': $tenant_id,                                                       #     ...                                                       #     'region': $REGION,                                                       #     }],                                                   #     'endpoints_links': [],                                                         #     }]                                                   -->                                                   if not catalog_ref:                                                      services = {}                                                   for region, region_ref in six.iteritems(catalog_ref):                                                      for service, service_ref in six.iteritems(region_ref):                                                         new_service_ref = services.get(service, {})                                                         new_service_ref['name'] = service_ref.pop('name')                                                         new_service_ref['type'] = service                                                         new_service_ref['endpoints_links'] = []                                                         service_ref['region'] = region                                                         endpoints_ref = new_service_ref.get('endpoints', [])                                                         endpoints_ref.append(service_ref)                                                         services[service] = new_service_ref                                                   return services.values()                                          </self.v2_token_data_helper.format_token>                                          token_id = self._get_token_id(token_data)                                          token_data['access']['token']['id'] = token_id                                          return token_id, token_data                                 </self.driver.issue_v2_token>                                 if self._needs_persistence:                                 <self._needs_persistence path=".">                                    @property                                    def _needs_persistence:                                       return self.driver.needs_persistence()                                       <self.driver.needs_persistence values="" path="keystone.token.provider.uuid.Provider">                                          class Provider(common.BaseProvider):                                             def __init__(self, *args, **kwargs):                                                super(Provider, self).__init__(*args, **kwargs)                                             def _get_token_id(self, token_data):                                                return uuid.uuid4().hex                                             def needs_persistence(self):                                                return True                                             # 这就是说token需要被后端存储                                       </self.driver.needs_persistence>                                 </self._needs_persistence>                                    data = dict(                                             id=token_id,                                             expires=token_data['access']['token']['expires'],                                             user=token_ref['user']                                             tenant=token_ref['tenant']                                             metadata_ref=token_ref['metadata'],                                             token_data=token_data,                                             bind=token_ref.get('bind'),                                             trust_id=token_ref['metadata'].get('trust_id'),                                             token_version=self.V2)                                    self._create_token(token_id, data)                                    <self._create_token values="token_id, data" path="keystone.token.provider">                                       def _create_token(self, token_id, token_data):                                          try:                                             if isinstance(token_data, six.string_types):                                                token_data['expires'] = timeutils.normalize_time(timeutils.pare_isotime(token_data['expires']))                                                timeutils.parse_isotime(token_data, token_data)                                             self._persistence.create_token(token_id, token_data)                                             <self._persistence values="self" path=".">                                                @property                                                def _persistence(self):                                                   if self._persistence_manager is None:                                                      self._persistence_manager = persistence.PersistenceManager()                                                   return self._persistence_manager                                                # persistence.PersistenceManager() path="keystone.token.persistence.core"                                                @dependency.requires('assignment_api', 'identity_api', 'resource_api', 'token_provider_api', 'trust_api')                                                class PersistenceManager(manager.Manager):                                                   driver_namespace = 'keystone.token.persistence'                                                   def __init__(self):                                                      super(PersistenceManager, self).__init__(CONF.token.driver)                                                   def get_token(self, token_id):                                                      if not token_id:                                                         raise exception.TokenNotFound(unique_id='')                                                      unique_id = utils.generate_unique_id(token_id)                                                      <utils.generate_unique_id values="(token_id='')" path="keystone.token.utils">                                                         def generate_unique_id(token_id):                                                            return cms.cms_hash_token(token_id, mode=cfg.CONF.token.hash_algorithm)                                                      </utils.generate_unique_id>                                                      token_ref = self._get_token(unique_id)                                                      <self._get_token values="unique_id"  path="">                                                         @MEMOIZE                                                         def _get_token(self, token_id):                                                            return self.driver.get_token(token_id)                                                      </self._get_token>                                                      self._assert_valid(token_id, token_ref)                                                      <self._assert_valid values="(token_id, token_ref)" path="">                                                         def _assert_valid(self, token_id, token_ref):                                                            # token如果过期,抛出TokenNotFound                                                            current_time = timeutils.normalize_time(timeutils.utcnow())                                                            expires = token_ref.get('expires')                                                            if not expires or current_time > timeutils.normalize_time(expires):                                                               raise exception.TokenNotFound(token_id=token_id)                                                      </self._assert_valid>                                                      return token_ref                                                   def create_token(self, token_id, data):                                                      unique_id = utils.generate_unique_id(token_id)                                                      data_copy = copy.deepcopy(data)                                                      data_copy['id'] = unique_id                                                      ret = self.driver.create_token(unique_id, data_copy)                                                      <self.drier.create_token values="(unique_id, data_copy)" path="keystone.token.persistence.backends.sql.Token">                                                         def create_token(self, token_id, data):                                                            data_copy = copy.deepcopy(data)                                                            if not data_copy.get('expires'):                                                               data_copy['expires'] = provider.default_expire_time()                                                            if not data_copy.get('user_id'):                                                               data_copy['user_id'] = data_copy['user']['id']                                                            token_ref = TokenModel.from_dict(data_copy)                                                            token_ref.valid = True                                                            session = sql.get_session()                                                            with session.begin():                                                               session.add(token_ref)                                                               # 跟sqlchemy一样 可以查看sqlchemy相关文档                                                            return token_ref.to_dict()                                                      </self.drier.create_token>''                                                      if MEMOIZE.should_cache(ret):                                                         self._get_token.set(ret, self, unique_id)                                                         # 这边的set到底是哪里来的                                                         # 这个是继承的sqlalchemy.models.ModelBase 父类的父类                                                      return ret                                             </self._persistence>                                          exception Exception:                                             exce_info = sys,exc_info()                                             try:                                                self._persistence.get_token(token_id)                                             except exception.TokenNotFound:                                                six.reraise(*exc_info)                                    </self._create_token>                                 return token_id, token_data                        </self.token_provider_api.issue_v2_token>                        return token_data               </EC2Controller>               # 生效               mapper.connect(                  '/ec2tokens',                  # /v2.0/ec2tokens url是组装还是就直接 /ec2tokens ?                  controller=ec2_controller,                  action='authenticate',                  conditions=dict(method=['POST'])               )               # crub               mapper.connect(                  '/users/{user_id}/credentials/OS-EC2',                  controllers=ec2_controller,                  action='create_credential',                  conditions=dict(method=['POST']))               <create_credential values="(self, context, user_id, tenant_id)" path="keystone.contrib.ec2.controller.EC2Extension">                  @controller.v2_deprecated                  def create_credential(self, context, user_id):                     if not self._is_admin(context):                        <self._is_admin values="context" path=".">                           def _is_admin(self, context):                              try:                                 self.assert_admin(context)                                 <self.assert_admin values="context" path="keystone.common.wsgi.Application">                                    def assert_admin(self, context):                                       if not context['is_admin']:                                          user_token_ref = utils.get_token_ref(context)                                          <utils.get_token_ref values="context" path="keystone.common.utils">                                             def get_token_ref(context):                                                try:                                                   auth_context = (context['environment'][authorization.AUTH_CONTEXT_ENV])                                                   # authorization.AUTH_CONTEXT_ENV = 'KEYSTONE_AUTH_CONTEXT'                                                   # path: keystone.common.authorization                                                   return auth_context['token']                                                except KeyError:                                                   LOG.warning(_LW("Couldn't find the auth context."))                                                   raise exception.Unauthorized()                                          </utils.get_token_ref>                                          validate_token_bind(context, user_token_ref)                                          <validate_token_bind values="(context, user_token_ref)" path="keystone.common.wsgi">                                             def validate_token_bind(context, token_ref):                                                # 确认token是否绑定                                                bind_mode = CONF.token.enforce_token_bind                                                # bind = 'permissive'                                                if bind_mode == 'disabled':                                                   return                                                if not isinstance(token_ref, token_model.KeystoneToken):                                                   raise except.UnexpectedError(_('token reference must be a KeystoneToken type, got: %s') % type(token_ref))                                                bind = token_ref.bind                                                permissive = bind_mode in ('permissive', 'strict')                                                name = None if permissive or bind_mode == 'required' else bind_mode                                                if not bind:                                                   if permissive:                                                      return                                                   else:                                                      LOG.info(_LI("No bind information present in token"))                                                      raise exception.Unauthorized()                                                for bind_type, identifier in bind.items():                                                   # kerberos: 判断绑定类型在判断绑定remote-user是否相符合                                                   # permissive: pass                                                   # 其他: 报错                                                   if bind_type == 'kerberos':                                                      if not (context['environment']).get('AUTH_TYPE', '').lower() == 'negotiate'):                                                         LOG.info(_LI("Kerberos credentials required and not present"))                                                         raise exception.Unauthorized()                                                      if not context['environment'].get('REMOTE_USER') == identifier:                                                         LOG.info(_LI("Kerberos credentials do not match "                                                                "those in bind"))                                                         raise exception.Unauthorized()                                                      LOG.info(_LI("Kerberos bind authentication successful"))                                                   elif bind_mode == 'permissive':                                                      LOG.debug(("Ignoring unknown bind for permissive mode: "                       "                                             {%(bind_type)s: %(identifier)s}"),                                                              {'bind_type': bind_type, 'identifier': identifier})                                                   else:                                                      LOG.infoLOG.info(_LI("Couldn't verify unknown bind: "                                                                     "{%(bind_type)s: %(identifier)s}"),                                                              {'bind_type': bind_type, 'identifier': identifier})                                                      raise exception.Unauthorized()                                          </validate_token_bind>                                          creds = copy.deepcopy(user_token_ref.metadata)                                          try:                                             creds['user_id'] = user_token_ref.user_id                                             # user_token_ref 是KeystoneToken类                                          except exception.UnexpectedError:                                             LOG.debug('Invalid user')                                             raise exception.Unauthorized()                                          if user_token_ref.project_scoped:                                             <user_token_ref.project_scoped values="" path="keystone.modele.token_model">                                                @property                                                def project_scoped(self):                                                   if self.version is V3:                                                      return 'project' in self                                                   else:                                                      return 'tenant' in self['token']                                             </user_token_ref.project_scoped>                                             creds['tenant_id'] = user_token_ref.project_id                                             <user_token_ref.project_id values="" path=".">                                                @property                                                def project_id(self):                                                   try:                                                      if self.version is V3:                                                         return self['project']['id']                                                      else:                                                         return self['token']['tenant']['id']                                                   except KeyError:                                                      raise exception.UnexpectedError()                                             </user_token_ref.project_id>                                          else:                                             LOG.debug('Invalid tenant')                                             raise exception.Unauthorized()                                          creds['roles'] = user_token_ref.role_names                                          <user_token_ref.role_names values="" path="">                                             @property                                             def role_names(self):                                                # 返回role name列表                                                # r为one role                                                if self.version is V3:                                                   return [r['name'] for r in self.get('roles', [])]                                                else:                                                   return [r['name'] for r in self['user'].get('roles', [])]                                          </user_token_ref.role_names>                                          self.policy_api.enforce(creds, 'admin_required', {})                                          <self.policy_api.enforce values="(creds, 'admin_required', {})" path="keystone.policy.core">                                             @dependency.provider('policy_api')                                             class Manager(manager.Manager):                                                driver_namespace = 'keystone.policy'                                                _POLICY = 'policy'                                                def __init__(self):                                                   super(Manager, self).__init__(CONF.policy.driver)                                             # keystone.policy.backends.rules                                             class Policy(policy.PolicyDriverV8):                                                def enforce(self, credentials, action, target):                                                   LOG.debug('enfore %(action)s: %(credentials)s', {'action': action, 'credentials': credentials})                                                   enforce(credentials, action, target)                                                   <enforce values="credentials, action, target, do_raise=True" path="keystone.policy.backends.rules">                                                      from oslo_policy import policy as common_policy                                                      _ENFORCER = None                                                      def reset():                                                         global _ENFORCER                                                         _ENFORCER = None                                                      def init():                                                         global _ENFORCE                                                         if not _ENFORCER:                                                            _ENFORCER = common_policy.Enforcer(CONF)                                                      def enforce(credentials, action, target, do_raise=True):                                                         # 确认action在目标上的有效性                                                         init()                                                         extra = {}                                                         # 如果需要做一个raise,所以需要添加字典参数                                                         if do_raise:                                                            extra.update(exc=exception.ForbiddenAction, action=action, do_raise=do_raise)                                                         return _ENFORCER.enforce(action, target, credentials, **extra)                                                         # _ENFORCER.enforce 是调用Enforce下的enforce                                                         <_ENFORCER.enforce values="(action, target, credentials, **extra)" path="oslo_policy.policy">                                                            class Enforcer(object):                                                               def enforce(self, rule, target, creds, do_raise=False, exc=None, *agrs, **kwargs):                                                                  self.load_rules()                                                                  if instance(rule, _checks.BaseCheck):                                                                     result = rule(target, creds, self)                                                                  elif not self.rules:                                                                     result = False                                                                  else:                                                                     try:                                                                        result = self.rules[rule](target, creds, self)                                                                     except KeyError:                                                                        LOG.debug('Rule [%s] does not exist', rule)                                                                        result = False                                                                  if do_raise and not reslut:                                                                     if exc:                                                                        raise exc(*args, **kwargs)                                                                     raise PolicyNotAuthorized(rule, target, creds)                                                                  return result                                                         </_ENFORCER.enforce>                                                   @重点部分,重点分析                                                   </enforce>                                          </self.policy_api.enforce>                                 </self.assert_admin>                                 # 判断是否有admin权限                                 return True                              except (exception.Forbidden, exception.Unauthorized):                                 return False                        </self._is_admin>                        self._assert_identity(context, user_id)                     return super(EC2Controller, self).create_credential(context, user_id, tenant_id)               </create_credential>               mapper.connect(                  '/users/{user_id}/credentials/OS-EC2',                  controllers=ec2_controller,                  action='get_credentials',                  conditions=dict(method=['GET']))               mapper.connect(                  '/users/{user_id}/credentials/OS-EC2/{credential_id}',                  controllers=ec2_controller,                  action='get_credential',                  conditions=dict(method=['GET']))               mapper.connect(                  '/users/{user_id}/credentials/OS-EC2/{credential_id}',                  controllers=ec2_controller,                  action='delete_credential',                  conditions=dict(method=['DELETE']))      </EC2Extension.factory>      9-[filter:s3_extension]      paste.filter_factory = keystone.contrib.s3:S3Extension.factory      <S3Extension.factory values="" path="keystone.contrib.s3:S3Extension.factory">         # 是向其他应用开放的认证      </S3Extension.factory>      10-[filter:crud_extension]      paste.filter_factory = keystone.contrib.admin_crud:CrudExtension.factory      <CrudExtension.factory path="keystone.contrib.admin_crud:CrudExtension.factory">         class CrudExtension(wsgi.ExtensionRouter):            def add_router(self, mapper):               tenant_controller = resource.controllers.Tenant()               assignment_tenant_controller = (assignment.controllers.TenantAssignment())               user_controller = identity.controllers.User()               role_controller = assignment.controllers.Role()               assignment_role_controller = assignment.controller.RoleAssignmentV2()               service_controller = catalog.controllers.Service()               endpoint_controller = catalog.controllers.Endpoint()               # 上面全是提供的API               # 租户/project操作               mapper.connect(                     '/tenants',                     controller=tenant_controller,                     action='create_project',                     conditions=dict(method=['POST']))               mapper.connect(                     '/tenant/{tenant_id}',                     controller=tenant_controller,                     action='update_project',                     conditions=dict(method=['PUT','POST'])               # 重点,后面在分析      </CrudExtension.factory>      11-[filter:admin_service]      paste.app_factory = keystone.service:admin_app_factory      <keystone.service.admin_app_factory>         @fail_gracefully         <fail_garcefully values="" path="." function="执行装饰函数,若出错,报错:严重">            def fail_gracefully(f):               @functools.wraps(f):               def wrapper(*args, **kw):                  try:                     return f(*args, **kw)                  except Exception as e:                     LOG.debug(e, exc_info=True)                     LOG.critical(e)                     sys.exit(1)            return wrapper         </fail_garcefully>         def admin_app_factory(global_conf, **local_conf):            controllers.register_version('v2.0'):            return wsgi.ComposingRouter(routes.Mapper(), [identity.routes.Admin(), assignment.routes.Admin(), token.routes.Router(),                                 resource.routers.Admin(), routers.VersionV2('admin'), routers.Extension()])      </keystone.service.admin_app_factory>   </keystone-paste.ini></paste_deploy>

查看原文:http://www.zoues.com/index.php/2015/09/26/keystone_admin_api/

0 0
原创粉丝点击