Closed StephenOTT closed 3 years ago
This can be done via Interceptors.
For instance, the Response Interceptor userPwdRemover removes the password field from GET /users
It is easy to make a similar one that applies different filtering logic depending on the user role that can be retrieved with request.getAuthenticatedAccount().getRoles()
.
The interceptor could also modify the projection qparam of the request request.getProjectionDocument()
forcing the projection to apply on the MongoDB find()
Similarly, a REQUEST_AFTER_AUTH Interceptor can forbid write request containing some fields depending on the user role.
if (request.getContent().asDocument().containsKey("protected") && !request.getAuthenticatedAccount().getRoles().contains("ADMIN")) {
response.setInError(true);
response.setStatusCode(403);
return;
}
A generic role-based fields filtering Interceptor and a role-based request content checker can be implemented simplifying your use-case. Maybe handling the configuration directly in the ACL document of the mongoAclAuthorizer. This would be super useful!
{
"_id": { "$oid": "5d9485639eab3a852d48a1de" },
"predicate": "path-prefix[/blog] and (method[GET] or method[POST])",
"roles": ["editor"],
"priority": 1,
"readFilter": null,
"writeFilter": null,
"project": {"protected", 0} <------
"forbid": [ "protected", "subdoc.protected"] <------
}
it seems to be the missing feature in RestHeart to make the API more end-user friendly / not leaking data. Building public facing APIs directly with RH has the flaw of exposing all fields and opening all fields up to edit at the moment. So ya super useful to add this restriction!
How would you handle project/forbid rules in a ACL with multiple matching ACL rules?
ok we will do it!
only one ACL permission is taken into account per each request. this is controlled by the field priority
. if more that one rule have same priority, the first one is taken into account (first one means document with bigger _id
)
with loglevel=DEBUG the matching permissions (role+matching predicate) are logged highlighting which one applied.
Added this enhancement to the roadmap for 5.3.
Hi @StephenOTT
I just pushed an improvement that makes easy filtering responses, authorizing requests by checking the json body and modifying the request content on the server-side.
you can try it either building from sources or with docker:
$ docker pull softinstigate/restheart:82bc66b
This will be available on the next stable release 6.0
The following is an example of permission on a POST request that uses
mongo.mergeRequest
option to force some server-side valued properties (for instance sets the author
property equal to the userid, "author": "@user.userid"
)bson-request-whitelist
and bson-request-contains
to check the request content # allow role 'user' to create documents under /{userid}
# the request content must contain 'title' and 'content' <- bson-request-contains(title, content)
# the request content cannot contain any property other than 'title' and 'content' <- bson-request-whitelist(title, content)
# no qparams can be specified <- qparams-whitelist()
# the property 'author' and 'status' are added to the request at server-side <- mergeRequest
# the property 'log' with some request values is added to the request at server-side <- mergeRequest
- roles: [ user ]
predicate: >
method(POST)
and path-template('/{userid}')
and equals(@user.userid, ${userid})
and bson-request-whitelist(title, content)
and bson-request-contains(title, content)
and qparams-whitelist()
priority: 100
mongo:
mergeRequest: >
{"author": "@user.userid", "status": "draft", "log": "@request"}
The following is an example of permission that uses the mongo.projectResponse
option to filter out the property log
from the response (you can also use { "public": 1 }
to just return the listed properties)
# allow role 'user' GET document from /{userid}
# a read filter apply, so only document with status=public or author=userid are returned <- readFilter
# must use 'page' qparam <- qparams-contain(page)
# cannot use 'filter' and 'sort' qparams <- qparams-blacklist(filter, sort)
# the property 'log' is removed from the response <- projectResponse
- roles: [ user ]
predicate: >
method(GET)
and path-template('/{userid}')
and equals(@user.userid, ${userid})
and qparams-contain(page)
and qparams-blacklist(filter, sort)
priority: 100
mongo:
readFilter: >
{ "$or": [
{"status": "public"},
{"author": "@user.userid" }
]}
projectResponse: >
{ "log": 0 }
Is there the current ability to create projection rules and schemas specific to a role/authorization against a collection?
It would seem to be a key feature: Where a document has administrative and user viewable properties: where some fields should not be shared with the authorized user, and they can edit specific fields.
Likely some sort list of field access restrictions per role, which impact default projections and user's ability to request fields
similar to something like: https://github.com/gethuman/fakeblock or something like wrapping filters in redaction rules?
Thanks!