Guide to write XACML policies in WSO2 Identity Server 2.0 - Part - I

This blog post explains how to write policies in XACML for WSO2 Identity Server.

A given policy has an identifier, a rule combining algorithm, a description, a target and a set of rules.

<Policy PolicyId="urn:sample:xacml:2.0:samplepolicy"
  RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
  xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os">

  <Description>Sample XACML Authorization Policy.</Description>

  <Target>...</Target>

  <Rule>...</Rule>

</Policy>
Since, a given Policy may contain multiple Rules, each of which may evaluate to different access control decisions, XACML needs some way of reconciling the decisions each makes.

This is done through a collection of Combining Algorithms.

Each algorithm represents a different way of combining multiple descisions evaluated through different rules into a single descision.

Following rule combining algorithms are defined in XACML 2.0.

urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:deny-overrides
urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:permit-overrides
urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable
urn:oasis:names:tc:xacml:1.1:rule-combining-algorithm:ordered-denyoverrides
urn:oasis:names:tc:xacml:1.1:rule-combining-algorithm:ordered-permitoverrides
when we have urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable as the rule combining alogorithm, it will pick the first rule applicable from the defined set of Rules.

Once a XACML request being received at the PDP it needs to find a policy that applies to the corresponding request.

To do this, XACML uses the element Target.

A Target is basically a set of simplified conditions for the Subject, Resource and Action that must be met for a Policy or Rule to apply to a given request.

Once a Target is defined directly under Policy element - it defines the set of conditions that must be met to pick that Policy.

<Policy PolicyId="urn:sample:xacml:2.0:samplepolicy"
  RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
  xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os">

  <Description>Sample XACML Authorization Policy.</Description>

  <Target>

    <Subjects>...</Subjects>
    <Resources>...</Resources>
    <Actions>...</Actions>

  </Target>

  <Rule>...</Rule>

</Policy>
To make this very clear - let's go through an example.

This policy will be picked for a request having, any Subject, any Action on Resource http://localhost:8280/services/echo/.

<Policy PolicyId="urn:sample:xacml:2.0:samplepolicy"
  RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
  xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os">

  <Description>Sample XACML Authorization Policy.</Description>

  <Target>

    <Subjects> <AnySubject/> </Subjects>

    <Resources>
      <Resource>
        <ResourceMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-regexp-match">
        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">http://localhost:8280/services/echo/</AttributeValue>
        <ResourceAttributeDesignator
          AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"
          DataType="http://www.w3.org/2001/XMLSchema#string"/>
        </ResourceMatch>
      </Resource>
    </Resources>

    <Actions> <AnyAction/> </Actions>

  </Target>

  <Rule>...</Rule>

</Policy>
For the time being, let's not worry too much about <Resources/> element.

Let's see another example. Here the Target is applied to the Rule - not to the entire Policy it self.

<Policy PolicyId="urn:sample:xacml:2.0:samplepolicy"
  RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
  xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os">

  <Description>Sample XACML Authorization Policy.</Description>

  <Rule Effect="Permit" RuleId="primary-access-rule">

    <Target>

      <Subjects> <AnySubject/> </Subjects>

      <Resources>
        <Resource>
          <ResourceMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-regexp-match">
          <AttributeValue
            DataType="http://www.w3.org/2001/XMLSchema#string">http://localhost:8280/services/echo/</AttributeValue>
          <ResourceAttributeDesignator
            AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"
            DataType="http://www.w3.org/2001/XMLSchema#string"/>
          </ResourceMatch>
        </Resource>
      </Resources>

      <Actions> <AnyAction/> </Actions>

    </Target>

  </Rule>

</Policy>
I guess, that explains enough about <Policy/> and <Target/> elements.

Let's move to the <Rule/> element. You may recall, that I mentioned there can be multiple Rule elements per given Policy.

Also - we discussed about Rule Combining Algorithms.

Let's focus on the child elements of the Rule element.

The way the Sun XACML engine determines whether a rule is applicable to an incoming request is by evaluating the Target and optional Condition (if it exists).

These are ANDed together, and the rule's effect achieved if the ANDed value is TRUE.

You know where Rule element fits in to a XACML policy - for the purpose of explaining, I'll just take out the isolated Rule element only - so keep in mind this is always within <Policy> tags.

<Rule Effect="Permit" RuleId="primary-access-rule">

  <Target>...</Target>
  <Condition>...</Condition>

</Rule>
A policy contains one or more Rules.

Each rule has a RuleId and an Effect.

An Effect is the intended consequence of a satisfied rule, which can be either "Deny" or "Permit." This means that if the rule is deemed applicable to an incoming service request, and the rule's conditions evaluate to TRUE, then the specified effect should be enforced.

Since we already discussed about the <Target/> element under the context of <Rule/>, we'll skip it here.

Let's focus on the <Condition/> element.

A Condition is a predicate that must be satisfied for a rule to be assigned its effect.

Okay - a Target defines a set of constraints for a Rule. So - what does a Condition do? Let's differentiate Condition from Target.

While Targets are appealing, frame-like expressions, they have a constrained logic which isn't always expressive enough to narrow down whether a policy is applicable to a service request.

Hence, the need for Condition element arises. If either the policy Target or the Rule Target is not able to adequately express a constraint, a Condition can be added to a Rule.

A Condition can only present within a Rule.

If a Condition is intended to be applicable to the entire Policy, the Condition must be repeated in every Rule in that Policy.

Let's go ahead with an example.

We want to restrict users based on their attributes.

Say - for example a given user has an accessList attribute - and we want to restrict access to a given resource based on the accessList.

I'll take an isolated <Condition/> element here...

<Condition>
  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of">
    <SubjectAttributeDesignator AttributeId="accessList" DataType="http://www.w3.org/2001/XMLSchema#string"/>
    <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag">
      <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">nurses</AttributeValue>
      <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">doctors</AttributeValue>
    </Apply>
  </Apply>
</Condition>
Let's start from the inner most <Apply/> element.

It uses the string-bag function on two attributes.

This bag function wraps a set of possible values for the attribute defined under <SubjectAttributeDesignator/> element. In this case - possible values for the attribute 'accessList' should be either 'nurses' or 'doctors'.

Now, let's look at the outer most <Apply/> element. It uses string-at-least-one-member-of function which will be applied on the results of the inner function.

In other words - final condition says - if you want to access the resource you have to be a member of 'doctors' or 'nurses'.

This will basically conclude the part-1 of this series of blog posts.

In the next blog post I would like to write about Attributes and Attribute Designators.