Quantum的权限认证(2)

本文地址:http://blog.csdn.net/spch2008/article/details/9698667

当用户在命令行中输入 quantum port-show  时,最终将会转到 quantum\api\v2\base.py的Controller中的show方法。

def show(self, request, id, **kwargs):

    return {self._resource:
            self._view(self._item(request,
                                  id,
                                  do_authz=True,
                                  field_list=field_list,
                                  parent_id=parent_id),
                       fields_to_strip=added_fields)}

	
	
def _item(self, request, id, do_authz=False, field_list=None,
          parent_id=None):
    
    action = self._plugin_handlers[self.SHOW]
   
    obj_getter = getattr(self._plugin, action)
    obj = obj_getter(request.context, id, **kwargs)
   
    if do_authz:
        policy.enforce(request.context, action, obj, plugin=self._plugin)
    return obj
而在show中,会跳转到_item方法中,该方法调用policy.enforce进行权限认证。

quantum\policy.py中

def enforce(context, action, target, plugin=None):
    
    init()
    real_target = _build_target(action, target, plugin, context)
    match_rule = _build_match_rule(action, real_target)
    credentials = context.to_dict()
    
    return policy.check(match_rule, real_target, credentials,
                        exceptions.PolicyNotAuthorized, action=action)

在这里,假设用户输入的是quantum port-show命令,则action为get_port,  context为

上一篇所述的Context对象.而target为一个用户查询的结果,是一个字典,内容格式如下:

def _make_port_dict(self, port, fields=None):
    res = {"id": port["id"],
           'name': port['name'],
           "network_id": port["network_id"],
           'tenant_id': port['tenant_id'],
           "mac_address": port["mac_address"],
           "admin_state_up": port["admin_state_up"],
           "status": port["status"],
           "fixed_ips": [{'subnet_id': ip["subnet_id"],
                          'ip_address': ip["ip_address"]}
                         for ip in port["fixed_ips"]],
           "device_id": port["device_id"],
           "device_owner": port["device_owner"]}
    return self._fields(res, fields)

/etc/quantum/policy.json内容,只列出get_port涉及到的内容。

"admin_or_owner": [["role:admin"], ["tenant_id:%(tenant_id)s"]],
"get_port": [["rule:admin_or_owner"]],

init进行初始化操作,从policy.json文件中读取权限信息,交给_set_rules处理。
def _set_rules(data):
    default_rule = 'default'
    policy.set_rules(policy.Rules.load_json(data, default_rule))
set_rules设置全局变量_rules,变量指向一个Rules对象,存放所有加载的规则。Rules继承于dict,即Rules本身具有字典功能。

内容为:

 { 'get_port' : RuleCheck('rule', 'admin_or_owner'), 'admin_or_owner' : OrCheck([RoleCheck('role', 'admin'),GenericCheck('tenant_id','%(network_tenant_id)s')])}

具体加载过程在下一篇中介绍。

def _build_match_rule(action, target):
   
    match_rule = policy.RuleCheck('rule', action)
	return match_rule
返回一个RuleCheck对象,self.kind = 'rule', self.match = action = 'get_port'。

credentials = context.to_dict()调用to_dict得到一个字典,包含验证所需要的用户信息。

def check(rule, target, creds, exc=None, *args, **kwargs):

    if isinstance(rule, BaseCheck):
        result = rule(target, creds)
		
	return result
验证过程,调用match_rule(RuleCheck对象)的call方法。

@register("rule")
class RuleCheck(Check):
    def __call__(self, target, creds):
        """
        Recursively checks credentials based on the defined rules.
        """

        return _rules[self.match](target, creds)
是一个递归调用的过程,由上可知,self.match值为'get_port',_rules['get_port']值为RuleCheck('rule', 'admin_or_owner'),继续调用

__call__方法。此时self.match值为‘admin_or_owner’,_rules['admin_or_owner']值为OrCheck([RoleCheck('role', 'admin'),GenericCheck('tenant_id','%(network_tenant_id)s')])

调用OrCheck的call方法:

def __call__(self, target, cred):

    for rule in self.rules:
        if rule(target, cred):
            return True

    return False
只要有一个规则符合条件,即返回真。先转向RoleCheck的call方法。
@register("role")
class RoleCheck(Check):
    def __call__(self, target, creds):
        """Check that there is a matching role in the cred dict."""

        return self.match.lower() in [x.lower() for x in creds['roles']]
self.match为admin, 检测creds用户的角色是否有admin,如果有,返回真,否则,验证失败。

如果验证失败,则进行GenericCheck验证。如果二者都验证失败,则说明用户没有进行此操作的权限。


其实思路很简单:对于一个action(get_port)对应一个RuleCheck对象,由该对象转向相应规则。

RuleCheck('rule', 'get_port')  在第一个递归调用时候,找到_rules = {'get_port': RuleCheck('rule', 'admin_or_owner'},这样,get_port找到对应的RuleCheck。

再进行一次递归调用,转向OrCheck('[RoleCheck('role', 'admin'),GenericCheck('tenant_id','%(network_tenant_id)s')]))



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值