owned this note
owned this note
Published
Linked with GitHub
$\newcommand{\true}{\mathsf{true}}
\newcommand{\false}{\mathsf{false}}
\newcommand{\grant}{\mathtt{grant}}
\newcommand{\deny}{\mathtt{deny}}
\newcommand{\ifrule}{\mathtt{if}}
\newcommand{\elserule}{\mathtt{else}}
\newcommand{\cond}{cond}
\newcommand{\guard}{guard}
\newcommand{\undefined}{\mathtt{undef}}
\newcommand{\conflict}{\mathtt{conflict}}
\newcommand{\decision}[1]{\mathtt{decision}\!\left({#1}\right)}
\newcommand{\dec}{dec}
\newcommand{\policy}{pol}
\newcommand{\eval}{\mathtt{eval}}
\newcommand{\casepolicy}{\mathtt{case}}
\newcommand{\goc}[1]{\mathsf{GoC}(\vphantom{g_{-}}{#1})}
\newcommand{\doc}[1]{\mathsf{DoC}(\vphantom{g_{-}}{#1})}
\newcommand{\gobl}[1]{\mathsf{GObl}(\vphantom{g_{-}}{#1})}
\newcommand{\dobl}[1]{\mathsf{DObl}(\vphantom{g_{-}}{#1})}
\newcommand{\TrueGuard}[1]{\mathsf{T}(\vphantom{g_{-}}{#1})}
\newcommand{\ReachGuard}[1]{\mathsf{R}(\vphantom{g_{-}}{#1})}
\newcommand{\obligation}[3]{\mathsf{oblg}(\vphantom{g_{-}}{#1},\,{#2},\,{#3})}
\newcommand{\obligationguard}[3]{\mathsf{oblg'}(\vphantom{g_{-}}{#1},\,{#2},\,{#3})}
\newcommand{\dand}{\;\&\&\;}
\newcommand{\dor}{\;||\;}
\newcommand{\accesscontrolname}{\textsf{FROST}}
\newcommand{\mergepol}{\mathtt{join}}
\newcommand{\refast}[1]{(\ast_{#1})}$
:::info
Latest update: 22.11.2018
:::
# Properties of Obligations
This document provides references to literature as well as some analysis on properties of obligations, namely temporality and accountability as well as their monitoring. The representation of obligations as obligation policies in the $\accesscontrolname{}$ language is explained and an obligation object is introduced to replace the key-value string-pair obligation. Then a generalized policy object is defined to unify the notation of policy objects and obligation object and an example is given to demonstrate its purpose.
**Documents**
- [Compilation of Policies with Obligations](https://hackmd.io/t5YMLzMCRQ2CEVEER2Vzpg)
- [Test vectors for EPIC use cases](https://hackmd.io/r8hnR8daRmy596FMdSoK-Q)
| Author(s) | Year | Title |
|:-:|:-:|:-|
| M. Ali<br>*et al* | '10 | [Obligation Language for Access Control<br>and Privacy Policies](http://www.fim.uni-passau.de/fileadmin/files/lehrstuhl/meer/publications/pdf/Ali2010a.pdf) |
| D. Chadwick | '09 | [Obligation Standardization](https://www.w3.org/2009/policy-ws/papers/Chadwick.pdf) |
| D.E. Kateb<br>*et al* | '14 | [Towards a Full Support of Obligations In XACML](https://orbilu.uni.lu/bitstream/10993/19082/1/CRISIS.pdf) |
| K. Irwin<br>*et al* | '06 | [On the Modeling and Analysis of Obligations](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.2076&rep=rep1&type=pdf) |
| P. Gama,<br>P. Ferreira | '05 | [Obligation Policies: An Enforcement Platform](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.144.9853&rep=rep1&type=pdf) |
| Q. Ni<br>*et al* | '08 | [An Obligation Model Bridging Access Control<br>Policies and Privacy Policies](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.666.1141&rep=rep1&type=pdf) |
| M. Hilty<br>*et al* | '05 | [On Obligations](https://mediatum.ub.tum.de/doc/1253903/file.pdf) |
| L. Chen<br>*et al* | '12 | [Obligations in Risk-Aware Access Control](https://s3.amazonaws.com/academia.edu.documents/30738688/Chen__PST2012.pdf?AWSAccessKeyId=AKIAIWOWYYGZ2Y53UL3A&Expires=1534179707&Signature=OHeQrq4vv9rn5Nbd%2FT7luR6ihB4%3D&response-content-disposition=inline%3B%20filename%3DObligations_in_risk-aware_access_control.pdf) |
| M. Pontual<br>*et al* | '11 | [On the Management of User Obligations](http://homepage.divms.uiowa.edu/~comarhaider/publications/obligation-sacmat11.pdf) |
| M. Pontual<br>*et al* | '10 | [Toward Practical Authorization-dependent<br>User Obligation Systems](http://venom.cs.utsa.edu/dmz/techrep/2009/CS-TR-2009-011.pdf) |
| Oasis | '17 | [eXtensible Access Control Markup Language<br>Version 3.0](http://docs.oasis-open.org/xacml/3.0/xacml-3.0-core-spec-en.pdf) |
| Xain | '18 | The $\accesscontrolname{}$ Language v0.8.1 |
**Contents**
- [Properties of Obligations](#Properties-of-Obligations)
- [Temporal Categories](#Temporal-Categories)
- [Accountability and Monitoring](#Accountability-and-Monitoring)
- [Obligation Policies](#Obligation-Policies)
- [Obligation Objects](#Obligation-Objects)
- [Generalized Policy Objects](#Generalized-Policy-Objects)
- [Example](#Example)
Obligations can be classified into *positive* and *negative* obligations. The term *positive* shall denote duties corresponding to an access request. The term *negative* shall denote prohibitions (e.g. write locks while reading access is granted), which can be reformulated as part of the policy itself and therefore are enforceable by the PEP most of the time.
In contrast to obligations for the system/resource, the obligations for a user of an access request, where the actual fulfillment of this duty usually lies in the future (e.g. the payment of a monthly subscription), are unenforceable by the PEP and rely solely on the user in many cases. The violation of obligations targeted at users may be punished and their diligent fulfillment may be incentivised, which can be monitored, e.g., by some kind of credit rating.
Optional obligations, also called advices, may be monitored by the PEP, but their violation must not change the decision of the PDP. The differentiation between obligations and advices is dependent on the use case.
## Temporal Categories
Positive obligations, from now on only called obligations, can be categorized into *pre*-, *ongoing*- and *post*-obligations. A violation of an obligation only makes sense in a temporal context, i.e. without any deadline/timeframe there is little meaning to the violation of an obligation related to an access request.
*Pre*-obligations refer to obligations to be fulfilled before the actual access is granted (e.g. complying with terms of service of a rental car). They are sometimes called *provisions* by other authors. *Ongoing*-obligations refer to obligations to be periodically checked while the actual access is performed (e.g. obeying to the speed limit or regional restrictions of the rental car stated in the terms of service). *Post*-obligations refer to obligations to be fulfilled after the actual access is completed (e.g. sending a report about the rental car usage after return). They are sometimes called *obligations* (without any prefix) by other authors.
If *pre*-obligations are not fulfilled, then the PEP should not grant access. If *ongoing*-obligations are not fulfilled, then the PEP might restrict or terminate access. If *post*-obligations are not fulfilled, then the PEP should not grant access for reoccurring requests in the future.
*Post*-obligations might additionally trigger future obligations once or periodically. The trigger itself can be a fixed date in the future. Alternatively, the trigger can be an event, which requires the monitoring of events by the PEP.
## Accountability and Monitoring
The violation of obligations can be transferred into an accountability problem, such that it can be attributed who caused the violation of the obligation. Violation of obligations by the system/resource should usually not happen, because the PEP should deny access if any obligations are known to be unfulfillable by the system/resource. That means, violation of obligations might usually be caused by users participating in the access control setting.
While the `obligation_grant` and `obligation_deny` objects provided by the PDP represent the circuits used to calculate the set of obligations for a $\grant$ or $\deny$ decision, it is in the domain of the PEP to monitor all pending obligations and to check if they are fulfilled or violated at some point in time. The monitoring may be partitioned into several subtasks.
It should check if users are authorized to perform the necessary actions needed to fulfill their obligations. Due to possible violations of *post* obligations the monitoring should include a history log to base future access decisions on past violations. Also, it should monitor if newly appended obligations are contradicting or preventing the fulfillment of currently existing obligations. Moreover, in a policy composition setting it might be necessary for the PEP to check for self-contradicting, or cyclic-dependent, or cascading, or subsumed obligations.
- cascading obligations: obligations which trigger further obligations and so on, i.e. finite or infinite obligation sequences
- cyclic-dependent obligations: cascading obligations which repeat at some point, i.e. infinite obligation sequences
- self-contradicting obligations: two (sets of) obligations which have opposite semantic meanings
- subsumed obligations: two (sets of) obligations where one is part of the other, formally or semantically
In the case of policies composed by the PDP this is covered by the 4-valued logic, so one could argue about a mechanism for obligation composition and static analysis for obligation policies.
## Obligation Policies
Obligations themselves might be written as policies. Common reoccurring elements are deadlines or timeframes to state when unfulfilled obligations become violated. Obligations usually specify actions to be taken by some subject or user or system. Also, it should be specified on which subjects or resources the actions are targeted. These key elements may be tied to conditions or events.
This means that obligation policies can be expressed as $\accesscontrolname{}$ policies containing conditions that check the time constraints as well as conditions checking some state or attribute, respectively, that is supposed to change when the specific action is performed. The same applies to events (which are not defined here), because this should be observable by the system to be taken into account, i.e. any kind of altered state. The access control of whether the subject is able to perform the action on the object in the first place can be handled by the $\accesscontrolname{}$ language, too. Since it usually matters if the obligation was fulfilled by the user who is obliged to it or some other entity, this can be checked by additional conditions which, e.g., read data from logs.
It is important to note, that the result from an evaluated obligation policy has to be interpreted differently than access request policy decisions. One way to do this is to assign the meaning *obligation is fulfilled* to the decision $\grant$, and *obligation is violated* to the decision $\deny$. A *pending obligation* which still has to be monitored can be assigned $\undefined$. *Pending obligations* may be further divided into *available* and *unavailable pending obligations*, where the latter refers to the unsatisfiability of a *pending obligation* by the user due to missing authorization by the system.
It is then up to the PEP to periodically task the PDP with the evaluation of the obligation policies corresponding to pending obligations and to take action based on the computed decision. The PEP should always enable the user to be able to fulfill her obligations, i.e. the general problem of accountability should be reduced to user accountability.
## Obligation Objects
To facilitate obligation policies, the notation of type-value pairs like
```json
{
"type": "Obligation",
"value": "log_event"
}
```
from the previous sections could be extended to an obligation object like
```json
// obligation object
{
"type": "Obligation",
"attribute_list": [
// name/id of obligation policy
{
"type": "ObligationName",
"value": "log_event"
},
// temporal type of obligation policy
{
"type": "ObligationType",
"value": "pre"
},
// target of the obligation policy
{
"type": "ObligationTarget",
"value": "resource"
},
// additional context data for obligation policy
{
"type": "ObligationContext",
"attribute_list": [
{
...
},
...
]
},
// circuit GoC for obligation policy
"obligation_goc": {
...
},
// circuit DoC for obligation policy
"obligation_doc": {
...
}
]
}
```
Next to an unique name or identifier `ObligationName` and the temporal type `ObligationType` for the obligation policy there are four more items contained in the obligation object. The circuits `obligation_goc` and `obligation_doc` are the compiled intermediate language representations of the obligation policy and their compilation is performed the same way as for policies themselves. The additional field `ObligationTarget` specifies the entity that must fulfill the obligation and the field for context information `ObligationContext` should only ever be used for things that can't be expressed by the $\accesscontrolname{}$ language, which basically means for states that can't be observed by the system.
Note, that the `obligation_goc` and `obligation_doc` circuits for obligations policies are not tied to either `obligation_grant` or `obligation_deny` circuits of the policy object. Instead both circuits `obligation_grant` and `obligation_deny` contain a list of obligation objects which in turn contain the above described circuits `obligation_goc` and `obligation_doc`. Therefore, the data structure of a policy object looks like the following:
- policy_object (object)
- policy_goc (circuit)
- policy_doc (circuit)
- obligation_grant (circuit)
- obligation_object (list of objects)
- ObligationName (field)
- ObligationType (field)
- ObligationTarget (field)
- ObligationContext (list)
- obligation_goc (circuit)
- obligation_doc (circuit)
- obligation_deny (circuit)
- obligation_object (list of objects)
- ObligationName (field)
- ObligationType (field)
- ObligationTarget (field)
- ObligationContext (list)
- obligation_goc (circuit)
- obligation_doc (circuit)
The obligation object must be normalized in the same way as the policy objects as formalized in [Attribute Store & Policy Store](https://hackmd.io/M2D0hXjsTOynEWFBzycikw).
## Generalized Policy Objects
Another important observation about obligations policies is, that they could in turn have obligations too, which would result in a cascade of obligations. This way, an obligation object can be seen as a policy object with additional information about name, type and context.
Hence, a uniform approach to policy and obligation objects leads to a generalized policy object with five components: the four circuits `policy_goc`, `policy_doc`, `obligation_grant`, `obligation_deny` and a list `context`. The obligation circuits themselves contain a list of obligation policies represented as generalized policy objects, which in turn can have obligations, etc. The `context` list of the outermost generalized policy object will be empty, whereas the `context` list of the inner generalized policy objects will contain information about the obligations.
The data structure of the generalized policy object is
- generalized_policy_object (object)
- context (empty list)
- policy_goc (circuit)
- policy_doc (circuit)
- obligation_grant (circuit)
- generalized_policy_object (list of objects)
- context (list)
- policy_goc (circuit)
- policy_doc(circuit)
- obligation_grant (circuit)
- ...
- obligation_deny (circuit)
- ...
- obligation_deny (circuit)
- generalized_policy_object (list of objects)
- context (list)
- policy_goc (circuit)
- policy_doc(circuit)
- obligation_grant (circuit)
- ...
- obligation_deny (circuit)
- ...
where the JSON representation will be
```json
// generalized policy object of the policy
{
// empty context list for the policy
"context": [],
// circuit GoC for the policy
"policy_goc": {
...
},
// circuit DoC for the policy
"policy_doc": {
...
},
// circuit GObl for the policy
"obligation_grant": {
// conditional branches containing lists of obligations
...
"obligations": [
// generalized policy object for the first grant-obligation policy
{
// context list for the obligation policy
"context": [
// name, type, target, etc
{
...
},
...
],
// circuit GoC for the obligation policy
"policy_goc": {
...
},
// circuit DoC for the obligation policy
"policy_doc": {
...
},
// circuit GObl for the obligation policy
"obligation_grant": {
...
// empty or
// further nested lists of obligations
...
},
// circuit DObl for the obligation policy
"obligation_deny": {
...
// empty or
// further nested lists of obligations
...
}
},
// generalized policy object for the second grant-obligation policy
{
...
},
...
]
...
},
// circuit DObl for the policy
"obligation_deny": {
// conditional branches containing lists of obligations
...
"obligations": [
// generalized policy object for the first deny-obligation policy
{
// context list for the obligation policy
"context": [
// name, type, target, etc
{
...
},
...
],
// circuit GoC for the obligation policy
"policy_goc": {
...
},
// circuit DoC for the obligation policy
"policy_doc": {
...
},
// circuit GObl for the obligation policy
"obligation_grant": {
...
// empty or
// further nested lists of obligations
...
},
// circuit DObl for the obligation policy
"obligation_deny": {
...
// empty or
// further nested lists of obligations
...
}
},
// generalized policy object for the second deny-obligation policy
{
...
},
...
]
...
}
}
```
The generalized policy object must be normalized in the same way as the policy objects as formalized in [Attribute Store & Policy Store](https://hackmd.io/M2D0hXjsTOynEWFBzycikw). We will give an example in the following section to illustrate the usability of the generalized policy object.
## Example
Picking up the example policy $q$ from the [Compilation of Policies with Obligations](https://hackmd.io/t5YMLzMCRQ2CEVEER2Vzpg) document, where
\begin{align*}
\goc{q} &= \left( Subj == \text{"}owner\text{"} \right) \\
\doc{q} &= \lnot\! \left( Subj == \text{"}owner\text{"} \right) \\
\gobl{q} &= \begin{cases}
\{\text{"}log\_event\text{"}\} & \text{if } \left( Subj == \text{"}owner\text{"} \right) \\
\{\,\} & \text{otherwise}
\end{cases} \\
\dobl{q} &= \{\,\}
\end{align*}
an obligation policy for logging the user access on granting constitutes an obligation for the `ObligationTarget` system/resource. Therefore, the PEP can check whether this obligation is fulfillable before issuing the final access decision.
The value of `ObligationType` may depend on the kind of resource and the intention of the policy writer. In case of just logging the access, e.g. reading a document, this can be written as a `pre` type obligation. But in the case of logging interactions with the resource during the access, e.g. writing in a document, this can be expressed by an `ongoing` obligation.
The obligation policy for $\{\text{"}log\_event\text{"}\}$ has to have a check whether a log entry for the respective identifiers is contained in the log file, e.g. by an unary membership operation. Time constraints (relative to the current time of the access request) might be written to prevent DoS attack vectors, otherwise the resource has arbitrary time to abide by the `pre` type obligation before granting access.
Here, we will consider a pre-obligation with a ten seconds time frame:
\begin{align*}
o &= \grant\ \ifrule\ \left( resource{.}log{.}isMember(entryID) \right. \\
& \qquad\qquad\qquad \left. \dand currentTime \leq (requestTime+10s) \right) \\
& \qquad \oplus\ \deny\ \ifrule\ \left( currentTime > (requestTime+10s) \right)
\end{align*}
The obligation policy $o$ yields $\grant$ if the log entry exists before the specified time has expired, it yields $\deny$ after the specified time has expired and it yields $\undefined$ otherwise. Here, $\oplus$ denotes the join operator in the information ordering, also called $\mergepol$ in the $\accesscontrolname{}$ yellow paper.
An empty obligation policy $e$ for $\{\,\}$ can be modeled as a constant $\grant$ policy, which is always fulfilled when the PEP monitors the pending obligations:
\begin{align*}
e = \grant
\end{align*}
Exploiting the logical equivalences for arbitrary policies $p_1$ and $p_2$ under an environment $\rho$ it holds
\begin{align*}
\goc{p_1 \oplus p_2} &= \goc{p_1} \dor \goc{p_2} & \doc{p_1 \oplus p_2} &= \doc{p_1} \dor \doc{p_2} \\
\goc{p_1 \otimes p_2} &= \goc{p_1} \dand \goc{p_2} & \doc{p_1 \otimes p_2} &= \doc{p_1} \dand \doc{p_2}
\end{align*}
with the information join $\oplus$ and the information meet $\otimes$. The compiled circuits for the obligation policies $o$ and $e$ are
\begin{align*}
\begin{split}
\goc{o} &= resource{.}log{.}isMember(entryID) \\
& \quad\dand currentTime \leq (requestTime+10s) \\
\doc{o} &= currentTime > (requestTime+10s) \\
\gobl{o} &= \{\,\} \\
\dobl{o} &= \{\,\}
\end{split}
\qquad\qquad
\begin{split}
\goc{e} &= \true \\
\doc{e} &= \false \\
\gobl{e} &= \{\,\} \\
\dobl{e} &= \{\,\}
\end{split}
\end{align*}
and the (simplified) JSON notation for the generalized policy object for policy $q$ looks like
```json
// generalized policy object for policy q
{
// empty context list for policy q
"context": [],
// circuit GoC(q) for policy q
"policy_goc": {
// subj==owner
"operation": "eq",
"attribute_list": [
{
"type": "Ed25519",
"value": "0x1234..."
},
{
"type": "request.subject.type",
"value": "request.subject.value"
}
]
},
// circuit DoC(q) for policy q
"policy_doc": {
// not(subj==owner)
"operation": "not",
"attribute_list": [
{
"operation": "eq",
"attribute_list": [
{
"type": "Ed25519",
"value": "0x1234..."
},
{
"type": "request.subject.type",
"value": "request.subject.value"
}
]
}
]
},
// circuit GObl(q) for policy q
"obligation_grant": {
"operation": "if",
"attribute_list": [
// if-condition: subj==owner
{
"operation": "eq",
"attribute_list": [
{
"type": "Ed25519",
"value": "0x1234..."
},
{
"type": "request.subject.type",
"value": "request.subject.value"
}
]
},
// if-statement: obligation policy o
{
"obligations": [
// generalized policy object for obligation policy o
{
// context for obligation policy o
"context": [
{
"type": "ObligationName",
"value": "log_event"
},
{
"type": "ObligationType",
"value": "pre"
},
{
"type": "ObligationTarget",
"value": "resource"
}
],
// circuit GoC(o) for obligation policy o
"policy_goc": {
"operation": "and",
"attribute_list": [
// 1st and-term: isMember(entryID)
{
"operation": "isMember",
"attribute_list": [
{
"type": "resource.log.type",
"value": "resource.log.value"
},
{
"type": "String",
"value": "entryID"
}
]
},
// 2nd and-term: currentTime <= requestTime+10s
{
"operation": "lte",
"attribute_list": [
{
"type": "resource.time.type",
"value": "resource.time.value"
},
{
"operation": "add",
"attribute_list": [
{
"type": "request.context.time.type",
"value": "request.context.time.value"
},
{
"type": "Time",
"value": "000010"
}
]
}
]
}
// end of and
]
},
// circuit DoC(o) for obligation policy o
"policy_doc": {
// currentTime > requestTime+10s
"operation": "gt"
"attribute_list": [
{
"type": "resource.time.type",
"value": "resource.time.value"
},
{
"operation": "add",
"attribute_list": [
{
"type": "request.context.time.type",
"value": "request.context.time.value"
},
{
"type": "Time",
"value": "000010"
}
]
}
]
},
// empty circuit GObl(o) for obligation policy o
"obligation_grant": {},
// empty circuit DObl(o) for obligation policy o
"obligation_deny": {}
}
]
},
// else-statement: obligation policy e
{
"obligations": [
// generalized policy object for obligation policy e
{
// context for obligation policy e
"context": [
{
"type": "ObligationName",
"value": "empty"
},
{
"type": "ObligationType",
"value": "pre"
},
{
"type": "ObligationTarget",
"value": "resource"
}
],
// circuit GoC(e) for oblgation policy e
"policy_goc": {
"type": "Boolean",
"value": "true"
},
// circuit DoC(e) for obligation policy e
"policy_doc": {
"type": "Boolean",
"value": "false"
},
// empty circuit GObl(e) for obligation policy e
"obligation_grant": {},
// empty circuit DObl(e) for obligation policy e
"obligation_deny": {}
}
]
}
// end of if
]
},
// circuit DObl(q) for policy q
"obligation_deny": {
"obligations": [
// generalized policy object for obligation policy e
{
// context for obligation policy e
"context": [
{
"type": "ObligationName",
"value": "empty"
},
{
"type": "ObligationType",
"value": "pre"
},
{
"type": "ObligationTarget",
"value": "resource"
}
],
// circuit GoC(e) for oblgation policy e
"policy_goc": {
"type": "Boolean",
"value": "true"
},
// circuit DoC(e) for obligation policy e
"policy_doc": {
"type": "Boolean",
"value": "false"
},
// empty circuit GObl(e) for obligation policy e
"obligation_grant": {},
// empty circuit DObl(e) for obligation policy e
"obligation_deny": {}
}
]
}
}
```
Note, that we need to allow for empty circuits `obligation_grant` and `obligation_deny` if there are no obligations attached to an obligation policy. Otherwise we would run into a infinite cascade of circuits. This is not a restriction, but it merely reflects the intention of empty obligations in the $\accesscontrolname{}$ language. The policy object for the "empty" obligation policy $e$ on the other hand cannot be omitted, since it is part of the if-clause of the non-empty obligations for policy $q$. (However, this could be short-circuited by defining if-clauses without an else-branch as having the generalized policy object for the empty obligation policy $e$ in the omitted else-branch. Also, an obligation circuit containing only the generalized policy object for the empty obligation policy $e$ could be left void.) That means, *generalized policy objects* and *policy circuits* must never be empty, but (inner) *obligation circuits* and (outer) *contexts* may be empty.
An access request by the owner of the resource then results in a $\grant$ decision by the PDP, which is returned to the PEP together with its respective obligation to log the event. Then the obligation monitor of the PEP periodically checks with the PDP, e.g. every fraction of a second, if the obligation policy yields $\grant$ and then in turn grants access for the user (based on the decision of the PDP as well as the fulfillment of the obligation). While the obligation policy yields $\undefined$ the PEP keeps on monitoring the obligation and keeps the final decision on the access request on hold. When the obligations policy yields $\deny$ the PEP in turn denies access for the user (based on the violation of the obligation, even though it is overwriting the decision of the PDP).