crossbario / crossbar

Crossbar.io - WAMP application router
https://crossbar.io/
Other
2.05k stars 274 forks source link

Implement caching for dynamic authorizers #212

Open oberstet opened 9 years ago

oberstet commented 9 years ago

The docs currently read:

For WAMP sessions using custom authorization, Crossbar.io maintains a permissions cache for that session. When a client wants to perform an interaction, it will look into the cache, and only upon a cache miss ask the custom authorization function to determine the permissions.

However, no caching is currently implemented.

If we add caching, apps need mechanisms:

The latter would be a meta procedure. The former would probably best be done by allowing to return not only true or false from a dynamic authorizer, but an object:

{"allow": true, "cache": false}

This is an API break. It also needs adjusting the WAMP AP spec.

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/7882137-implement-caching-for-dynamic-authorizers?utm_campaign=plugin&utm_content=tracker%2F462544&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F462544&utm_medium=issues&utm_source=github).
goeddea commented 9 years ago

removed reference to caching in the documentation

oberstet commented 7 years ago

Dynamic authorizers already can return a cache indicator flag ({"allow": true, "cache": false}) - it only needs implementation;)

ecorm commented 6 years ago

It should be noted that the lack of this cache significantly increases the wire traffic between Crossbar and backend components wanting to do dynamic authorization. For each incoming CALL message from the frontend, there is an additional dynamic authorization RPC round trip involved. SUBSCRIBE messages from the front end wouldn't be so bad due to their infrequent nature.

Purging the authorization cache is crucial for when the application changes access control permissions for its users/roles. Consider allowing the purging to be selective (by session, authid, or authrole) so that the entire cache isn't needlessly flushed.

oberstet commented 6 years ago

@ecorm not true in this generality: eg when the dynamic authorizer runs side-by-side/embedded in the router, there isn't any wire at all (or the wire is logical): boils down to in-process function calls.

when the authorizer runs out-of-process, but eg via UDS, the "wire" is a byte buffer in the kernel.

but yes, when the authorizer runs out-of-process on a different machine, then there is a wire, and there is traffic ..

oberstet commented 6 years ago

purging based on authrole, yes, purging based on session/authid: no.

the latter isn't relevant for authorization. Crossbar.io (by design) authorizes an action (eg subscribe) only based on realm and role (and the details of the action), NOT based on session or authid.

if you want to do the latter, you need to implement authorization within the endpoints (eg procedure being called) itself.

as said: by design.

ecorm commented 6 years ago

Authorization per authid is indeed relevant for our project, because we've implemented our own Role Based Access Control (RBAC) scheme that can be changed at runtime. Our application requires that user roles be created/updated/removed dynamically at runtime. Furthermore, users can be assigned to multiple roles.

As you can see, we can't use Crossbar's authroles for this purpose. Instead, we're planning on using Crossbar's authroles as a way of classifying sessions as frontend or backend.

I don't see why we couldn't do per-authid access control within our custom dynamic authorizer, as long as we're willing to live without caching. After all, we have access to the authid string within the passed-in session object.

I thought about implementing procedure call authorization within our backend RPC handlers, but we'd end up having to synchronize a table of {session_id, authid} pairs with Crossbar, and force Caller Identification on every frontend call. We could use wamp.session.on_join but I'm worried about the race condition of the frontend calling a procedure immediately after joining.

Another problem is that our RBAC scheme also applies to pubsub events. There are events that only certain user roles have permission to subscribe to (in order to safeguard against information leakage). I can't think of a sane way to perform access control on event subscriptions without using the dynamic authorization mechanism. We can't rely on calling wamp.subscription.remove_subscriber in response to wamp.subscription.on_subscribe because there's a brief window in which an unauthorized user can listen to events they don't have access to.


TL;DR: Whatever you do, please retain the possibility of disabling the cache if it stores the results on a per-authrole basis. This is to allow the possibility of applications performing per-authid access control using the dynamic authorizer.

ecorm commented 6 years ago

It appears my fear of a race condition was valid: #479

haizaar commented 6 years ago

@ecorm, I'm in the same boat with highly dynamic access control environment, so I'm planning to implement dynamic authn/z for everything as well. I did a POC so far, but didn't test it in scale.

Can you please share your experience?