Identity Service

The Vanadium Identity Service generates blessings. It uses an OAuth2 identity provider to get the email address of a user and then issues a blessing with that email address. For example, after determining that the user is alice@university.edu (using OAuth2), this service will issue the blessing dev.v.io/u/alice@university.edu (where dev.v.io is the namespace for which the public key of the identity service is considered authoriative). The blessing may also contain specific caveats per the user's request.

Broadly, this identity service consists of two main components:

  • HTTPS Authentication Service: This service authenticates the user using an OAuth2 Identity Provider, and securely hands out a token (henceforth called a macaroon) that encapsulates the user's authenticated identity and any caveats that the user may have requested to be added to the blessing. The cryptographic construction of macaroons ensures that their contents cannot be tampered with.
  • Vanadium Blessing Service: This is a Vanadium RPC service with a method that exchanges the macaroon for a blessing. The principal invoking this RPC is blessed with a name and caveats extracted from the presented macaroon.

One additional service enables revocation of the blessings granted by the blessing service:

  • Vanadium Discharge Service: This is a Vanadium RPC service enables revocation. The service issues discharges for a revocation caveat if the blessing has not been revoked by the user. The discharges are valid for 15 minutes.

All three services are exposed by a single binary - identityd. In order to save users from talking to two different services (the HTTP service and the Blessing service) and managing macaroons, we also provide a command-line tool - principal - that talks to both of the services and obtains a blessing for the principal that the tool is running as.

Preliminaries

Before diving into the details of identityd's design, some prerequisites:

  • Principals, Blessings and Caveats.
  • Third-party caveats: In a nutshell, a third-party caveat is a restriction on the use of a blessing that must be validated by a party other than the two communicating with and authorizing each other. The blessing with a third-party caveat is considered valid only if accompanied by a discharge issued by the third party that validated the restrictions. Discharges are unforgeable and cryptographically bound to the correpsonding third-party caveat.
  • Macaroons: For the purposes of the identity service, a macaroon is a bearer token, similar to a cookie that can only be minted (and verified) by the identity service. A macaroon encapsulates state whose bits cannot be tampered with by anyone but the identity service. The state itself though is visible to the bearers of the macaroon. In particular, the identity service with a secret HMAC key k defines a macaroon for a state as: Macaroonk(state) = HMAC(k, state) The name “cookie” or “token” could have been used instead, but the term macaroon was an allusion to this paper.

Service interfaces

The HTTPS Authentication Service runs at https://dev.v.io/auth and uses the Google OAuth2 web service flow for authenticating users. It has a specific OAuth2 ClientID and ClientSecret obtained from the Google Developer Console. It supports the following routes:

RoutePurpose
/google/seekblessingsReceive blessing requests
/google/caveatsDisplay a form for selecting caveats to be added to a blessing
/google/sendmacaroonReceive a POST request from the caveat selection form
/google/listblessingsEnumerate all blessings made by a particular user
/google/revokeReceive revocation requests

The blessing service is a Vanadium RPC service reachable via the name /ns.dev.v.io:8101/identity/dev.v.io/u/google and presents the MacaroonBlesser interface:

type MacaroonBlesser interface {
  // Bless uses the provided macaroon (which contains email and caveats)
  // to return a blessing for the client.
  Bless(macaroon string) (blessing security.WireBlessings | error)
}

Blessing flow

The principal command-line tool is used to orchestrate the process of obtaining a macaroon from the HTTPS Authentication Service and exchanging it for a blessing from the Vanadium Blessing Service. The following sequence diagram lists the network requests involved in this process:

  • Solid-line arrows represent HTTPS requests (except one HTTP to localhost).
  • Dotted-line arrows represent Vanadium RPC requests.

Steps 1 thru 4 in the sequence diagram above result in the principal tool invocation obtaining a macaroon.

Steps 5 and 6 exchange that macaroon for a blessing.

  1. The tool generates a random state parameter toolState and starts an HTTP server on localhost for receiving the macaroon. toolURI denotes the URI of this server (e.g., http://127.0.0.1:14141), and toolPublicKey denotes the public key of the principal running the tool. It then directs the web browser on the machine to the HTTP Authentication Service while informing it of toolURI, toolPublicKey and the toolState parameters. For example, it might redirect to: https://dev.v.io/auth/google/seekblessings?redirect_uri=<toolURI>&state=<toolState>&public_key=<toolPublicKey>

  2. The HTTP Authentication Service extracts toolURI, toolState and toolPublicKey and redirects the browser to the Google OAuth2 endpoint (using the web service flow). The redirect_uri provided to this endpoint is set to the page that presents a form to control caveats on the final blessing and the state parameter is set to: oauthstate = Macaroonk(toolURI + toolState + toolPublicKey + serverCookie) where serverCookie is a cookie set by the HTTP Authentication Service in the user‘s browser. This leads the user’s browser to a URL like: https://accounts.google.com/o/oauth2/auth?client_id=...&redirect_uri=https://dev.v.io/auth/google/caveat&state=oauthstate

    The Google OAuth2 endpoint asks the user to login and grant access to email address to the Vanadium Identity Server, after which it redirect the browser back to: https://dev.v.io/auth/google/caveats?code=<authcode>&state=<oauthstate>

  3. The caveats page at the HTTP Authentication Service receives authcode and oauthstate. It then:

    • Verifies that oauthstate is a valid macaroon generated by step 2.
    • Extracts toolURI, toolState, toolPublicKey and serverCookie from the macaroon.
    • Verifies that serverCookie matches the cookie presented by the browser
    • Exchanges authcode for an email address (via an identity token) using the OAuth2 client-secret.
    • Displays a form for selecting caveats to be added to the blessing that will ultimately be provided to the principal tool started in step 1. Embedded in this form is formstate = Macaroon<sub>k</sub>(toolURI + toolState + toolPublicKey + email + serverCookie).
  4. When the user submits the form rendered in step 3, the browser sends the form contents to https://dev.v.io/auth/google/sendmacaroon which performs the following steps:

    • Verifies that formstate is a valid macaroon.
    • Extracts toolURI, toolState, toolPublicKey, email and serverCookie encapsulated in the macaroon.
    • Verifies that serverCookie matches the cookie presented by the browser.
    • Verifies that toolURI is a localhost URI.
    • Computes M = Macaroonk(email, toolPublicKey, caveats).
    • Redirects the browser to: https://<toolURI>/macaroon?state=<toolState>&macaroon=M&root_key=publicKey where publicKey is the blessing root of the identity service.
  5. The principal tool receives the macaroon M, toolState and the blessing root via the HTTP redirect in step 4. It then:

    • Verifies that toolState obtained here matches the one created in step 1.
    • Invokes the Bless RPC on the blessing service passing it M as an argument. It only sends this request if the the RPC server proves that it's public key is publicKey via the authentication protocol used in RPCs.
  6. The Vanadium Blessing Service that receives this RPC performs the following steps:

    • Verifies that the macaroon presented is valid.
    • Extracts email, toolPublicKey and caveats from it.
    • Verifies that the principal making the RPC request has the same public key as toolPublicKey. This check ensures that the macaroon can only be used by the principal tool that requested it in the first place. It protects against impersonation attacks wherein an attacker steals the macaroon handed out in step 5 and then tries to obtain a blessing for the email address encapsulated in the macaroon.
    • Generates a blessing with the name dev.v.io/u/<email> and the caveats extracted from the macaroon. This blessing is bound to the public key of the principal making the RPC request (i.e., toolPublicKey).
    • Records the creation of this blessing in a database which can be queried via https://dev.v.io/auth/google/listblessings.

Supported caveats

The caveat addition form presented to the user in step 4 supports a few types of caveats:

Revocation

The revocation caveat that is (at the user's request) added to the blessing is a third-party caveat with a unique 16-byte ID and the object name of the discharging service. Each time a revocation caveat is created, the blessing service stores the corresponding ID and the revocation status in a SQL database.

The discharge service run by identityd extracts the ID from the caveat and looks it up in the database. If the database suggests that blessing should be revoked, it refuses to issue a discharge.

This is implemented in services/identity/internal/revocation.

Revocation can be triggered by clicking buttons on https://dev.v.io/auth/google/listblessings.