Distributed authorization with RavenDB
The question came up in a somewhat unrelated discussion, about the RavenDB authorization bundle usage:
I have an 'Account' service which is responsible for managing all things 'user'.
I have a 'Messaging' service which is responsible for all things 'messaging' i.e. wall posts, conversations etc.My question is this:
- Should the account service store the master User with Roles and Permissions - when it is asked for a user it can send back a dto with the roles and permissions (could get chunky)
- Should the Messaging Service maintain it's own copy of a User - with it's own set of roles and permissions?
I wasn’t sure what to answer, because a lot depended on the actual physical infrastructure of the system. But after some back & forth, it turned out that those were true services, in other words, they were independent from one another and each had its own data store.
That completely ruled out the first possibility, we don’t want to have to rely on another service for something that is as central for our service as authorization. The other option, of having each service (there are currently 5, all total) maintain their own users, is fraught with the potential for disaster.
Instead, a better option is to simply replicate the relevant parts from the Account’s service database to the related services. The authorization bundle record information about users, roles & permissions, that allows us to create the following data storage scheme for the Account database. Actually, we are talking about two different databases in the Account database instance:
- Accounts – All the application specific account information
- Permissions – All the authorization information
We setup RavenDB replication from the Account.Permissions database to each of the services databases, that means that any change to permission will be replicated to all the related databases.
For each service, we treat the authorization information as usual, and we get cross service, background replicated, fully distributed authorization system that can make authorization decisions without touching any external data source.
Let us take the example of viewing a message:
- Jane sends a message on Joe’s wall (which should only be visible to Joe’s friends). The new message is written to the Messages database.
- Drew then befriends Joe. That means that we setup the friendships on the Accounts database and the permissions on the Permissions database.
- The information on the Permissions database then replicates to the Messages database.
- The next query to the Messages database will make the authorization decisions locally, against its own copy, but it will get the new permissions and show Jane’s message to Drew.
That is quite elegant, even if I say so myself.
Comments
I'm grinning ear to ear - that is soooooo elegant - even if i say so myself!!
love it!!
:)
Wouldn't this method of replicating the actual data store become somehow unmanageable if you have a more than trivial number of services or if authentication and authorization logic is based on business rules and data written in code?
I am thinking that it would become quite expensive to maintain the same or different logic against all services. For example, I want to block access to three services for all users younger than 18 years old. Maybe the Accounts datastore just stores the birthdate and the authorization service needs to compute the age of the user. Wouldn't this mean that I need to change all three services application code in order to implement this rule?
Another point to challenge would be the "enterprise rules", where you are not allowed to distribute potentially sensitive data like Accounts to any backend system even if it belongs to you.
Robert,
In most cases, the number of services is limited, a service is an organization function, and they don't have a lot.
The auth logic is the same, it is a shared dll used everywhere.
As for the data you are replicating, you aren't replicating personal info, you are replicating permissions info
re: "enterprise rules" - in some cases you are required to shard sensitive data.
This kind of reminds me of two bounded contexts that could be "related" through some messaging and events. Couldn't the situation be handled that way?
What is done in here is an ETL integrated straight into a db engine, isn't? No external messaging systems needed. Pure pub/sub by specifying what should be published where. Nice
Comment preview