There has been a lot of talk lately in the Federated vs Distributed environments.
I therefore created a page to try to explain why a Federated environment is usually (but not always) better than a completely distributed one, the strengths and weaknesses of both architectures.
The short version is: today "distributed" means non-interoperable, slow and lack of control. While this can be good for systems that seek anonymity, it is be very bad for other applications, especially commercial ones.
This does not mean that Fenrir can not be used to build distributed systems. The flexibility of this protocol allows you to build non-federated, distributed protocols.
Once you have read the Authentication Details, you can understand how Fenrir creates secure channels.
But what is the data that is exchanged, and how do federated environments interact?
When needed we will use these abbreviations:
- AS: Authentication Server
- S: Service
- A: Application
- C: Client Manager
In our federated examples, the client from example.org will connect to example.com (note the different TLD)
each client must have:
- client id: 128bit, randomly generated by the client only once on its very first setup, then saved somewhere.
- tokens: random 128bit, used for authentication and authorization.
- authorization type: one per token: 1 byte to limit the users' privileges.
The tokens (one per device/service) will be given by the AS to the client manager after the first login.
Fenrir supports authentication, but how is authorization different?
Authorization defines the set of privileges that a user can have.
Usually when we login somewhere we have complete access to the action that user can do -- This is authentication without authorization, or just a binary authorization.
In OAuth and other protocols the concept of authorization is introduced to limit what the user can do with that authenticated connection.
If we apply the authorization to a scenario where the client can connect multiple times with multiple applications or devices, we can easily imagine that we might want one application to have some rights (example: read-only), while an other might have full access.
Think about your bank account: you might want full access on your computer, but your phone might be better off with just read-only data, as it is easily lost.
Introducing the Authorization Lattice
The new concept introduced in Fenrir is that of an authorization lattice: we use a Lattice to group the possible privileges in a hierarchal way, so that a user can always limit himself, but can not get higher authorization than what he was given.
Take this authorization lattice for example:
Recall that in a client device we find a Client Manager and the applications. The Client Manager manages the tokens, the applications only receive connection data.
When a client is issued a token, each token is tied to an authorization.
Let's consider a token which is tied to the "Modify" authorization in the lattice above.
Since a token is bounded to the "modify" authorization, during authentication the client can say he has this token for the "modify" authorization, but he wants a limited authorization a lower level of the lattice ("read" or "bottom" in the example).
After checking that the token is valid and the client isn't asking for more authorization that his token can grant, the AS proceeds with authorizing the connection.
This means that the user will be able to limit the maximum privilege usable by a device, and then the Client Manager can further limit the privilege before authorizing the application.
By this system we can force an application down to a certain privilege. Without this system the most we could do would be to hope that the application automatically limits itself and does not do more than we asked.
And the management of the privileges will all be in the hands of the end user, not on a third party or a developer.
The whole authentication works more or less like this:
In a successful communication setup this happens:
C sends to AS:
- authentication data (user/token)
- client id
- authorization type
AS verifies the information and sends to the Service:
- user id, authorization type.
S sends back to the AS:
- encryption keys
- connection id
AS sends to the client:
- encryption keys, connection id
- Service ip, port etc...
- the C will give to the application:
- encryption keys
- Service ip, port etc...
- authorization type
- the application can now connect to the service.
Backup trust / hack safety
This is a simplified view. The full algorithm includes shared secrets between C and AS and between C and S.
These shared secrets act as a backup safety for the user. If the authentication server is compromised, the shared secret between the C and the S will ensure the safety of the user data. If the trust system (in our case, DNSSEC) is somehow compromised, the shared secret between the C and the AS will make it impossible for the attacker to MITM the connection or impersonate the AS
different domain authentication
Assuming C and AS are in the same domain, and AS2 and S2 are in a different domain:
- C asks to his AS new tokens for the service S2, which is in an other domain.
- AS gives back a token
- C uses the token to authenticate with AS2, in the other domain, asking for service S2
- AS and AS2 verify the token, AS2 might send the service lattice to AS
- AS2 informs S2 of a new users, and gets back the encryption keys and connection information
- AS2 sends the service data to C
- C can connect to the S2
This lattice management means that the service has to synchronize the authorization lattice with all the Authentication Servers that play a role in the authentication and with the client.
While this is not a big problem inter-domain, it can be a little problem in intra-domain setups.
The lattice will be transferred as a list of:
- one byte: lattice version
- one byte: number X of nodes (max:64)
- X 64 bit bitmask to represent connections between nodes
- X null-terminated strings (max: 25 char) as node label
This means that a full lattice weights 2+864+6425 = 2114 bytes, which is 2 ethernet packets at maximum.
The problem of lattice versions is taken care of with the "lattice version" byte, although I still have to think about how to convert a token from one lattice version to the other. (suggestions?)
The lattice distribution is done the first time a client connects to a service. Since it is the first time, we can authenticate and assume that the user has full access ("top"), but as soon as we have authenticated we transfer the lattice to the client.