发送带有多个值的 XACML 请求以由策略评估

Posted

技术标签:

【中文标题】发送带有多个值的 XACML 请求以由策略评估【英文标题】:Sending XACML request with multiple values in bag to be evaluated by policy 【发布时间】:2019-07-04 10:53:46 【问题描述】:

以下是针对中国墙的 XACML 策略,它使用stringAtLeastOneMemberOf 比较两个属性,看看它们是否包含相同的值列表。

即如果请求访问对象的主体具有标签[1, 4, 5],而对象具有标签[2, 3, 5],则访问将被拒绝,因为两者都包含5

中国墙政策

ALFA 代码

attribute subjectConflicts 
    id = "urn:oasis:names:tc:xacml:1.0:subject:subject-conflicts"
    type = string
    category = subjectCat

attribute resourceConflicts 
    id = "urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts"
    type = string
    category = resourceCat




namespace models 
    import Attributes.*

    /*
     * 
     * This policy implements the Chinese Wall model.
     * 
     */
    policy ChineseWall 
        target clause resourceType=="calcert"
        apply firstApplicable

        /*
         * Check subject is not in conflict with object OEMs and calibrators
         * 
         * This rule will deny access is user.label contains at least 1 value that is also present
         * in object.label
         */
        rule noconflict 
            target clause actionId=="read" or actionId=="write"
            condition stringAtLeastOneMemberOf(subjectConflicts, resourceConflicts)
            deny
        
    

XACML 政策

<?xml version="1.0" encoding="UTF-8"?>
<!--This file was generated by the ALFA Plugin for Eclipse from Axiomatics AB (http://www.axiomatics.com).-->
<!--Any modification to this file will be lost upon recompilation of the source ALFA file-->
<xacml3:Policy xmlns:xacml3="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="http://axiomatics.com/alfa/identifier/models.ChineseWall" RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable" Version="1.0">
    <xacml3:Description>This policy implements the Chinese Wall model.</xacml3:Description>
    <xacml3:PolicyDefaults>
        <xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116</xacml3:XPathVersion>
    </xacml3:PolicyDefaults>
    <xacml3:Target>
        <xacml3:AnyOf>
            <xacml3:AllOf>
                <xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                    <xacml3:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">calcert</xacml3:AttributeValue>
                    <xacml3:AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-type" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false" />
                </xacml3:Match>
            </xacml3:AllOf>
        </xacml3:AnyOf>
    </xacml3:Target>
    <xacml3:Rule Effect="Deny" RuleId="models.ChineseWall.noconflict">
        <xacml3:Description>Check subject is not in conflict with object OEMs and calibrators

This rule will deny access is user.label contains at least 1 value that is also present
in object.label</xacml3:Description>
        <xacml3:Target>
            <xacml3:AnyOf>
                <xacml3:AllOf>
                    <xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <xacml3:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">read</xacml3:AttributeValue>
                        <xacml3:AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false" />
                    </xacml3:Match>
                </xacml3:AllOf>
                <xacml3:AllOf>
                    <xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <xacml3:AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">write</xacml3:AttributeValue>
                        <xacml3:AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false" />
                    </xacml3:Match>
                </xacml3:AllOf>
            </xacml3:AnyOf>
        </xacml3:Target>
        <xacml3:Condition>
            <xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of">
                <xacml3:AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-conflicts" Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false" />
                <xacml3:AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false" />
            </xacml3:Apply>
        </xacml3:Condition>
    </xacml3:Rule>
</xacml3:Policy>

政策执行点 (PEP) 代码

我正在使用Authzforce Core PDP for Java 来模拟 PDP,并按如下方式评估请求:

private DecisionRequest parseJSONAndBuildXACML(JSONObject obj) 
    DecisionRequestBuilder builder = server.pdpEngine.getEngine().newRequestBuilder(-1, -1);

    /** Add Principle **/
    // Principle ID
    AttributeFqn principleID = AttributeFqns.newInstance(XACML_1_0_ACCESS_SUBJECT.value(), Optional.empty(), XacmlAttributeId.XACML_1_0_SUBJECT_ID.value());
    AttributeBag<?> principleIDValue = Bags.singletonAttributeBag(StandardDatatypes.STRING, new StringValue("Principle" + obj.getJSONObject("principle").getString("id")));
    builder.putNamedAttributeIfAbsent(principleID, principleIDValue);

    // Principle Label
    AttributeFqn principleLabel = AttributeFqns.newInstance(XACML_1_0_ACCESS_SUBJECT.value(), Optional.<String>empty(), XACML_1_0_SUBJECT_LABEL);
    AttributeBag<?> principleLabelValue = Bags.singletonAttributeBag(StandardDatatypes.INTEGER, new IntegerValue(new MediumInteger(obj.getJSONObject("principle").getInt("label"))));
    builder.putNamedAttributeIfAbsent(principleLabel, principleLabelValue);

    // Principle Conflict Set
    AttributeFqn principleConflicts = AttributeFqns.newInstance(XACML_1_0_ACCESS_SUBJECT.value(), Optional.empty(), XACML_1_0_SUBJECT_CONFLICTS);
    Collection<StringValue> pconflicts = getStringListFromJsonArray(obj.getJSONObject("principle").getJSONArray("conflicts"));
    AttributeBag<?> principleConflictsValue = Bags.newAttributeBag(StandardDatatypes.STRING, pconflicts);
    //AttributeBag<?> principleConflictsValue = Bags.singletonAttributeBag(StandardDatatypes.STRING, new StringValue(obj.getJSONObject("principle").getString("conflicts")));
    builder.putNamedAttributeIfAbsent(principleConflicts, principleConflictsValue);

    // Object ID
    AttributeFqn objectID = AttributeFqns.newInstance(XACML_3_0_RESOURCE.value(), Optional.empty(), XACML_1_0_RESOURCE_ID.value());
    AttributeBag<?> objectIDValue = Bags.singletonAttributeBag(StandardDatatypes.STRING, new StringValue(obj.getJSONObject("object").getString("id")));
    builder.putNamedAttributeIfAbsent(objectID, objectIDValue);

    // Object Type
    AttributeFqn objectType = AttributeFqns.newInstance(XACML_3_0_RESOURCE.value(), Optional.empty(), XACML_1_0_RESOURCE_TYPE);
    AttributeBag<?> objectTypeValue = Bags.singletonAttributeBag(StandardDatatypes.STRING, new StringValue(obj.getJSONObject("object").getString("type")));
    builder.putNamedAttributeIfAbsent(objectType, objectTypeValue);

    // Object Label
    AttributeFqn objectLabel = AttributeFqns.newInstance(XACML_3_0_RESOURCE.value(), Optional.<String>empty(), XACML_1_0_RESOURCE_LABEL);
    AttributeBag<?> objectLabelValue = Bags.singletonAttributeBag(StandardDatatypes.INTEGER, new IntegerValue(new MediumInteger(obj.getJSONObject("object").getInt("label"))));
    builder.putNamedAttributeIfAbsent(objectLabel, objectLabelValue);

    // Object Conflict Set
    AttributeFqn objectConflicts = AttributeFqns.newInstance(XACML_3_0_RESOURCE.value(), Optional.empty(), XACML_1_0_RESOURCE_CONFLICTS);
    Collection<StringValue> oconflicts = getStringListFromJsonArray(obj.getJSONObject("object").getJSONArray("conflicts"));
    AttributeBag<?> objectConflictsValue = Bags.newAttributeBag(StandardDatatypes.STRING, oconflicts);
    //AttributeBag<?> objectConflictsValue = Bags.singletonAttributeBag(StandardDatatypes.STRING, new StringValue(obj.getJSONObject("object").getString("conflicts")));
    builder.putNamedAttributeIfAbsent(objectConflicts, objectConflictsValue);

    // Action
    AttributeFqn action = AttributeFqns.newInstance(XACML_3_0_ACTION.value(), Optional.empty(), XacmlAttributeId.XACML_1_0_ACTION_ID.value());
    AttributeBag<?> actionValue = Bags.singletonAttributeBag(StandardDatatypes.STRING, new StringValue(obj.getString("action")));
    builder.putNamedAttributeIfAbsent(action, actionValue);

    return builder.build(false);

在这种情况下,JSONObject 就是我将请求从客户端发送到 PDP 引擎的方式。其他策略有效,这里的问题是我正在向包发送一个字符串,即"[2, 4, 5]",但它总是导致NotApplicable。是否有我应该在这里使用的列表类型来符合政策?

这是我发送的 JSON:


    "principle": 
        "conflicts": [
            "1",
            "2",
            "10"
        ],
        "id": "Principle 1",
        "label": 3
    ,
    "action": "read",
    "object": 
        "conflicts": [
            "4",
            "5",
            "9"
        ],
        "id": "Object 1",
        "label": 2,
        "type": "calcert"
    

挑战

更准确地说,冲突集的 Authzforce 的 Java 代码中的 JSON 输出将是一个字符串,即"[2,3,5]",而我认为这需要是另一种格式(因为它总是导致 NotApplicable),但这是我的问题。

【问题讨论】:

你能告诉我们ALFA的来源吗? @DavidBrossard 我已经更新了 OP 以包含 ALFA! 【参考方案1】:

您需要在代码中修复至少 2 个问题:

    由于您想要一个字符串列表中的包,可能不止一个,您必须使用更通用的 Bags.newAttributeBag(...) - 第二个参数必须是您的实际字符串列表 - 而不是强>Bags.singletonAttributeBag()。只有这样,PDP 才会将其视为多个 String 类型的 AttributeValue。

    您使用了相同的主题属性XACML_1_0_SUBJECT_CONFLICTS 两次,第二次是 objectConflicts 属性,所以我猜这是错误的,需要修复,因为这必须是资源改为属性urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts

【讨论】:

我正在使用AttributeBag&lt;?&gt; principleConflictsValue = Bags.newAttributeBag(StandardDatatypes.STRING, conflicts);,其中conflicts 是来自JSON 的Collection&lt;String&gt;,其中JSON 是["1", "2", "3"],这仍然会导致拒绝。我是否正确使用了属性包?还是来自 JSON 的输入有问题? 对于第一个问题,您必须对所有多值属性使用Bags.newAttributeBag(...),即principalConflictsValue 和objectConflictsValue(可能你错过了第二个)。 第二个问题怎么样,你解决了吗?我认为你的问题没有解决。请相应地编辑您的问题或将我们指向完整的最新代码(例如在 github 上),以便我们可以跟踪您的更改/修复,否则很难检查和/或重现。 好的。您现在使用固定代码做出的决定是什么? Deny 或 NotApplicable? 您仍然在 OP 中说 Deny,但在您对 David Brossard 的回答中说 NotApplicable。只想确认一下。并且要小心 'first-applicable' 算法;在您的策略中,您仅将一个规则与拒绝效果结合在一起,因此您将获得拒绝(如果规则评估为拒绝)或 NotApplicable(默认情况下)作为最终结果,仅此而已(或在错误的情况下不确定,但这是边缘情况)。更多信息见 XACML 规范附录 C.8。 抱歉给您带来了困惑,我目前正在获取 NotApplicable。 在这种情况下,很抱歉... 它按预期工作!。实际上,对于这样的请求和策略,策略的目标是 Matchcalcert 资源类型),但是:规则的目标是 Matchread 操作)并且 Condition 为 False(subject-conflictsresource-conflicts 没有共同的字符串),因此规则不适用(参见 XACML §7.11),因此 first-applicable 算法导致 NotApplicable(参见 XACML §C. 8)。如果你期待别的东西,你应该改变组合算法(例如permit-unless-deny,如果你想要 Permit 代替)。【参考方案2】:

首先,您必须了解 XACML 中的所有属性默认情况下都是值包。因此,urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts 是一个可以包含 0(零)、1 或更多值的包。但它仍然是一个包。 ALFA / XACML 中的任何属性都是如此。这意味着当你写:

target clause resourceType=="calcert"

您实际上是在说 如果至少有一个值 resourceType 等于 calcert...

在您的情况下,您正在使用一个名为stringAtLeastOneMemberOf 的函数。此函数接收两个字符串类型的包,如果第一个包包含第二个包中存在的至少一个值,则返回 true。它类似于stringIsIn,只是后者接受一个原子字符串和一个字符串包。您必须写 stringIsIn(stringOneAndOnly(a), b) 才能使其正常工作。属性 a 也必须是一个包含单个值的包。

在您的情况下,您有 2 个可以多值的属性(subjectConflictsresourceConflicts)。这意味着如果你“打印”它们,你会看到类似 ["a", "b", "c", "a"] 的东西。这是一袋价值观。顺便说一下,包可以包含重复项。并且顺序无关紧要(属性的顺序或属性值的顺序)。

现在,您要做的是发送一个表示此内容的 XACML JSON 请求。生成的 JSON 应如下所示:

示例 JSON 请求

在这个例子中,两个属性都是多值的:


   "Request":
      "Resource":[
         
            "Attribute":[
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:resource:resource-type",
                  "Value":"calcert"
               ,
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts",
                  "Value":[
                     "4",
                     "5",
                     "6"
                  ]
               
            ]
         
      ],
      "Action":[
         
            "Attribute":[
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:action:action-id",
                  "Value":"read"
               
            ]
         
      ],
      "AccessSubject":[
         
            "Attribute":[
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:subject:subject-conflicts",
                  "Value":[
                     "1",
                     "2",
                     "3"
                  ]
               
            ]
         
      ]
   

请求也可以写成


   "Request":
      "Resource":[
         
            "Attribute":[
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:resource:resource-type",
                  "Value":"calcert"
               ,
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts",
                  "Value":"4"
               ,
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts",
                  "Value":"5"
               ,
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts",
                  "Value":"6"
               
            ]
         
      ],
      "Action":[
         
            "Attribute":[
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:action:action-id",
                  "Value":"read"
               
            ]
         
      ],
      "AccessSubject":[
         
            "Attribute":[
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:subject:subject-conflicts",
                  "Value":"1"
               ,
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:subject:subject-conflicts",
                  "Value":"2"
               ,
               
                  "AttributeId":"urn:oasis:names:tc:xacml:1.0:subject:subject-conflicts",
                  "Value":"3"
               
            ]
         
      ]
   

XACML JSON 响应示例


   "Response":[
      
         "Decision":"NotApplicable"
      
   ]

为请求/响应找到合适的 SDK

在您的代码中,您使用 AuthZForce 的 PEP SDK。 Cyril 在他的另一个回答中指出了主要错误:

        AttributeBag<?> objectConflictsValue = Bags.singletonAttributeBag(StandardDatatypes.STRING, new StringValue(obj.getJSONObject("object").getString("conflicts")));

问题是您要在 XACML 包内的单个值中添加冲突 ["1",...] 的整个字符串表示形式,而不是单独添加每个部分。

在我的示例中,我使用了自己的Java JSON PEP SDK。代码如下所示:

将每个值逐一相加:

resource.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts", "4"));
resource.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts", "5"));
resource.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts", "6"));

或添加为值数组:

resource.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts", new String[]"4","5","6"));

完整代码

package io.xacml.pep.json.so;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.xacml.json.model.Attribute;
import io.xacml.json.model.Category;
import io.xacml.json.model.Request;
import io.xacml.json.model.Response;
import io.xacml.json.model.Result;
import io.xacml.pep.json.client.AuthZClient;
import io.xacml.pep.json.client.ClientConfiguration;
import io.xacml.pep.json.client.DefaultClientConfiguration;
import io.xacml.pep.json.client.jaxrs.JaxRsAuthZClient;
import lombok.extern.slf4j.Slf4j;

/**
 * This class contains sample code using JAX-RS to invoke a Policy Decision Point.
 * It supports both the JSON Profile of XACML 1.0 (where the response could be either an Object or
 * an Array) and the JSON Profile of XACML 1.1 (where the response is always an array - to simplify
 * things)
 *
 * @author djob
 */
@Slf4j
public class Example 

    public static void main(String[] args) 

        ObjectMapper mapper = new ObjectMapper();
        ClientConfiguration clientConfiguration = DefaultClientConfiguration.builder()
                .pdpUrl("http://djob-hp:8080")
                .username("ads-user")
                .password("secret")
                .build();

        // Add user attributes
        Category subject = new Category();
        subject.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:subject:subject-conflicts", "1"));
        subject.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:subject:subject-conflicts", "2"));
        subject.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:subject:subject-conflicts", "3"));

        // Add action attributes - if any
        Category action = new Category();
        action.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:action:action-id", "read"));

        // Add user attributes
        Category resource = new Category();
        resource.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:resource:resource-type", "calcert"));
        resource.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts", "4"));
        resource.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts", "5"));
        resource.addAttribute(new Attribute("urn:oasis:names:tc:xacml:1.0:resource:resource-conflicts", "6"));

        Request authZRequest = new Request();
        authZRequest.addAccessSubjectCategory(subject);
        authZRequest.addActionCategory(action);
        authZRequest.addResourceCategory(resource);

        AuthZClient authZClient = new JaxRsAuthZClient(clientConfiguration, mapper);
        Response authZResponse = authZClient.makeAuthorizationRequest(authZRequest);

        for (Result r : authZResponse.getResults()) 
            log.debug(r.getDecision().name());
        
    

【讨论】:

感谢您的详细解答!但是,使用我拥有的代码(因此无需进行重大更改),如何使用包将冲突列表添加为属性?如果您看到我对 Cyrils 回答的评论,我会在将列表添加到包时检索值,如下所示:Bag(elementType='http://www.w3.org/2001/XMLSchema#string', elements=[1, 2, 10], causeForEmpty=null)。但我仍然收到DENY/NOT_APPLICABLE 你是被拒绝还是不适用? 不适用。

以上是关于发送带有多个值的 XACML 请求以由策略评估的主要内容,如果未能解决你的问题,请参考以下文章

XACML Authzforce PDP 自定义策略

XACML 政策和要求

即使策略规则中缺少该属性,具有附加属性的 XACML 3.0 请求也匹配

XACML 政策。应用函数字符串子集给出意外结果

XACML简介

XACML简介