This tutorial describes the administration of level 3 advanced authorization rules into Authzforce, either directly, or with the help of the Keyrock GUI. The simple verb-resource based permissions are amended to use XACML and new XACML permissions added to the existing roles. The updated ruleset is automatically uploaded to Authzforce PDP, so that policy execution points such as the PEP proxy are able to apply the latest ruleset.
The tutorial demonstrates examples of interactions using the Keyrock GUI, as well cUrl commands used to access the REST APIs of Keyrock and Authzforce - Postman documentation is also available.
- このチュートリアルは日本語でもご覧いただけます。
Details
12.3 Central Terminal Area
- Red or Yellow Zone
- No private vehicle shall stop, wait, or park in the red or yellow zone.
- White Zone
- No vehicle shall stop, wait, or park in the white zone unless actively engaged in the immediate loading or unloading of passengers and/or baggage.
— Los Angeles International Airport Rules and Regulations, Section 12 - Landside Motor Vehicle Operations
Business rules change over time, and it is necessary to be able to amend access controls accordingly. The
previous tutorial included a static XACML <PolicySet>
loaded
into Authzforce. This component offers advanced authorization (level 3) access control where every policy decision
is calculated on the fly and new rules can be applied under new circumstances. The details of the
Authzforce Policy Decision Point (PDP) were discussed in the
previous tutorial, suffice to say, the Authzforce PDP
interprets rules according to the XACML standard
and offers a means to adjudicate on any access request provided that sufficient information can be supplied.
For full flexibility, it must be possible to load, update and activate a new access control XACML <PolicySet>
whenever
necessary. In order to do, this Authzforce offers a simple REST Policy Administration Point (PAP), an alternative
role-based PAP is available within Keyrock
eXtensible Access Control Markup Language (XACML) is a vendor neutral declarative access control policy language. It was created to promote common access control terminology and interoperability. The architectural naming conventions for elements such as Policy Execution Point (PEP) and Policy Decision Point (PDP) come from the XACML specifications.
XACML policies are split into a hierarchy of three levels - <PolicySet>
, <Policy>
and <Rule>
, the <PolicySet>
is
a collection of <Policy>
elements each of which contain one or more <Rule>
elements.
Each <Rule>
within a <Policy>
is evaluated as to whether it should grant access to a resource - the overall
<Policy>
result is defined by the overall result of all <Rule>
elements processed in turn. Separate <Policy>
results are then evaluated against each other using combining algorithms define which <Policy>
wins in case of
conflict.
Further information can be found within the XACML standard and additional resources can be found on the web.
For the first half of the tutorial, a simple two rule <PolicySet>
will be administered using the Authzforce PAP.
Thereafter the Keyrock GUI will be used to administer XACML rules within the existing tutorial application on an
individual XACML <Rule>
level. The policy decision request code within the PEP-Proxy may also need to be
customized to enable the enforcement of complex XACML rules.
Within the Authzforce PAP all CRUD actions occur on the <PolicySet>
level. It is therefore necessary to create a
complete, valid XACML file before uploading it to the service. There is no GUI available to ensure the validity of the
<PolicySet>
prior to uploading the XACML.
Keyrock can create a valid XACML file based on available roles and permissions and pass this to Authzforce. Indeed Keyrock already does this whenever it combines with Authzforce as all its own basic authorization (level 2) permissions must be translated into advanced authorization (level 3) permissions before they can be adjudicated by Authzforce.
Within Keyrock, each role corresponds to an XACML <Policy>
, each permission within that role corresponds to an
XACML <Rule>
. There is a GUI available for uploading and amending the XACML for each <Rule>
and all CRUD actions
occur on the <Rule>
level.
Provided care is taken when creating <Rule>
you can use Keyrock to simplify the administration of XACML and create
a valid <PolicySet>
for Authzforce.
When using advanced authorization (level 3), a policy execution point sends an authorization request to the relevant domain endpoint within Authzforce, providing all of the information necessary for Authzforce to provide a judgement. Details of the interaction can be found in the previous tutorial.
The full code to supply each request to Authzforce can be found within the tutorials' Git Repository
Obviously the definition of "all of the information necessary" may change over time, applications must therefore be flexible enough to be able to modify the requests sent to ensure that sufficient information is passed.
To keep things simple all components will be run using Docker. Docker is a container technology which allows to different components isolated into their respective environments.
- To install Docker on Windows follow the instructions here
- To install Docker on Mac follow the instructions here
- To install Docker on Linux follow the instructions here
Docker Compose is a tool for defining and running multi-container Docker applications. A YAML file is used configure the required services for the application. This means all container services can be brought up in a single command. Docker Compose is installed by default as part of Docker for Windows and Docker for Mac, however Linux users will need to follow the instructions found here
We will start up our services using a simple bash script. Windows users should download cygwin to provide a command-line functionality similar to a Linux distribution on Windows.
This application demonstrates the administration of level 3 Advanced Authorization security into the existing Stock Management and Sensors-based application created in previous tutorials and secures access to the context broker behind a PEP Proxy. It will make use of five FIWARE components - the Orion Context Broker, the IoT Agent for UltraLight 2.0, the Keyrock Identity Manager, the Wilma PEP Proxy and the Authzforce XACML Server. All access control decisions will be delegated to Authzforce which will read the ruleset from a previously uploaded policy domain.
Both the Orion Context Broker and the IoT Agent rely on open source MongoDB technology to keep persistence of the information they hold. We will also be using the dummy IoT devices created in the previous tutorial. Keyrock uses its own MySQL database.
Therefore the overall architecture will consist of the following elements:
- The FIWARE Orion Context Broker which will receive requests using NGSI-v2
- The FIWARE IoT Agent for UltraLight 2.0 which will receive southbound requests using NGSI-v2 and convert them to UltraLight 2.0 commands for the devices
- FIWARE Keyrock offer a complement Identity Management System
including:
- An OAuth2 authentication system for Applications and Users
- A site graphical frontend for Identity Management Administration
- An equivalent REST API for Identity Management via HTTP requests
- FIWARE Authzforce is a XACML Server providing an interpretive Policy Decision Point (PDP) protecting access to resources such as Orion and the tutorial application.
- FIWARE Wilma is a PEP Proxy securing access to the Orion microservices, it delegates the passing of authorization decisions to Authzforce PDP
- The underlying MongoDB database :
- Used by the Orion Context Broker to hold context data information such as data entities, subscriptions and registrations
- Used by the IoT Agent to hold device information such as device URLs and Keys
- A MySQL database :
- Used to persist user identities, applications, roles and permissions
- The Stock Management Frontend does the following:
- Displays store information
- Shows which products can be bought at each store
- Allows users to "buy" products and reduce the stock count.
- Allows authorized users into restricted areas, it also delegates authorization decisions to the Authzforce PDP
- A webserver acting as set of dummy IoT devices using the UltraLight 2.0 protocol running over HTTP - access to certain resources is restricted.
Since all interactions between the elements are initiated by HTTP requests, the entities can be containerized and run from exposed ports.
The all container configuration values found in the YAML file have been described in previous tutorials.
To start the installation, do the following:
git clone https://github.com/FIWARE/tutorials.Administrating-XACML.git
cd tutorials.Administrating-XACML
git checkout NGSI-v2
./services create
Note
The initial creation of Docker images can take up to three minutes
Thereafter, all services can be initialized from the command-line by running the services Bash script provided within the repository:
./services start
Note
If you want to clean up and start over again you can do so with the following command:
./services stop
The following people at test.com
legitimately have accounts within the Application
- Alice, she will be the Administrator of the Keyrock Application
- Bob, the Regional Manager of the supermarket chain - he has several store managers under him:
- Manager1
- Manager2
- Charlie, the Head of Security of the supermarket chain - he has several store detectives under him:
- Detective1
- Detective2
The following people at example.com
have signed up for accounts, but have no reason to be granted access
- Eve - Eve the Eavesdropper
- Mallory - Mallory the malicious attacker
- Rob - Rob the Robber
For more details (Click to expand)
Name | Password | |
---|---|---|
alice | alice-the-admin@test.com |
test |
bob | bob-the-manager@test.com |
test |
charlie | charlie-security@test.com |
test |
manager1 | manager1@test.com |
test |
manager2 | manager2@test.com |
test |
detective1 | detective1@test.com |
test |
detective2 | detective2@test.com |
test |
Name | Password | |
---|---|---|
eve | eve@example.com |
test |
mallory | mallory@example.com |
test |
rob | rob@example.com |
test |
To apply an access control policy, it is necessary to be able to do the following:
- Create a consistent
<PolicySet>
- Supply a Policy Execution Point (PEP) which provides necessary data
As will be seen, Keyrock is able help with the first point, and custom code within the PEP Proxy can help with
the second. Authzforce itself does not offer a UI, and is not concerned with generation and management of XACML
policies - it assumes that each <PolicySet>
it receives has already been generated by another component.
Full-blown XACML editors are available, but the limited editor within Keyrock is usually sufficient for most access control scenarios.
Authzforce can act as a Policy Administration Point (PAP), this means that PolicySets can be created and amended using API calls directly to Authzforce
However there is no GUI for creating or amending a <PolicySet>
, and no generation tool. All CRUD actions occur on the
<PolicySet>
level.
A full XACML <PolicySet>
for any non-trivial application is very verbose. For simplicity, for this part of the
tutorial, we will work on a completely new set of access rules designed for airport parking enforcement. Authzforce
is implicitly multi-tenant - a single XACML server can be used to administrate access control policies for multiple
applications. Security policies for each application are held in a separate domain where they can access their own
<PolicySets>
- therefore administrating the airport application will not interfere with the existing rules for the
tutorial supermarket application.
To create a new domain in Authzforce, make a POST request to the /authzforce-ce/domains
endpoint including a
unique external-id
within the <domainProperties>
element
curl -X POST \
http://localhost:8080/authzforce-ce/domains \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<domainProperties xmlns="http://authzforce.github.io/rest-api-model/xmlns/authz/5" externalId="airplane"/>'
The response includes a href
in the <n2:link>
element which holds the domain-id
used internally within
Authzforce.
An empty PolicySet
will be created for the new domain. By default all access will be permitted.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<ns4:link
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns2="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
xmlns:ns3="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns4="http://www.w3.org/2005/Atom"
xmlns:ns5="http://authzforce.github.io/core/xmlns/pdp/6.0"
rel="item"
href="Sv-RRw9vEem6UQJCrBIBDA"
title="Sv-RRw9vEem6UQJCrBIBDA"
/>
The new domain-id
(in this case Sv-RRw9vEem6UQJCrBIBDA
) will be used with all subsequent requests.
To request a decision from Authzforce, make a POST request to the domains/{domain-id}/pdp
endpoint. In this case the
user is requesting access to loading
in the white
zone.
Remember to amend the request below to use your own {domain-id}
:
curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pdp \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false">
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">airplane!</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">white</AttributeValue>
</Attribute>
</Attributes>
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">loading</AttributeValue>
</Attribute>
</Attributes>
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" />
</Request>'
The response for the request includes a <Decision>
element to Permit
or Deny
access to the resource. at this point
all requests will be Permit
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Response
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns2="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
xmlns:ns3="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns4="http://www.w3.org/2005/Atom"
xmlns:ns5="http://authzforce.github.io/core/xmlns/pdp/6.0"
>
<Result>
<Decision>Permit</Decision>
</Result>
</Response>
To create a PolicySet
for a given domain information in Authzforce, make a POST request to the
/authzforce-ce/domains/{{domain-id}}/pap/policies
endpoint including the full set of XACML rules to upload.
For this initial Policy, the following rules will be enforced
- The white zone is for immediate loading and unloading of passengers only
- There is no stopping in the red zone
The full data for an XACML <PolicySet>
is very verbose and has been omitted from the request below:
Remember to amend the request below to use your own {domain-id}
:
curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pap/policies \
-H 'Content-Type: application/xml' \
-d '<PolicySet>...etc</PolicySet>'
(Click to expand)
{domain-id}
:curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pap/policies \
-H 'Content-Type: application/xml' \
-d '<PolicySet>...etc</PolicySet>'
Remember to amend the request below to use your own {domain-id}
:
curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pap/policies \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<PolicySet xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicySetId="f8194af5-8a07-486a-9581-c1f05d05483c" Version="1" PolicyCombiningAlgId="urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-unless-permit">
<Description>Policy Set for Airplane!</Description>
<Target />
<Policy PolicyId="airplane" Version="1.0" RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit">
<Description>Vehicle Roles from the Male announcer in the movie Airplane!</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">airplane!</AttributeValue>
<AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
</Match>
</AllOf>
</AnyOf>
</Target>
<Rule RuleId="white-zone" Effect="Permit">
<Description>The white zone is for immediate loading and unloading of passengers only</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">white</AttributeValue>
<AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
</Match>
</AllOf>
</AnyOf>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">loading</AttributeValue>
<AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
</Match>
</AllOf>
</AnyOf>
</Target>
</Rule>
<Rule RuleId="red-zone" Effect="Deny">
<Description>There is no stopping in the red zone</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">red</AttributeValue>
<AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
</Match>
</AllOf>
</AnyOf>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">stopping</AttributeValue>
<AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
</Match>
</AllOf>
</AnyOf>
</Target>
</Rule>
</Policy>
</PolicySet>
'
The response contains the internal ID of the policy held within Authzforce and version information about the
PolicySet
versions available. The rules of the new PolicySet
will not be applied until the PolicySet
is activated.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<ns4:link
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns2="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
xmlns:ns3="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns4="http://www.w3.org/2005/Atom"
xmlns:ns5="http://authzforce.github.io/core/xmlns/pdp/6.0"
rel="item"
href="f8194af5-8a07-486a-9581-c1f05d05483c/1"
title="Policy 'f8194af5-8a07-486a-9581-c1f05d05483c' v1"
/>
To activate a PolicySet
, make a PUT request to the /authzforce-ce/domains/{domain-id}/pap/pdp.properties
endpoint
including the policy-id
to update within the <rootPolicyRefExpresion>
attribute
Remember to amend the request below to use your own {domain-id}
:
curl -X PUT \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pap/pdp.properties \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<pdpPropertiesUpdate xmlns="http://authzforce.github.io/rest-api-model/xmlns/authz/5">
<rootPolicyRefExpression>f8194af5-8a07-486a-9581-c1f05d05483c</rootPolicyRefExpression>
</pdpPropertiesUpdate>'
The response returns information about the PolicySet
applied.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<ns3:pdpProperties
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns2="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
xmlns:ns3="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns4="http://www.w3.org/2005/Atom"
xmlns:ns5="http://authzforce.github.io/core/xmlns/pdp/6.0"
lastModifiedTime="2019-01-03T15:54:45.341Z"
>
<ns3:feature
type="urn:ow2:authzforce:feature-type:pdp:core"
enabled="false"
>urn:ow2:authzforce:feature:pdp:core:strict-attribute-issuer-match</ns3:feature>
<ns3:feature
type="urn:ow2:authzforce:feature-type:pdp:core"
enabled="false"
>urn:ow2:authzforce:feature:pdp:core:xpath-eval</ns3:feature>
... ETC
<ns3:rootPolicyRefExpression>f8194af5-8a07-486a-9581-c1f05d05483c</ns3:rootPolicyRefExpression>
<ns3:applicablePolicies>
<ns3:rootPolicyRef Version="1">f8194af5-8a07-486a-9581-c1f05d05483c</ns3:rootPolicyRef>
</ns3:applicablePolicies>
</ns3:pdpProperties>
At this point, making a request to access to loading
in the white
zone will return Permit
Remember to amend the request below to use your own {domain-id}
:
curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pdp \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false">
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">airplane!</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">white</AttributeValue>
</Attribute>
</Attributes>
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">loading</AttributeValue>
</Attribute>
</Attributes>
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" />
</Request>'
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Response
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns2="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
xmlns:ns3="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns4="http://www.w3.org/2005/Atom"
xmlns:ns5="http://authzforce.github.io/core/xmlns/pdp/6.0"
>
<Result>
<Decision>Permit</Decision>
</Result>
</Response>
At this point, making a request to access to loading
in the red
zone will return Deny
Remember to amend the request below to use your own {domain-id}
:
curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pdp \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false">
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">airplane!</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">red</AttributeValue>
</Attribute>
</Attributes>
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">loading</AttributeValue>
</Attribute>
</Attributes>
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" />
</Request>'
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Response
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns2="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
xmlns:ns3="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns4="http://www.w3.org/2005/Atom"
xmlns:ns5="http://authzforce.github.io/core/xmlns/pdp/6.0"
>
<Result>
<Decision>Deny</Decision>
</Result>
</Response>
To update a PolicySet
for a given domain information in Authzforce, make a POST request to the
/authzforce-ce/domains/{{domain-id}}/pap/policies
endpoint including the full set of XACML rules to upload. Note that
the Version
must be unique.
For the updated Policy, the previous rules will be reversed
- The red zone is for immediate loading and unloading of passengers only
- There is no stopping in the white zone
The full data for an XACML <PolicySet>
is very verbose and has been omitted from the request below:
Remember to amend the request below to use your own {domain-id}
:
curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pap/policies \
-H 'Content-Type: application/xml' \
-d '<PolicySet>...etc</PolicySet>'
(Click to expand)
{domain-id}
:curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pap/policies \
-H 'Content-Type: application/xml' \
-d '<PolicySet>...etc</PolicySet>'
Remember to amend the request below to use your own {domain-id}
:
curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pap/policies \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<PolicySet xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicySetId="f8194af5-8a07-486a-9581-c1f05d05483c" Version="2" PolicyCombiningAlgId="urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-unless-permit">
<Description>Policy Set for Airplane!</Description>
<Target />
<Policy PolicyId="airplane" Version="1.0" RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit">
<Description>Vehicle Roles from the Female announcer in the movie Airplane!</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">airplane!</AttributeValue>
<AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
</Match>
</AllOf>
</AnyOf>
</Target>
<Rule RuleId="red-zone" Effect="Permit">
<Description>The red zone is for immediate loading and unloading of passengers only</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">red</AttributeValue>
<AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
</Match>
</AllOf>
</AnyOf>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">loading</AttributeValue>
<AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
</Match>
</AllOf>
</AnyOf>
</Target>
</Rule>
<Rule RuleId="white-zone" Effect="Deny">
<Description>There is no stopping in the white zone</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">white</AttributeValue>
<AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
</Match>
</AllOf>
</AnyOf>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">stopping</AttributeValue>
<AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
</Match>
</AllOf>
</AnyOf>
</Target>
</Rule>
</Policy>
</PolicySet>
'
The response contains version information about the PolicySet
versions available. The rules of the new PolicySet
will not be applied until the PolicySet
is activated.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<ns4:link
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns2="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
xmlns:ns3="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns4="http://www.w3.org/2005/Atom"
xmlns:ns5="http://authzforce.github.io/core/xmlns/pdp/6.0"
rel="item"
href="f8194af5-8a07-486a-9581-c1f05d05483c/2"
title="Policy 'f8194af5-8a07-486a-9581-c1f05d05483c' v2"
/>
To update an active a PolicySet
, make another PUT request to the
/authzforce-ce/domains/{domain-id}/pap/pdp.properties
endpoint including the policy-id
to update within the
<rootPolicyRefExpresion>
attribute. The ruleset will be updated to apply the latest uploaded version.
Remember to amend the request below to use your own {domain-id}
:
curl -X PUT \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pap/pdp.properties \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<pdpPropertiesUpdate xmlns="http://authzforce.github.io/rest-api-model/xmlns/authz/5">
<rootPolicyRefExpression>f8194af5-8a07-486a-9581-c1f05d05483c</rootPolicyRefExpression>
</pdpPropertiesUpdate>'
The response returns information about the PolicySet
applied.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<ns3:pdpProperties
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns2="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
xmlns:ns3="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns4="http://www.w3.org/2005/Atom"
xmlns:ns5="http://authzforce.github.io/core/xmlns/pdp/6.0"
lastModifiedTime="2019-01-03T15:58:29.351Z"
>
<ns3:feature
type="urn:ow2:authzforce:feature-type:pdp:core"
enabled="false"
>urn:ow2:authzforce:feature:pdp:core:strict-attribute-issuer-match</ns3:feature>
<ns3:feature
type="urn:ow2:authzforce:feature-type:pdp:core"
enabled="false"
>urn:ow2:authzforce:feature:pdp:core:xpath-eval</ns3:feature>
... ETC
<ns3:rootPolicyRefExpression>f8194af5-8a07-486a-9581-c1f05d05483c</ns3:rootPolicyRefExpression>
<ns3:applicablePolicies>
<ns3:rootPolicyRef Version="2">f8194af5-8a07-486a-9581-c1f05d05483c</ns3:rootPolicyRef>
</ns3:applicablePolicies>
</ns3:pdpProperties>
Since the new policy has been activated, at this point, making a request to access to loading
in the white
zone will
return Deny
Remember to amend the request below to use your own {domain-id}
:
curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pdp \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false">
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">airplane!</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">white</AttributeValue>
</Attribute>
</Attributes>
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">loading</AttributeValue>
</Attribute>
</Attributes>
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" />
</Request>'
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Response
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns2="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
xmlns:ns3="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns4="http://www.w3.org/2005/Atom"
xmlns:ns5="http://authzforce.github.io/core/xmlns/pdp/6.0"
>
<Result>
<Decision>Deny</Decision>
</Result>
</Response>
Making a request to access to loading
in the red
zone under the current policy will return Permit
Remember to amend the request below to use your own {domain-id}
:
curl -X POST \
http://localhost:8080/authzforce-ce/domains/{domain-id}/pdp \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false">
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">airplane!</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">red</AttributeValue>
</Attribute>
</Attributes>
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">loading</AttributeValue>
</Attribute>
</Attributes>
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" />
</Request>'
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Response
xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns2="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
xmlns:ns3="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns4="http://www.w3.org/2005/Atom"
xmlns:ns5="http://authzforce.github.io/core/xmlns/pdp/6.0"
>
<Result>
<Decision>Permit</Decision>
</Result>
</Response>
Keyrock offers a role based access control identity management system. Typically every permission is only accessible to users within a given role. We have already seen how Verb-Resource rules can be set-up and enforced using the basic authorization (level 2) access control mechanism found within Keyrock, the data for defining an advanced permission can also be administered using the Keyrock GUI or via Keyrock REST API requests.
Keyrock permissions work on individual XACML <Rule>
elements rather than a complete <PolicySet>
. The
<PolicySet>
is generated by combining all the roles and permissions.
In a similar manner to the previous tutorial, two roles have been created, one for store detectives and another for management users. A series of permissions have been set up for the supermarket application, the following XACML rules are applied:
- Can unlock the door at any time
- Can ring the alarm bell before 8 a.m. or after 5 p.m. UTC.
- Can access the context broker data at any time
- Have access to the price change area
- Have access to the stock count area
- Can ring the alarm bell between 8 a.m. and 5 p.m. UTC.
- Can access the context broker data from 8 a.m. to 5 p.m. UTC.
As you can see some of the new rules now have a time element to them and are no longer simple Verb-Resource rules.
For most of the rules, the Policy Execution Point (i.e. the request to Authzforce and analysis of the result) is found within the tutorial code -
The context broker data for the Store and IoT Devices is held in is secured behind the PEP Proxy. This means that only security staff are able to access the system outside of core hours.
Note
within the Keyrock, only four resources have been secured using advanced authorization rules (level 3)
- sending the ring bell command
- access to the price-change area
- access to the order-stock area
- PEP Proxy access to the context broker
For contrast, one resource has been left as a simple VERB Resource permission (level 2)
- sending the unlock door command
Enter a username and password to enter the application. The default super-user has the values alice-the-admin@test.com
and test
.
curl -iX POST \
http://localhost:3005/v1/auth/tokens \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"name": "alice-the-admin@test.com",
"password": "test"
}'
The response header from Keyrock returns an X-Subject-token
which identifies who has logged on the application.
This token is required in all subsequent requests to gain access
HTTP/1.1 201 Created
X-Subject-Token: d848eb12-889f-433b-9811-6a4fbf0b86ca
Content-Type: application/json; charset=utf-8
Content-Length: 138
ETag: W/"8a-TVwlWNKBsa7cskJw55uE/wZl6L8"
Date: Mon, 30 Jul 2018 12:07:54 GMT
Connection: keep-alive
The response body from Keyrock indicates that Authzforce is in use and XACML Rules can be used to define access policies.
{
"token": {
"methods": ["password"],
"expires_at": "2019-01-03T17:04:43.358Z"
},
"idm_authorization_config": {
"level": "advanced",
"authzforce": true
}
}
As a reminder, for simple verb-resource permissions, the /applications/{{app-id}}/permissions/{permission-id}}
endpoint will return the permission listed under that ID. The X-Auth-token
must be supplied in the headers.
curl -X GET \
http://localhost:3005/v1/applications/tutorial-dckr-site-0000-xpresswebapp/permissions/entrance-open-0000-0000-000000000000 \
-H 'Content-Type: application/json' \
-H 'X-Auth-token: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
The response returns the details of the requested permission, for a verb-resource permission, the xml
element is
null
. This permission indicates that a user is permitted to make a POST request to the /door/unlock
endpoint to
unlock the main entrance.
{
"permission": {
"id": "entrance-open-0000-0000-000000000000",
"name": "Unlock",
"description": "Unlock main entrance",
"is_internal": false,
"action": "POST",
"resource": "/door/unlock",
"xml": null,
"oauth_client_id": "tutorial-dckr-site-0000-xpresswebapp"
}
}
XACML Rule permissions can be accessed in the same way, the /applications/{{app-id}}/permissions/{permission-id}}
endpoint will return the permission listed under that ID. The X-Auth-token
must be supplied in the headers.
curl -X GET \
http://localhost:3005/v1/applications/tutorial-dckr-site-0000-xpresswebapp/permissions/alrmbell-ring-24hr-xaml-000000000000 \
-H 'Content-Type: application/json' \
-H 'X-Auth-token: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
The response returns the details of the requested permission, for a XACML Rule permission, the xml
element holds the
details of the associated XACML <Rule>
the action
and resource
fields are null
.
There is already one <Rule>
within the xml
attribute, which states the following:
Security Staff Can only ring the alarm bell before 8 a.m. or after 5 p.m.
To see the full <Rule>
(Click to expand)
<Rule RuleId="alrmbell-ring-24hr-hours-000000000000" Effect="Permit">
<Description>Ring Alarm Bell (Outside Core Hours)</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">/bell/ring</AttributeValue>
<AttributeDesignator
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="true"
/>
</Match>
</AllOf>
</AnyOf>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">POST</AttributeValue>
<AttributeDesignator
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="true"
/>
</Match>
</AllOf>
</AnyOf>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string"
>security-role-0000-0000-000000000000</AttributeValue>
<AttributeDesignator
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
AttributeId="urn:oasis:names:tc:xacml:2.0:subject:role"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="true"
/>
</Match>
</AllOf>
</AnyOf>
</Target>
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:not">
<Apply FunctionId="urn:oasis:names:tc:xacml:2.0:function:time-in-range">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-one-and-only">
<AttributeDesignator
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment"
AttributeId="urn:oasis:names:tc:xacml:1.0:environment:current-time"
DataType="http://www.w3.org/2001/XMLSchema#time"
MustBePresent="false"
/>
</Apply>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-one-and-only">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-bag">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#time">08:00:00</AttributeValue>
</Apply>
</Apply>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-one-and-only">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:time-bag">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#time">17:00:00</AttributeValue>
</Apply>
</Apply>
</Apply>
</Apply>
</Condition>
</Rule>
The <Target>
element of the <Rule>
defines access on a Verb-Resource level in a similar manner as seen in the
previous tutorial. The <Condition>
element holds the time part of the rule and is evaluated by Authzforce based on
the current server time.
{
"permission": {
"id": "alrmbell-ring-24hr-xaml-000000000000",
"name": "Ring Alarm Bell (Outside Core hours)",
"description": "Ring Alarm Bell for Security",
"is_internal": false,
"action": null,
"resource": null,
"xml": "<Rule RuleId=\"alrmbell-ring-24hr-hours-000000000000\" Effect=\"Permit\">\n<Description>Ring Alarm Bell (Outside Core Hours)</Description>\n<Target>\n<AnyOf>\n<AllOf>\n<Match MatchId=\"urn:oasis:names:tc:xacml:1.0:function:string-equal\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">/bell/ring</AttributeValue>\n<AttributeDesignator Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\" AttributeId=\"urn:thales:xacml:2.0:resource:sub-resource-id\" DataType=\"http://www.w3.org/2001/XMLSchema#string\" MustBePresent=\"true\" />\n</Match>\n</AllOf>\n</AnyOf>\n<AnyOf>\n<AllOf>\n<Match MatchId=\"urn:oasis:names:tc:xacml:1.0:function:string-equal\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">POST</AttributeValue>\n<AttributeDesignator Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:action\" AttributeId=\"urn:oasis:names:tc:xacml:1.0:action:action-id\" DataType=\"http://www.w3.org/2001/XMLSchema#string\" MustBePresent=\"true\" />\n</Match>\n</AllOf>\n</AnyOf>\n<AnyOf>\n<AllOf>\n<Match MatchId=\"urn:oasis:names:tc:xacml:1.0:function:string-equal\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">security-role-0000-0000-000000000000</AttributeValue>\n<AttributeDesignator Category=\"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\" AttributeId=\"urn:oasis:names:tc:xacml:2.0:subject:role\" DataType=\"http://www.w3.org/2001/XMLSchema#string\" MustBePresent=\"true\" />\n</Match>\n</AllOf>\n</AnyOf>\n</Target>\n<Condition>\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:not\">\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:2.0:function:time-in-range\">\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:time-one-and-only\">\n<AttributeDesignator AttributeId=\"urn:oasis:names:tc:xacml:1.0:environment:current-time\" DataType=\"http://www.w3.org/2001/XMLSchema#time\" Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\" MustBePresent=\"false\"></AttributeDesignator>\n</Apply>\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:time-one-and-only\">\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:time-bag\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#time\">08:00:00</AttributeValue>\n</Apply>\n</Apply>\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:time-one-and-only\">\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:time-bag\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#time\">17:00:00</AttributeValue>\n</Apply>\n</Apply>\n</Apply>\n</Apply>\n</Condition>\n</Rule>",
"oauth_client_id": "tutorial-dckr-site-0000-xpresswebapp"
}
}
Tip An annotated version of the full <PolicySet>
can be found within the
tutorial itself
To request a decision from Authzforce, make a POST request to the domains/{domain-id}/pdp
endpoint. In this case the
user is requesting access to POST
to the /bell/ring
endpoint.
curl -X POST \
http://localhost:8080/authzforce-ce/domains/gQqnLOnIEeiBFQJCrBIBDA/pdp \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false">
<Attributes Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject">
<Attribute AttributeId="urn:oasis:names:tc:xacml:2.0:subject:role" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">security-role-0000-0000-000000000000</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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">tutorial-dckr-site-0000-xpresswebapp</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">/bell/ring</AttributeValue>
</Attribute>
</Attributes>
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">POST</AttributeValue>
</Attribute>
</Attributes>
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" />
</Request>'
The response for the request includes a <Decision>
element to Permit
or Deny
access to the resource.
If the time on the server is between 8 a.m. and 5 p.m. UTC, the access request will be denied.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<ns2:Response
xmlns="http://www.w3.org/2005/Atom"
xmlns:ns2="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns3="http://authzforce.github.io/core/xmlns/pdp/6.0"
xmlns:ns4="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns5="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
>
<ns2:Result>
<ns2:Decision>Deny</ns2:Decision>
</ns2:Result>
</ns2:Response>
The policy will now be updated as follows:
Security Staff Can only ring the alarm bell before 8 a.m. or after 5 p.m., except for Charlie who can ring the bell at any time
This means that the alrmbell-ring-24hr-xaml-000000000000
permission will need to be amended to apply two rules:
To see the new <Rule>
(Click to expand)
<Rule RuleId="alrmbell-ring-only-000000000000" Effect="Permit">
<Description>Allow Full Access to Charlie the Security Manager</Description>
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">/bell/ring</AttributeValue>
<AttributeDesignator
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="true"
/>
</Match>
</AllOf>
</AnyOf>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">POST</AttributeValue>
<AttributeDesignator
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="true"
/>
</Match>
</AllOf>
</AnyOf>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">charlie</AttributeValue>
<AttributeDesignator
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="true"
/>
</Match>
</AllOf>
</AnyOf>
</Target>
</Rule>
This is most easily be done in the GUI by pasting the rule into the appropriate text box, however it can also be done programmatically.
To log-in to the Keyrock GUI, enter the username and password on the log-in page http://localhost:3005/
Navigate to correct application, and click on the manage roles tab
Select a permission to edit
The HTTP Verb and Resource rule needs to be left blank, but the applicable XACML <Rule>
elements need to be pasted
within the Advanced XACML Rule textbox as shown:
Alternatively to programmatically amend the XACML rules governing a permission, make a PATCH request to the
/applications/{{app-id}}/permissions/{permission-id}}
endpoint. The body of the request must include three
attributes - action
and resource
must both be set to ""
and the xml
attribute should hold the XACML text.
The full data for the request very verbose and has been omitted below:
curl -X PATCH \
http://localhost:3005/v1/applications/tutorial-dckr-site-0000-xpresswebapp/permissions/alrmbell-ring-24hr-xaml-000000000000 \
-H 'Content-Type: application/json' \
-H 'X-Auth-token: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' \
-d '{
"permission": {
"action": "",
"resource": "",
"use_authorization_service_header" : false,
"xml": "<Rule RuleId=\"alrmbell-ring-only-000000000000\" Effect=\"Permit\"> etc..."
}
}
(Click to expand)
curl -X PATCH \
http://localhost:3005/v1/applications/tutorial-dckr-site-0000-xpresswebapp/permissions/alrmbell-ring-24hr-xaml-000000000000 \
-H 'Content-Type: application/json' \
-H 'X-Auth-token: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' \
-d '{
"permission": {
"action": "",
"resource": "",
"use_authorization_service_header" : false,
"xml": "<Rule RuleId=\"alrmbell-ring-only-000000000000\" Effect=\"Permit\"> etc..."
}
}
curl -X PATCH \
http://localhost:3005/v1/applications/tutorial-dckr-site-0000-xpresswebapp/permissions/alrmbell-ring-24hr-xaml-000000000000 \
-H 'Content-Type: application/json' \
-H 'X-Auth-token: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' \
-d '{
"permission": {
"action": "",
"resource": "",
"use_authorization_service_header" : false,
"xml": "<Rule RuleId=\"alrmbell-ring-only-000000000000\" Effect=\"Permit\">\n<Description>Allow Full Access to Charlie the Security Manager</Description>\n<Target>\n<AnyOf>\n<AllOf>\n<Match MatchId=\"urn:oasis:names:tc:xacml:1.0:function:string-equal\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">/bell/ring</AttributeValue>\n<AttributeDesignator Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\" AttributeId=\"urn:thales:xacml:2.0:resource:sub-resource-id\" DataType=\"http://www.w3.org/2001/XMLSchema#string\" MustBePresent=\"true\" />\n</Match>\n</AllOf>\n</AnyOf>\n<AnyOf>\n<AllOf>\n<Match MatchId=\"urn:oasis:names:tc:xacml:1.0:function:string-equal\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">POST</AttributeValue>\n<AttributeDesignator Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:action\" AttributeId=\"urn:oasis:names:tc:xacml:1.0:action:action-id\" DataType=\"http://www.w3.org/2001/XMLSchema#string\" MustBePresent=\"true\" />\n</Match>\n</AllOf>\n</AnyOf>\n<AnyOf>\n<AllOf>\n<Match MatchId=\"urn:oasis:names:tc:xacml:1.0:function:string-equal\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">charlie</AttributeValue>\n<AttributeDesignator Category=\"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\" AttributeId=\"urn:oasis:names:tc:xacml:1.0:subject:subject-id\" DataType=\"http://www.w3.org/2001/XMLSchema#string\" MustBePresent=\"true\" />\n</Match>\n</AllOf>\n</AnyOf>\n</Target>\n</Rule>\n<Rule RuleId=\"alrmbell-ring-24hr-hours-000000000000\" Effect=\"Permit\">\n<Description>Ring Alarm Bell (Outside Core Hours)</Description>\n<Target>\n<AnyOf>\n<AllOf>\n<Match MatchId=\"urn:oasis:names:tc:xacml:1.0:function:string-equal\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">/bell/ring</AttributeValue>\n<AttributeDesignator Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:resource\" AttributeId=\"urn:thales:xacml:2.0:resource:sub-resource-id\" DataType=\"http://www.w3.org/2001/XMLSchema#string\" MustBePresent=\"true\" />\n</Match>\n</AllOf>\n</AnyOf>\n<AnyOf>\n<AllOf>\n<Match MatchId=\"urn:oasis:names:tc:xacml:1.0:function:string-equal\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">POST</AttributeValue>\n<AttributeDesignator Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:action\" AttributeId=\"urn:oasis:names:tc:xacml:1.0:action:action-id\" DataType=\"http://www.w3.org/2001/XMLSchema#string\" MustBePresent=\"true\" />\n</Match>\n</AllOf>\n</AnyOf>\n<AnyOf>\n<AllOf>\n<Match MatchId=\"urn:oasis:names:tc:xacml:1.0:function:string-equal\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#string\">security-role-0000-0000-000000000000</AttributeValue>\n<AttributeDesignator Category=\"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject\" AttributeId=\"urn:oasis:names:tc:xacml:2.0:subject:role\" DataType=\"http://www.w3.org/2001/XMLSchema#string\" MustBePresent=\"true\" />\n</Match>\n</AllOf>\n</AnyOf>\n</Target>\n<Condition>\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:not\">\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:2.0:function:time-in-range\">\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:time-one-and-only\">\n<AttributeDesignator AttributeId=\"urn:oasis:names:tc:xacml:1.0:environment:current-time\" DataType=\"http://www.w3.org/2001/XMLSchema#time\" Category=\"urn:oasis:names:tc:xacml:3.0:attribute-category:environment\" MustBePresent=\"false\"></AttributeDesignator>\n</Apply>\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:time-one-and-only\">\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:time-bag\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#time\">08:00:00</AttributeValue>\n</Apply>\n</Apply>\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:time-one-and-only\">\n<Apply FunctionId=\"urn:oasis:names:tc:xacml:1.0:function:time-bag\">\n<AttributeValue DataType=\"http://www.w3.org/2001/XMLSchema#time\">17:00:00</AttributeValue>\n</Apply>\n</Apply>\n</Apply>\n</Apply>\n</Condition>\n</Rule>"
}
}'
The response shows the details of the attributes which have been updated.
{
"values_updated": {
"action": null,
"resource": null,
"xml": "<Rule RuleId=\"alrmbell-ring-only-000000000000\" Effect=\"Permit\"> etc..."
}
}
When Keyrock is connected to Authzforce the <PolicySet>
is automatically updated whenever the role-permission
associations are amended, the easiest way to do this is to delete and re-create any single association.
Firstly delete an association using a DELETE request:
curl -X DELETE \
http://localhost:3005/v1/applications/tutorial-dckr-site-0000-xpresswebapp/roles/security-role-0000-0000-000000000000/permissions/alrmbell-ring-24hr-xaml-000000000000 \
-H 'Content-Type: application/json' \
-H 'X-Auth-token: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
Then re-create it using a POST request as shown:
curl -X POST \
http://localhost:3005/v1/applications/tutorial-dckr-site-0000-xpresswebapp/roles/security-role-0000-0000-000000000000/permissions/alrmbell-ring-24hr-xaml-000000000000 \
-H 'Content-Type: application/json' \
-H 'X-Auth-token: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
If Authzforce has been updated, an additional authzforce
attribute will be present within the response, the new
<PolicySet>
will now be in place.
{
"role_permission_assignments": {
"role_id": "security-role-0000-0000-000000000000",
"permission_id": "alrmbell-ring-24hr-xaml-000000000000"
},
"authzforce": {
"create_policy": {
"message": " Success creating policy.",
"status": 200
},
"activate_policy": {
"message": "Success",
"status": 200
}
}
}
Additional Fields can be added to the policy decision request to improve the likelihood of a Permit
response.
In the example below, the emailaddress
and subject:subject-id
have been added to the body of the request within the
subject-category:access-subject
category.
With the new rule in place, the user charlie
will be able to access the /bell/ring
endpoint at all times of day.
The full data for the request very verbose and has been omitted below:
curl -X POST \
http://localhost:8080/authzforce-ce/domains/gQqnLOnIEeiBFQJCrBIBDA/pdp \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false">
...etc
</Request>'
(Click to expand)
curl -X POST \
http://localhost:8080/authzforce-ce/domains/gQqnLOnIEeiBFQJCrBIBDA/pdp \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false">
...etc
</Request>'
curl -X POST \
http://localhost:8080/authzforce-ce/domains/gQqnLOnIEeiBFQJCrBIBDA/pdp \
-H 'Content-Type: application/xml' \
-d '<?xml version="1.0" encoding="UTF-8"?>
<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false">
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">charlie</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">charlie-security@test.com</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:oasis:names:tc:xacml:2.0:subject:role" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">security-role-0000-0000-000000000000</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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">tutorial-dckr-site-0000-xpresswebapp</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:thales:xacml:2.0:resource:sub-resource-id" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">/bell/ring</AttributeValue>
</Attribute>
</Attributes>
<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="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">POST</AttributeValue>
</Attribute>
</Attributes>
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" />
</Request>'
The response is Permit
when the new <Rule>
has been applied.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<ns2:Response
xmlns="http://www.w3.org/2005/Atom"
xmlns:ns2="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
xmlns:ns3="http://authzforce.github.io/core/xmlns/pdp/6.0"
xmlns:ns4="http://authzforce.github.io/rest-api-model/xmlns/authz/5"
xmlns:ns5="http://authzforce.github.io/pap-dao-flat-file/xmlns/properties/3.6"
>
<ns2:Result>
<ns2:Decision>Permit</ns2:Decision>
</ns2:Result>
</ns2:Response>
The new policy for Charlie the security manager needs additional information to be passed to Authzforce
Programmatically, any Policy Execution Point consists of two parts, an OAuth request to Keyrock retrieves information about the user (such as the assigned roles) as well as the policy domain to be queried.
A second request is sent to the relevant domain endpoint within Authzforce, providing all of the information necessary for Authzforce to provide a judgement. Authzforce responds with a permit or deny response, and the decision whether to continue can be made thereafter.
The user.username
and user.email
have been added to the list of fields to be sent to Authzforce
function authorizeAdvancedXACML(req, res, next, resource = req.url) {
const keyrockUserUrl =
'http://keyrock/user?access_token=' + req.session.access_token + '&app_id=' + clientId + '&authzforce=true';
return oa
.get(keyrockUserUrl)
.then((response) => {
const user = JSON.parse(response);
return azf.policyDomainRequest(
user.app_azf_domain,
user.roles,
user.username,
user.email,
resource,
req.method
);
})
.then((authzforceResponse) => {
res.locals.authorized = authzforceResponse === 'Permit';
return next();
})
.catch((error) => {
debug(error);
res.locals.authorized = false;
return next();
});
}
The full code to supply each request to Authzforce can be found within the tutorials'
Git Repository - the
supplied information has been expanded to include the username
and email
within the generated XACML request
const xml2js = require('xml2js');
const request = require('request');
function policyDomainRequest(domain, roles, resource, action, username, email) {
let body =
'<?xml version="1.0" encoding="UTF-8"?>\n' +
'<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" CombinedDecision="false" ReturnPolicyIdList="false">\n';
// Code to create the XML body for the request is omitted
body = body + '</Request>';
const options = {
method: 'POST',
url: 'http://authzforceUrl/authzforce-ce/domains/' + domain + '/pdp',
headers: { 'Content-Type': 'application/xml' },
body
};
return new Promise((resolve, reject) => {
request(options, function (error, response, body) {
let decision;
xml2js.parseString(body, { tagNameProcessors: [xml2js.processors.stripPrefix] }, function (err, jsonRes) {
// The decision is found within the /Response/Result[0]/Decision[0] XPath
decision = jsonRes.Response.Result[0].Decision[0];
});
decision = String(decision);
return error ? reject(error) : resolve(decision);
});
});
}
After successfully update the Authzforce <PolicySet>
to include a special rule for Charlie, his rights will differ
from other users in the security role
Detective1 works for Charlie and has the security role
- From
http://localhost:3000
, log in asdetective1@test.com
with the passwordtest
- Click on the restricted access links at
http://localhost:3000
- access is denied - This is a management only permission - Open the Device Monitor on
http://localhost:3000/device/monitor
- Unlock a door - access is permitted - This is a security only permission
- Ring a bell - access is denied - This is not permitted to security users between 8 a.m. and 5 p.m. UTC.
Charlie has the security role
- From
http://localhost:3000
, log in ascharlie-security@test.com
with the passwordtest
- Click on the restricted access links at
http://localhost:3000
- access is denied - This is a management only permission - Open the Device Monitor on
http://localhost:3000/device/monitor
- Unlock a door - access is permitted - This is a security only permission
- Ring a bell - access is permitted - This is an exception which is only permitted to the user called
charlie
Want to learn how to add more complexity to your application by adding advanced features? You can find out by reading the other tutorials in this series
MIT © 2019-2024 FIWARE Foundation e.V.