-
Notifications
You must be signed in to change notification settings - Fork 2
Policy Endpoints #57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/policy-endpoint
Are you sure you want to change the base?
Policy Endpoints #57
Conversation
Some APIs might need non-JSON/form input, this allows this possibility. In the future we probably want a more generic solution, but for now this at least allows the possibility.
Due to the RoutedHttpRequestHandler catching unsupported requests with a default handler, it was impossible to combine multiple with a WaterfallHandler. This is now solved by moving most of the behaviour to the canHandle, and having a static throw handler for the 404.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work so far.
Some small changes would help.
After the changes, we can start with DELETE, and then with update (sparql update for patch and complete policy rewriting with PUT)
This prevents Components.js build errors
When looking into contracts in the future, this should be handled in a more robust way.
See the comment in AuxiliaryModesExtractor.ts for more details. This allows policies on resources to also apply to their auxiliary resources, such as .meta resources.
This includes derived resources, which is referenced in the demo setup, but not used in the example script. This can be re-added in the future should it be required.
For some reason, tsx could not exit gracefully when running these. Either it got stuck, or exited but left the process running. These issues did not occur with ts-node, but the solution in this commit seemed more acceptable than having a new dependency. Future work could include investigating if this is an issue with the server.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some small remarks on the docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a small amount of nit picks, but in general it looks really good!
If these are resolved, I think this PR can be merged.
The checkboxes and comments from the docs that are still unresolved by then should become issues then
The PUT works as a combination of DELETE and POST. It requires a body with the same content type as the [POST request](#creating-policies). This body will be interpreted as the requested policy with some rules. | ||
|
||
The PUT process: | ||
1. Find information about the policy. If it does not exist, return with a **status code 400** to indicate that you cannot rewrite a nonexistent policy. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I read this now, I am not 100% if this is the behaviour we want.
Either we allow PUT to create a resource if it does not exist yet (following the POST method).
Or we use a 404, as we performed a GET request and did not find any resource.
By typing this out, I think creating the resource (given that the identifier in the policy and the PUT policy-id match).
I would also argue similar behaviour with PATCH if the resource does not exist.
Perhaps @joachimvh has another opinion?
2. The content type of the body gets validated. The content-type must be set to `application/sparql-query`. Any other type will result in a response with **status code 400**. | ||
3. We use the policy information to create a store which only contains groups **(1)**, **(3)** and **(4)** as explained [above](#get-one-policy). This will serve as an isolated store, on which we can execute the update query. This implementation has its advantages: | ||
- We do not need to validate the sparql query, since we execute it on an isolated store. | ||
- Performing DELETE queries on rules out of your scope will simply not work, since they are not part of the isolated store. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that nothing then will happen?
I understand it as such and think that is valid behaviour.
Some operations require the client to specify a policy ID in the URL. Since policy ID's might contain reserved characters (e.g. `/`, `:`, ...), we have chosen to encode them with the builtin [`encodeURIComponent()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent). Using this method, reserved characters will be converted to their respective UTF-8 encodings. | ||
|
||
## Testing | ||
The current implementation is tested only by the script in `scripts\test-uma-ODRL-policy.ts`. This script tests every implemented endpoint with a designated flow. Since the script initiates with an empty storage, and there is no endpoint or other way to seed it, the first requests must test the POST endpoint. These tests are designed to ensure that the storage is filled. After the POST tests, the access endpoints can be tested. Every endpoint gets tested in this script, which makes sure that the added data is removed. The current testing will be replaced with proper unit tests in the near future. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and integrations tests of course :)
@@ -20,4 +20,7 @@ export interface UCRulesStorage { | |||
* @returns | |||
*/ | |||
deleteRule: (identifier: string) => Promise<void>; | |||
|
|||
// Experimental endpoint | |||
deleteRuleFromPolicy: (ruleID: string, PolicyID: string) => Promise<void>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the implementation, it seems like it deletes the usage control rule and its reference. Could you update the documentation as such?
Also remove the fact that it is experimental. At some point it will have unit tests and thus will not be experimental.
Could you also update the updateRule definition explaining that it does not delete the reference from policies?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this an artefact of using the earliest POST method in combination with the FileStorage solution?
If so, I think this can be removed
|
||
// 2. Retrieve the Policy Body | ||
const contentType = request.headers['content-type']; | ||
if (!/(?:application\/sparql-update)$/i.test(contentType)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it might be useful to use this utility for parsing the content type?
https://github.com/CommunitySolidServer/CommunitySolidServer/blob/main/src/util/HeaderUtil.ts#L381
The CSS is a dependency anyway
// Sanitization | ||
sanitizeRule(policyStore, clientId); | ||
|
||
// 3.1 Check that the other rules are unchanged | ||
const newState = getPolicyInfo(policyId, policyStore, clientId); | ||
if (newState.otherRules.length !== 0 || newState.otherPolicyRules.length !== 0) | ||
throw new BadRequestHttpError("Update not allowed: attempted to modify rules not owned by client"); | ||
|
||
// 3.2 Check that only Policy/Rule changing quads are introduced and removed | ||
// The only modifications we allow are policy definitions, policy rules that define owned rules and owned rules themselves | ||
const newQuads = policyStore.getQuads(null, null, null, null); | ||
if (newQuads.length - newState.ownedRules.length - newState.ownedPolicyRules.length - newState.policyDefinitions.length | ||
!== initialQuads.length - ownedPolicyRules.length - ownedRules.length - policyDefinitions.length) | ||
throw new BadRequestHttpError("Update not allowed: this query introduces quads that have nothing to do with the policy/rules you own"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these sanitisation checks the same as the ones of rewritepolicies?
If so, maybe it is better to create a util function out of it that is re-used both here and in rewrite
Draft PR
To keep up with progress
Documentation is found within
docs/policy-management.md