Distributed workflow has to be the most complex use case to secure. In it you could have multiple participants being coordinated both synchronously and asynchronously. All forwarding and distributing information and data in between each other. All needing to trust one another. If you could define a relatively scalable and simple solution for workflow, you’d have something that would work in less complex scenarios.
The hub and spoke model that seems to be popular involves a central identity management provider (IDP) that participants ping to authenticate requests and to receive security information. The biggest problem I foresee with this approach is that the IDP becomes a central point of failure. The IDP needs to be available for applications to work. It needs to be on the same network. There’s a lot of extra distributed requests that need to be made.
All these problems bring me to thinking about the stateless principle of REST. RESTful services can have state, but not session state. The idea is that session state travels with the request. Could we do something similar with security information? Sure why not! How could you trust the integrity of such information? Digital Signatures. I’m sure there are protocols out there that have thought of similar ideas, but its cool to think things out for yourself. If your ideas match a particular existing protocol or specification you know you’re on the right track. The idea have have works as follows.
Let’s pretend we have a User named Bill that wants to interact with a Travel Agent service that will buy a ticket for him on an airline, reserve an airport taxi, and reserve a hotel room. So, Bill is interacting with the Travel Agent directly. The Travel Agent is acting on behalf of Bill when it interacts with the airline, taxi, and hotel services. The airline, tax, and hotel have to trust both the travel agent and Bill.
Step 1: Bill authenticates with an IDP saying he wants to interact with the Travel Agent. The IDP returns metadata that specifies both Bill’s and the Travel Agent’s permissions for all the interactions that must take place. It also returns the public keys for Bill and the Agent. The IDP digitally signs all this information using its private key.
Step 2: Bill sends a reservation request to the Travel Agent service. Bill signs the request including the signed permissions and keys provided by the IDP. Here’s what the request might look like:
POST /travel Host: travelagent.com Content-Type: application/reservation+xml Authorization: doseta-auth user=bill;h=Visa:Permissions:Public-Keys:Host;verb=POST;path=/travel;bh=...;b=... Visa: initiator=bill;h=Permissions:Public-Keys;d=idp.com;b=... Permissions: bill="agent hotel airline taxi"; agent="reserve-hotel reserve-taxi reserve-flight" Public-Keys: bill=23412341234;agent=3423412341234 <reservation>...</reservation>
Step 3: The Travel Agent authenticates and authorizes Bill’s request. The Authorization header contains metadata that is signed by Bill. The metadata signed by bill is the HTTP verb and path of the request (POST and /travel), and the hash of the XML posted by the request, as well as the Visa, Permissions, and Public-Key headers included within the request. The Travel Agent verifies this signed metadata by finding and using Bill’s public key in the transmitted Public-Keys header. If the signature passes, then the Travel Agent knows that Bill sent the request. But….It does not know yet if Bill is a trusted identity.
Step 4: How does the Travel Agent know Bill is a valid person? How does it know that Bill is allowed to make a reservation? To answer these questions, the Travel Agent first looks at the transmitted Visa header. What it boils down to is that the Travel Agent only trusts the IDP. The Visa header was generated by the IDP and is a digital signing of the Permissions and Public-Keys header. The IDP through the Visa header tells the Agent the permissions involved with the request and who will participate in the overall interaction. The Agent only needs to know the IDP’s public key prior to the request being initiated. So, the Agent verifies the digital signed Visa header using the stored public key of the IDP. A successful verification also means that the Agent can trust that Bill initiated the request. It can then look at the Permissions header to determine whether or not Bill is allowed to perform the action.
Step 5: Next the Travel Agent needs to interact with the Airline, Hotel and Taxi services on behalf of Bill. Here’s what a request to the Airline might look like.
POST /flights/tickets Host: airline.com Content-Type: application/ticket-purchase+xml Authorization: doseta-auth user=agent;h=Visa:Permissions:Public-Keys:Host;verb=POST;path=/flights/tickets;bh=...;b=... Visa: initiator=bill;h=Permissions:Public-Keys;d=idp.com;b=... Permissions: bill="agent hotel airline taxi"; agent="reserve-hotel reserve-taxi reserve-flight" Public-Keys: bill=23412341234;agent=3423412341234 <purchase>...</purchase>
You’ll notice that the Visa, Permissions, and Public-Keys headers are the same values as the original request made by Bill. The Authorization header is different as the Travel Agent is making the request. The airline services does authentication and authorization of the Agent’s request the same exact way the Agent did for Bill’s request. Again, the key part of this is that only the IDP is trusted and only the IDP’s public key needs to be known ahead of time.
Disclaimer, I’m new to security so dealing and thinking about attacks is new to me. Generally a lot of attacks can be prevented by specifying a timestamp and expiration with each sign piece of data. Services can refuse to honor old requests. Nonces could also be included within signature metadata to avoid replays.
User’s Private Key is compromised
User’s authentication with the IDP doesn’t have to be key based. It could be TOTP based where the user has to login through his browser providing a password along with a device-generated time-based key. The IDP could then return a temporary private key the client uses to sign requests.
IDP’s Private Key is compromised
This is a scary one. Maybe it could be prevented by requiring and acquiring Visa’s from multiple IDPs? A service would verify signatures from two or more IDPs. The probability of more than one IDP’s private key being compromised becomes less and less the more IDPs you have involved with the interadtion.
So here’s a summary of this brainstormed protocol:
- The Public-Keys header’s purpose is two-fold. First, its a list of public keys. More importantly it is a list of principles that are involved with the interaction.
- The Permissions header is a list of permissions of each principle involved for each service they will interact with.
- The Visa header is a digital signature of the Public-Keys and Permissions header. It also will probably have a timestamp and an expiration as well (all digitally signed of course).
- The Authorization header exists to verify the integrity of the HTTP request of the entity sending the request. It is a digital signature of the HTTP verb, path, host, message body, Visa, Permissions, and Public-Keys headers.
- The IDP is the only trusted entity in the whole multi-tier distributed interaction.
- Each service must have the IDP’s public key stored at deployment time prior to servicing any requests
- There is no communication to the IDP by any service. Even the initiating client’s first interaction with the IDP to obtain a Visa could be done ahead of time and re-used for multiple interactions.
This is just a rough outline, but there’s probably other things that could be added. Like nonce’s for instance. Its just a matter of implementing it and getting people to use it. The real question is, is there an existing protocol already out there that does this sort of thing?