you may confusing about the context

本文深入解析了OpenStack中Context的概念及其实现方式。通过详细分析Nova、Keystone和Neutron等模块,阐述了如何创建和使用Context来传递关键认证信息。

无论我们看openstack的哪个模块,在很多调用的函数参数中总能看到context的身影,context顾名思义是上下文,在调用时除了self,恐怕见到最多的是这个词,

很多时候并不知道context是什么,更不知道怎么用,从nova进去看看:

以/v2 rest 为例,

[composite:openstack_compute_api_v2]
use = call:nova.api.auth:pipeline_factory
noauth = compute_req_id faultwrap sizelimit noauth ratelimit osapi_compute_app_v2
keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
keystone_nolimit = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2

这个keystonecontext作为一个middleware,定义在:

[filter:keystonecontext]
paste.filter_factory = nova.api.auth:NovaKeystoneContext.factory

作为一个middleware继承自wsgi.Middleware

class NovaKeystoneContext(wsgi.Middleware):

和其他middle一样,NovaKeystoneContext实现__call__函数:

        ctx = context.RequestContext(user_id,
                                     project_id,
                                     user_name=user_name,
                                     project_name=project_name,
                                     roles=roles,
                                     auth_token=auth_token,
                                     remote_address=remote_address,
  #可以在request的header中指定,或者client时生成
                                     service_catalog=service_catalog,
                                     request_id=req_id)

        req.environ['nova.context'] = ctx
        return self.application

在controller中,执行具体相应时候,参数中有req,这时要使用时从req中取出即可


其他的模块都有类似的,比如keystone中:

[pipeline:admin_api]
# The last item in this pipeline must be admin_service or an equivalent
# application. It cannot be a filter.
pipeline = sizelimit url_normalize build_auth_context token_auth admin_token_auth xml_body_v2 json_body ec2_extension s3_extension crud_extension admin_service


[filter:build_auth_context]
paste.filter_factory = keystone.middleware:AuthContextMiddleware.factory

在process_request中:

request.environ[authorization.AUTH_CONTEXT_ENV] = auth_context


还有neutron中:

[composite:neutronapi_v2_0]
use = call:neutron.auth:pipeline_factory
noauth = request_id catch_errors extensions neutronapiapp_v2_0
keystone = request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0


[filter:keystonecontext]
paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory

        ctx = context.Context(user_id, tenant_id, roles=roles,
                              user_name=user_name, tenant_name=tenant_name,
                              request_id=req_id, auth_token=auth_token)

        # Inject the context...
        req.environ['neutron.context'] = ctx

        return self.application

和nova一样,在controller中可以使用


知道context是什么,有什么,再看起来就更明白了

EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, enc) ; int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc) { return evp_cipher_init_internal(ctx, cipher, impl, key, iv, enc, 0, NULL); } static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc, uint8_t is_pipeline, const OSSL_PARAM params[]) { int n; #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) ENGINE *tmpimpl = NULL; #endif /* * enc == 1 means we are encrypting. * enc == 0 means we are decrypting. * enc == -1 means, use the previously initialised value for encrypt/decrypt */ if (enc == -1) { enc = ctx->encrypt; } else { if (enc) enc = 1; ctx->encrypt = enc; } if (cipher == NULL && ctx->cipher == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET); return 0; } /* Code below to be removed when legacy support is dropped. */ if (is_pipeline) goto nonlegacy; #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) /* * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so * this context may already have an ENGINE! Try to avoid releasing the * previous handle, re-querying for an ENGINE, and having a * reinitialisation, when it may all be unnecessary. */ if (ctx->engine && ctx->cipher && (cipher == NULL || cipher->nid == ctx->cipher->nid)) goto skip_to_init; if (cipher != NULL && impl == NULL) { /* Ask if an ENGINE is reserved for this job */ tmpimpl = ENGINE_get_cipher_engine(cipher->nid); } #endif /* * If there are engines involved then we should use legacy handling for now. */ if (ctx->engine != NULL #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) || tmpimpl != NULL #endif || impl != NULL || (cipher != NULL && cipher->origin == EVP_ORIG_METH) || (cipher == NULL && ctx->cipher != NULL && ctx->cipher->origin == EVP_ORIG_METH)) { if (ctx->cipher == ctx->fetched_cipher) ctx->cipher = NULL; EVP_CIPHER_free(ctx->fetched_cipher); ctx->fetched_cipher = NULL; goto legacy; } /* * Ensure a context left lying around from last time is cleared * (legacy code) */ if (cipher != NULL && ctx->cipher != NULL) { if (ctx->cipher->cleanup != NULL && !ctx->cipher->cleanup(ctx)) return 0; OPENSSL_clear_free(ctx->cipher_data, ctx->cipher->ctx_size); ctx->cipher_data = NULL; } /* Start of non-legacy code below */ nonlegacy: /* Ensure a context left lying around from last time is cleared */ if (cipher != NULL && ctx->cipher != NULL) { unsigned long flags = ctx->flags; EVP_CIPHER_CTX_reset(ctx); /* Restore encrypt and flags */ ctx->encrypt = enc; ctx->flags = flags; } if (cipher == NULL) cipher = ctx->cipher; if (cipher->prov == NULL) { #ifdef FIPS_MODULE /* We only do explicit fetches inside the FIPS module */ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; #else EVP_CIPHER *provciph = EVP_CIPHER_fetch(NULL, cipher->nid == NID_undef ? "NULL" : OBJ_nid2sn(cipher->nid), ""); if (provciph == NULL) return 0; cipher = provciph; EVP_CIPHER_free(ctx->fetched_cipher); ctx->fetched_cipher = provciph; #endif } if (!ossl_assert(cipher->prov != NULL)) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } if (cipher != ctx->fetched_cipher) { if (!EVP_CIPHER_up_ref((EVP_CIPHER *)cipher)) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } EVP_CIPHER_free(ctx->fetched_cipher); /* Coverity false positive, the reference counting is confusing it */ /* coverity[use_after_free] */ ctx->fetched_cipher = (EVP_CIPHER *)cipher; } ctx->cipher = cipher; if (is_pipeline && !EVP_CIPHER_can_pipeline(cipher, enc)) { ERR_raise(ERR_LIB_EVP, EVP_R_PIPELINE_NOT_SUPPORTED); return 0; } if (ctx->algctx == NULL) { ctx->algctx = ctx->cipher->newctx(ossl_provider_ctx(cipher->prov)); if (ctx->algctx == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } } if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { /* * If this ctx was already set up for no padding then we need to tell * the new cipher about it. */ if (!EVP_CIPHER_CTX_set_padding(ctx, 0)) return 0; } #ifndef FIPS_MODULE /* * Fix for CVE-2023-5363 * Passing in a size as part of the init call takes effect late * so, force such to occur before the initialisation. * * The FIPS provider's internal library context is used in a manner * such that this is not an issue. */ if (params != NULL) { OSSL_PARAM param_lens[3] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; OSSL_PARAM *q = param_lens; const OSSL_PARAM *p; p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); if (p != NULL) memcpy(q++, p, sizeof(*q)); /* * Note that OSSL_CIPHER_PARAM_AEAD_IVLEN is a synonym for * OSSL_CIPHER_PARAM_IVLEN so both are covered here. */ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); if (p != NULL) memcpy(q++, p, sizeof(*q)); if (q != param_lens) { if (!EVP_CIPHER_CTX_set_params(ctx, param_lens)) { ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_LENGTH); return 0; } } } #endif if (is_pipeline) return 1; if (enc) { if (ctx->cipher->einit == NULL) { /* * We still should be able to set the IV using the new API * if the key is not specified and old API is not available */ if (key == NULL && ctx->cipher->einit_skey != NULL) { return ctx->cipher->einit_skey(ctx->algctx, NULL, iv, iv == NULL ? 0 : EVP_CIPHER_CTX_get_iv_length(ctx), params); } ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } return ctx->cipher->einit(ctx->algctx, key, key == NULL ? 0 : EVP_CIPHER_CTX_get_key_length(ctx), iv, iv == NULL ? 0 : EVP_CIPHER_CTX_get_iv_length(ctx), params); } if (ctx->cipher->dinit == NULL) { /* * We still should be able to set the IV using the new API * if the key is not specified and old API is not available */ if (key == NULL && ctx->cipher->dinit_skey != NULL) { return ctx->cipher->dinit_skey(ctx->algctx, NULL, iv, iv == NULL ? 0 : EVP_CIPHER_CTX_get_iv_length(ctx), params); } ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } return ctx->cipher->dinit(ctx->algctx, key, key == NULL ? 0 : EVP_CIPHER_CTX_get_key_length(ctx), iv, iv == NULL ? 0 : EVP_CIPHER_CTX_get_iv_length(ctx), params); /* Code below to be removed when legacy support is dropped. */ legacy: if (cipher != NULL) { /* * Ensure a context left lying around from last time is cleared (we * previously attempted to avoid this if the same ENGINE and * EVP_CIPHER could be used). */ if (ctx->cipher) { unsigned long flags = ctx->flags; EVP_CIPHER_CTX_reset(ctx); /* Restore encrypt and flags */ ctx->encrypt = enc; ctx->flags = flags; } #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) if (impl != NULL) { if (!ENGINE_init(impl)) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } } else { impl = tmpimpl; } if (impl != NULL) { /* There's an ENGINE for this job ... (apparently) */ const EVP_CIPHER *c = ENGINE_get_cipher(impl, cipher->nid); if (c == NULL) { /* * One positive side-effect of US's export control history, * is that we should at least be able to avoid using US * misspellings of "initialisation"? */ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } /* We'll use the ENGINE's private cipher definition */ cipher = c; /* * Store the ENGINE functional reference so we know 'cipher' came * from an ENGINE and we need to release it when done. */ ctx->engine = impl; } else { ctx->engine = NULL; } #endif ctx->cipher = cipher; if (ctx->cipher->ctx_size) { ctx->cipher_data = OPENSSL_zalloc(ctx->cipher->ctx_size); if (ctx->cipher_data == NULL) { ctx->cipher = NULL; return 0; } } else { ctx->cipher_data = NULL; } ctx->key_len = cipher->key_len; /* Preserve wrap enable flag, zero everything else */ ctx->flags &= EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) { if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL) <= 0) { ctx->cipher = NULL; ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); return 0; } } } #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE) skip_to_init: #endif if (ctx->cipher == NULL) return 0; /* we assume block size is a power of 2 in *cryptUpdate */ OPENSSL_assert(ctx->cipher->block_size == 1 || ctx->cipher->block_size == 8 || ctx->cipher->block_size == 16); if (!(ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) && EVP_CIPHER_CTX_get_mode(ctx) == EVP_CIPH_WRAP_MODE) { ERR_raise(ERR_LIB_EVP, EVP_R_WRAP_MODE_NOT_ALLOWED); return 0; } if ((EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(ctx)) & EVP_CIPH_CUSTOM_IV) == 0) { switch (EVP_CIPHER_CTX_get_mode(ctx)) { case EVP_CIPH_STREAM_CIPHER: case EVP_CIPH_ECB_MODE: break; case EVP_CIPH_CFB_MODE: case EVP_CIPH_OFB_MODE: ctx->num = 0; /* fall-through */ case EVP_CIPH_CBC_MODE: n = EVP_CIPHER_CTX_get_iv_length(ctx); if (n < 0 || n > (int)sizeof(ctx->iv)) { ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); return 0; } if (iv != NULL) memcpy(ctx->oiv, iv, n); memcpy(ctx->iv, ctx->oiv, n); break; case EVP_CIPH_CTR_MODE: ctx->num = 0; /* Don't reuse IV for CTR mode */ if (iv != NULL) { n = EVP_CIPHER_CTX_get_iv_length(ctx); if (n <= 0 || n > (int)sizeof(ctx->iv)) { ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH); return 0; } memcpy(ctx->iv, iv, n); } break; default: return 0; } } if (key != NULL || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) { if (!ctx->cipher->init(ctx, key, iv, enc)) return 0; } ctx->buf_len = 0; ctx->final_used = 0; ctx->block_mask = ctx->cipher->block_size - 1; return 1; }
10-30
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值