Search code examples
authorizationsubsetxacmlabacbalana

XACML policy. Apply function string-subset giving unexpected result


I'm using balana downloaded from git. I'm working on a policy rule which should only Permit if the policy's string-bag is a subset of the matching attributes in the request. Eg. Request contains attributes "letter=a, letter=b", and policy uses a string-subset to compare the set of letter attributes from the request to the string-bag. I've tried both orders of subset (subset letter stringbag vs subset stringbag letter) but they both come back with "Permit" when my test-request should be getting "Deny".

Sample policy

<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="policy1"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-overrides" Version="1.0">
    <Target>
        <AnyOf>
            <AllOf>
                <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                    <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                        myguid0123456789
                    </AttributeValue>
                    <AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
                </Match>
            </AllOf>
        </AnyOf>
    </Target>
    <Rule Effect="Deny" RuleId="securityLevel">
        <Condition>
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-greater-than">
                <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
                    <AttributeDesignator AttributeId="securityLevel" Category="tags" DataType="http://www.w3.org/2001/XMLSchema#integer" MustBePresent="true" />
                </Apply>
                <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">
                    9000
                </AttributeValue>
            </Apply>
        </Condition>
        <AdviceExpressions>
            <AdviceExpression AdviceId="channel-security-too-low" AppliesTo="Deny">
                <AttributeAssignmentExpression AttributeId="urn:oasis:names:tc:xacml:2.0:example:attribute:text">
                    <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                        Message security is over 9000! It's not good cap'n, I cannae make it go any faster!
                    </AttributeValue>
                </AttributeAssignmentExpression>
            </AdviceExpression>
        </AdviceExpressions>
    </Rule>
    <Rule Effect="Permit" RuleId="caveats">
        <Condition>
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-subset">
                <AttributeDesignator AttributeId="caveats" Category="tags" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
                <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag">
                    <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                        A
                    </AttributeValue>
                    <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                        B
                    </AttributeValue>
                    <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                        C
                    </AttributeValue>
                </Apply>
            </Apply>
        </Condition>
        <AdviceExpressions>
            <AdviceExpression AdviceId="data-caveat-not-on-channel" AppliesTo="Deny">
                <AttributeAssignmentExpression AttributeId="urn:oasis:names:tc:xacml:2.0:example:attribute:text">
                    <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                        caveat advice fail
                    </AttributeValue>
                </AttributeAssignmentExpression>
            </AdviceExpression>
        </AdviceExpressions>
    </Rule>
    <Rule RuleId="permit-rule" Effect="Permit" />
</Policy>

And I'm passing this request for testing:

Request

<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="true">
    <Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action">
        <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" IncludeInResult="true">
            <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                send
            </AttributeValue>
        </Attribute>
    </Attributes>
    <Attributes Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject">
        <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id" IncludeInResult="true">
            <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                99991699
            </AttributeValue>
        </Attribute>
    </Attributes>
    <Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource">
        <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" IncludeInResult="true">
            <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                myguid0123456789
            </AttributeValue>
        </Attribute>
    </Attributes>
    <Attributes Category="tags">
        <Attribute AttributeId="securityLevel" IncludeInResult="true">
            <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">
                8000
            </AttributeValue>
        </Attribute>
        <Attribute AttributeId="caveats" IncludeInResult="true">
            <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                A
            </AttributeValue>
        </Attribute>
        <Attribute AttributeId="caveats" IncludeInResult="true">
            <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
                B
            </AttributeValue>
        </Attribute>
    </Attributes>
</Request>

So, my thinking (because I'm not sure of any way to tell it negation) is that

  • it implicitly associates a negative match on the condition to the negation of the effect.

If that's true, my intuition is that a matching subset that's OK should say "Permit" but then if it fails to match the condition, it would instead say "Deny".

Since there's no target statement, my intuition is that it "should" try to evaluate that condition on all requests, so not matching the condition shouldn't cause the rule to skip being evaluated.

In any case, looking at the sample, I want it to say "my policy takes A,B, but you have A,B,C, so I have to deny you." Unfortunately that's not what it's doing, and I'm not sure why. Please help. x_x


Solution

  • You have several issues in your policy and request.

    First of all, in XML and XACML <element>value</element> is not the same as

    <element>
        value
    </element>
    

    If you are sending your requests as such and your policies are stored as such then the values you are checking are ' A ', ' B ' and so on. This is going to be an issue.

    Secondly you use a deny-overrides combining algorithm with your policy P. P contains 3 rules R1, R2, and R3. R1 is a deny rule. If it applies, then deny is returned and R2 and R3 will not be considered. If R1 does not apply, then the PDP moves on to R2 and R3. If R2 applies then the possible decision is Permit BUT the PDP still needs to check R3 in case it returns a Deny.

    You will get a Deny if securityLevel > 9000.

    You will get a Permit if securityLevel <= 9000 and caveats contains at most A, B, C.

    Finally R3 always grants you access. So no matter what you do in the second rule, the third one will grant you access. In other words R2 doesn't serve any purpose at all.

    I tested your policy in the Axiomatics Policy Server and I could see that behavior in the simulator. You should get the same with Balana.

    Also you should check for securityLevel in the target, not in the condition that's overkill.

    it implicitly associates a negative match on the condition to the negation of the effect.

    There is nothing implicit in XACML. The opposite of Permit is NotApplicable.

    Since there's no target statement, my intuition is that it "should" try to evaluate that condition on all requests, so not matching the condition shouldn't cause the rule to skip being evaluated.

    If there is no target in a rule, then it goes straight to the condition which it considers. It does not skip the rule. But in your case it returns NotApplicable.

    If you want to achieve what you are looking for, use combining algorithm first-applicable and change R3 from Permit to Deny.

    Have a look at this XACML blog for more information.