Closed N247S closed 1 year ago
Interesting. So not totally sure I understand all the constraints you have - however I have been working on a feature that will provide an API for applications to modify a requests/users permissions based on arbitrary metadata (the example I have implemented adds a permission 'fs_tf_setup' if the user has correctly set up two-factor auth.
Now - it is always worth separating authentication from authorization. Sounds like you are building a web app and are fine with using sessions as the method to authenticate. What isn't clear in your writeup is how and who decides which permissions to give a given user - you say 'managed by the user' - so do they log in (with all permissions the admin has granted them) and then request an accesstoken with fewer permissions? Are you trying to emulate oauth scopes?
So I think you want to be focusing on the authorization side (Permissions_required, roles_required). You could create a accesstoken and store that in the session and use that to populate the users permissions. You could add:
identity_loaded.connect_via(app)(_on_identity_loaded)
and in your _on_identity_loaded use the token to populate permissions - then the normal Flask-Security decorators could still be used. Look in Flask-Security-Too::core.py at what we do on identity load (not sure the order flask will call these in).
The feature I am working on basically adds a formal way to callout from _on_identity_loaded to application code..
Sorry - a bit rambling ...
Thanks for your response.
To clarify a bit, I have 2 separate portions of the web-app.
The latter I want to be as restricted as possible, and is where I would like to use the accesstoken
mechanism for.
Not sure if that fits the oauth-scope idea? I thought that was mostly part of unified-signin?
Anyways, the identity_loaded
portion is trivial for authorization I agree. But it is the authentication I want to keep separated in both mentioned portions. Especially because the second portion is 'session-less' I don't see how using a token for identity-population would be enough? Maybe I am overthinking this a bit
Not sure if this information makes more sence? Otherwise feel free to ask.
Ps. don't be sorry for 'rambling'. Any input is apreciated!
Ok - here is a thought - of course FS supports auth_tokens as a std authentication mechanism. So if I understand - if a user authenticates with an authtoken they should get different (less) permissions than if they authenticate via a web-session; and those permissions are specified/stored in the DB per user and don't have to be part of the auth token itself...
If so - then what might work is that in your identity_loaded method you could do:
if get_request_attr("fs_authn_via") == "token": adjust permissions as needed
Note that the user will already been granted the permissions as specified in their roles so you might have to remove some permissions... In this case the authentication will happen as part of the _request_loader, and you will have a chance to set the identities permissions PRIOR to any of the authorization decorators from being run.
Thanks again for your response.
That would work if the permission set was either fixed, or if only a single accesstoken was allowed. Also wouldn't this mess with the default token
authentication?
In any case, I added the accesstoken specs to the original question.
Rewriting this comment from this morning (coffee has kicked in).
You can overload UserMixin::get_auth_token and verify_auth_token - and you should be able to add additional pieces to the authtoken as returned by Flask-Security. In verify_auth_token() you can check for your expiration, etc constraints.
verify_auth_token could de-code the authtoken and place whatever additional stuff you put in there onto 'g' so that _on_identity_loaded could grab it and set/unset appropriate permissions.
Thanks for the response, sorry I couldn't get back earlier.
That could work. I have to be carefull though not ot mess up the normal 'token' mechanisms. I'll try several things and see what works best.
Thanks for your input!
If you have more questions - please open a discussion....
Goodday everyone,
I tried to add accesstokens which can be managed by the user to have a specific/limited set of permissions assigned to them (basically
POLP
). My current setup is to have a separate database-table for the accesstokens which have a reference to the original user. I extend the defaultUserMixin
model so aaccesstoken
can be used as a user in code. A customidentity_loaded
singal can provide the correct permissions this way.The problem is the authentication of a
accesstoken
is obviously different compared to a real user. Intergrating this feel like I am monkey-patching a lot of the default authn-mechanism which I want to keep in tact forreal users
. There is no way to configure it per user-type/user-model, which means I have to make several work-arounds.Basically I would prefer it would only use the session-less
token
authn-mechanism, but since that mechanism is hardcoded to compare thefs_uniquifier
/fs_token_uniquifier
property and is session/time based, it is not really usable for theaccesstoken
mechanism without modification.Option 1
One way of achieving something closely to this is by overriding the
request_loader
from theLoginManager
. That also mean thefreshness timers
are updated when usingauth_required
unless I override thesession_interface
. Besides it means I have to disable thecsrf
mechanism by flaggingfs_ignore_csrf
. In short, it is doable but feels like it is prone to messing up intended security-mechanisms unintentionally.Option 2
A different way is patching the
auth_required
(and alike) decorators. Since a customauthn-mechanism
cannot be used as the 3 supported mechanisms are hardcoded I have to create my own version. One which would leave the default machanisms intact, but also offer authentication specifically for theaccesstokens
. That would mean it is less dynamic (as one would have to specifically use my version ofauthn_required
to support theaccesstokens
.AcessToken specs
valid_untill
,inactivity_expire
)The question; what would be the better approuch, or is there something I have missed? I feel like the second option would be the better option if 'custom authn-mechanisms' are possible (not sure if there is a PR for it). Would love to hear any input on this.