转:http://blog.chinaunix.net/uid-20940095-id-4144300.html

1. openstack 鉴权简单介绍   
    众所周知,openstack通过keystone用来完成authenticate(认证),真正的鉴权(authorize)是在各个模块分别做的,具体实现为每个模块都有一个policy文件,叫policy.json,里面定义了鉴权用的rules。
    以nova为例,policy文件的位置在:/etc/nova/policy.json,下面先来看几条rules,了解其基本含义:

本含义:

"compute:create": "",
"compute:create:attach_network": "",
"compute:create:attach_volume": "",
"compute:create:forced_host": "is_admin:True",
"compute:get_all": "",
"compute:get_all_tenants": "",
"compute:start": "rule:admin_or_owner",
"compute:stop": "rule:admin_or_owner",
"compute:unlock_override": "rule:admin_api",

语法规则为:rule:[result]
rule:指这条规则是干啥的,通常对应一个action,以类似scope:action的形式给出,scope表示作用范围,action表示执行哪种操作
result: 表示这条rule的判定结果或者如何进行判定,比如"compute:create:forced_host":"is_admin:True",如果执行此操作的用户具有admin角色(role),则这条结果的判定结果就是True。
另外,rule是可以嵌套的,比如"compute:stop": "rule:admin_or_owner",表示compute:stop这条规则的结果为admin_or_owner这条规则的结果,而admin_or_owner规则如下:

"admin_or_owner": "is_admin:True or project_id:%(project_id)s",

如果调用这个操作的用户的角色是admin,就返回True,或者返回用户所属的project的id.

2. policy鉴权代码分析
针对每一个操作,都会经过一个叫@wrap_check_policy的decorator,以nova的resize操作为例,在执行真正的resize代码之前,先要经过一个叫@wrap_check_policy的装饰器来完成policy的check过程,具体参见后面的代码check_policy函数:

    @wrap_check_policy
@check_instance_lock
@check_instance_cell
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED],
task_state=[None])
def resize(self, context, instance, flavor_id=None,
**extra_instance_updates):

check_policy(context, action, target, scope='compute')函数有四个参数:
(1) context: 执行resize操作的上下文,其内容包括project_id, user_id, role,auth_token等信息,具体如下:

(2) action:表示当前执行的操作是啥,这里就是resize
(3) target:操作针对的object是啥,这里就是instance id
(4) scope:当前操作的作用域是啥,主要为了与policy文件中定义的作用域匹配,这里为compute,即nova执行的操作

def check_policy(context, action, target, scope='compute'):
_action = '%s:%s' % (scope, action) ##这里拼接成policy.json的rule,即_action=compute:resize
nova.policy.enforce(context, _action, target)
------------------------------------------------------------------------------------------------------------------------
def enforce(context, action, target, do_raise=True):
"""Verifies that the action is valid on the target in this context. :param context: nova context
:param action: string representing the action to be checked
this should be colon separated for clarity.
i.e. ``compute:create_instance``,
``compute:attach_volume``,
``volume:attach_volume``
:param target: dictionary representing the object of the action
for object creation this should be a dictionary representing the
location of the object e.g. ``{'project_id': context.project_id}``
:param do_raise: if True (the default), raises PolicyNotAuthorized;
if False, returns False :raises nova.exception.PolicyNotAuthorized: if verification fails
and do_raise is True. :return: returns a non-False value (not necessarily "True") if
authorized, and the exact value False if not authorized and
do_raise is False.
"""
init() ##policy.json被cache到cache_info数据结构中,init()函数就是去检查policy.json是否已经被加载或修改过,如果cache_info结构为空,说明policy.json还没有加载过,则执行加载;如果policy.json被修改过,也会重新进行加载 credentials = context.to_dict() ##将context转化成dictonary,就是上面context给出的内容,以便后面代码使用 # Add the exception arguments if asked to do a raise
extra = {}
if do_raise:
extra.update(exc=exception.PolicyNotAuthorized, action=action) ##增加no auth hook函数,即如果rule的结果为False,则执行no auth hook函数做一些处理 return policy.check(action, target, credentials, **extra) ##进行policy的check
--------------------------------------------------------------------------------------------------------------------
def init():
global _POLICY_PATH
global _POLICY_CACHE
if not _POLICY_PATH:
_POLICY_PATH = CONF.policy_file
if not os.path.exists(_POLICY_PATH):
_POLICY_PATH = CONF.find_file(_POLICY_PATH)
if not _POLICY_PATH:
raise exception.ConfigNotFound(path=CONF.policy_file)
utils.read_cached_file(_POLICY_PATH, _POLICY_CACHE,
reload_func=_set_rules) ##加载policy.json文件
---------------------------------------------------------------------------------------------------------------------- def read_cached_file(filename, cache_info, reload_func=None):
"""Read from a file if it has been modified. :param cache_info: dictionary to hold opaque cache.
:param reload_func: optional function to be called with data when
file is reloaded due to a modification. :returns: data from file """
mtime = os.path.getmtime(filename) ###获取policy.json文件的modify time,如果与cache_info中的mtime不同,则说明文件被修改过,则执行重新加载
if not cache_info or mtime != cache_info.get('mtime'):
LOG.debug(_("Reloading cached file %s") % filename)
with open(filename) as fap:
cache_info['data'] = fap.read()
cache_info['mtime'] = mtime
if reload_func:
reload_func(cache_info['data'])
return cache_info['data'] ###返回加载后的policy.json文件的内容
---------------------------------------------------------------------------------------------------------------------------
def check(rule, target, creds, exc=None, *args, **kwargs):
"""
Checks authorization of a rule against the target and credentials. :param rule: The rule to evaluate.
:param target: As much information about the object being operated
on as possible, as a dictionary.
:param creds: As much information about the user performing the
action as possible, as a dictionary.
:param exc: Class of the exception to raise if the check fails.
Any remaining arguments passed to check() (both
positional and keyword arguments) will be passed to
the exception class. If exc is not provided, returns
False. :return: Returns False if the policy does not allow the action and
exc is not provided; otherwise, returns a value that
evaluates to True. Note: for rules using the "case"
expression, this True value will be the specified string
from the expression.
""" # Allow the rule to be a Check tree
if isinstance(rule, BaseCheck):
result = rule(target, creds)
elif not _rules:
# No rules to reference means we're going to fail closed
result = False
else:
try:
# Evaluate the rule
result = _rules[rule](target, creds) ##没一条rule执行一个函数,这个对应关系记录在全局变量_rules
except KeyError:
# If the rule doesn't exist, fail closed
result = False # If it is False, raise the exception if requested
if exc and result is False:
raise exc(*args, **kwargs) return result

3. 总结 
    之前一直以为修改了policy.json文件,需要重启service才能重新加载policy.json生效,通过分析代码,证明policy.json是动态更新的。另外,通过分析代码,也搞清楚了如何添加自定义的rule,以便实现更细粒度的rule,稍后会给出一个自己实现的例子。

openstack policy 鉴权过程分析的更多相关文章

  1. 使用ranger对kafka进行鉴权

    使用ranger对kafka进行鉴权测试环境:ranger-kafka-plugin为0.6.3版本,kafka版本为kafka_2.10-0.10.1.1,且kafka broker为一个节点.一. ...

  2. 七牛云 PHP SDK服务器鉴权失败!参数解释

    昨天搞了一下午,用7牛官方的SDK demo 1.上传凭证 $policy = array( 'callbackUrl' => 'http://api.example.com/qiniu/upl ...

  3. 鉴权应用服务器 app客户端 web服务端 安全令牌(SecurityToken)、临时访问密钥(AccessKeyId, AccessKeySecret)

    设置EndPoint和凭证 移动终端是一个不受信任的环境,把AccessKeyId和AccessKeySecret直接保存在终端用来加签请求,存在极高的风险.建议只在测试时使用明文设置模式,业务应用推 ...

  4. .NET Core中的鉴权授权正确方式(.NET5)

    一.简介 前后端分离的站点一般都会用jwt或IdentityServer4之类的生成token的方式进行登录鉴权.这里要说的是小项目没有做前后端分离的时站点登录授权的正确方式. 一.传统的授权方式 这 ...

  5. ApiAuthValue鉴权机制总结

    一.背景介绍 1.自动化的配置工具autoconfig介绍 项目开发过程中,有些配置会随着运行环境的变化而各不相同.如jdbc驱动的配置,在开发环境可能链接到开发本地的数据库,测试环境则有一套测试专用 ...

  6. 搭建一个分布式MongoDB鉴权集群

    今天休假在家,测试并搭建了一个replica set shard MongoDB鉴权集群.replica set shard 鉴权集群中文资料比较少,本文是个人笔记,同时也希望对后来者有所帮助.本文仅 ...

  7. 开放平台鉴权以及OAuth2.0介绍

    OAuth 2.0 协议 OAuth是一个开发标准,允许用户授权第三方网站或应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的内容. OAuth 2.0 ...

  8. 取消mod_sofia的呼叫鉴权

    FreeSWITCH中默认的SIP呼叫是要鉴权的,流程如下. 终端 FreeSWITCH A -----Invite------> FS A <----Trying------ FS A ...

  9. android 高德地图出现【定位失败key鉴权失败】

    如题:android 高德地图出现[定位失败key鉴权失败] 原因:使用的是debug模式下的SHA1,发布的版本正确获取SHA1的方式见: 方法二使用 keytool(jdk自带工具),按照如下步骤 ...

随机推荐

  1. 针对用户在个人中心绑定手机认证的一些js代码。

    需求: 1:手机号码校验(格式的校验,手机号码是否已经绑定过)---未实现 2:填完手机号码,点击发送验证码,手机会收到一条信息 3:发送验证码按钮不可用,变成重新发送的倒计时 1):60秒以后又可以 ...

  2. HDU 1256 画8 模拟题

    解题报告:这题我觉得题目有一个没有交代清楚的地方就是关于横线的字符的宽度的问题,题目并没有说,事实上题目要求的是在保证下面的圈高度不小于上面的圈的高度的情况下,横线的宽度就是等于下面的圈的高度. #i ...

  3. POJ 2230 Watchcow && USACO Watchcow 2005 January Silver (欧拉回路)

    Description Bessie's been appointed the new watch-cow for the farm. Every night, it's her job to wal ...

  4. mysql zip 解压安装

    系统:win10 专业版 mysql 5.7.21 解压安装. 对于Windows,mysql官网推荐使用可执行文件进行安装,这里我还是暂时用noinstall 解压zip文件来安装 zip 文件解压 ...

  5. Python练习-一个简单易懂的迭代器,了解一下

    今天我们学习了迭代器,其实可以理解为是一个元素容器被遍历的方式,不难理解,看看下面的小例子: # 编辑者:闫龙 #一个简单的迭代器 l = [1,2,3,4,5,6,7]#建立一个列表l ite = ...

  6. 查看 CUDA cudnn 版本

    cuda 版本 cat /usr/local/cuda/version.txt cudnn 版本 cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MA ...

  7. jQuery 库的优缺点

    通用性良好,适合大多数常规网站,省去了为浏览器兼容性写封装函数的麻烦(1+版本支持IE6.7.8,2+版本支持包括IE9在内的现代浏览器). 通用性良好意味着特异性不好,所以jQuery并不适合特异性 ...

  8. JS获取元素内容属性以及修改

    1.通过document对象

  9. NB-iot 和 emtc两种技术区别

    此前有报道称,工信部正在拟定推动窄频物联网(NB-IoT)标准化,并对NB-IoT模块外形.封装以及针脚定义等提出新规范.业内人士认为,标准出台后将促进物联网规模化商用全面提速,迎来行业成长爆发期. ...

  10. Splay算法摘要

    先介绍变量定义 int n; struct Node { //Splay节点定义 ],val,num,siz; //fa:它爸爸:son它儿子,左0右1:val:这个节点的值 //num:这个值的数量 ...