Wiki

Clone wiki

ab / OldDocument

ABC of OpenID/AB

Author: Nat Sakimura, NRI

About OpenID

OpenID is a Digital Identity Framework that that conveys the authorization decision and identity attributes/data of an authenticated identity from the identity provider (OpenID provider, OP) to a requesting party called relying party (RP).

Problems of OpenID GET/POST Binding (aka OpenID Authentication 2.0)

OpenID/AB is a binding and casting of OpenID onto OAuth 2.0 and JSON. It solves many problems of the POST/GET binding of OpenID has.

Examples of "GET/POST Binding":

  • Long URL problem
    • Many mobile browser and some PC browsers choke at a long URL caused by AX, PAPE, and other extensions.
    • POST Binding can be used instead of GET, but it results in poor/unacceptable user interface.
    • Large Payload through EDGE and 3G network can be very frustratingly slow.
  • Security Problem
    • GET/POST binding cannot attain Level of Assurance 2 (LoA2) because of assertion disclosure
    • Non-repudiation is not possible with GET/POST binding because it does not define Public Key Signature.
    • Since GET/POST binding does not define assertion encryption based on recipient public key, it cannot support the store and forward use-case of the assertion.
  • Data Sharing Limitation
    • Only pair-wise data sharing between the OP and RP is possible.
    • OP to RP server-to-server "push" is defined, but there is no "pull". Even "push" is poorly documented and not well understood.
  • Implementation Complexity
    • Since GET/POST binding does not rely on SSL/TLS, one ends up with Diffie-Helman key exchange etc., which is slow and complex to implement in many scripting language.

The OpenID/AB actually solves all the above problems.

How OpenID/AB Works : Basic Three Parties Model

OpenID traditionally has been dealing with three parties model: three parties being

  1. User at Browser
  2. OpenID Provider (OP)
  3. Relying Party (RP)

They still are the main players in OpenID/AB. There is another set of important concept in AB.

  1. Request FIle (RF) and RF URL that points to it.
  2. Authorization Assertion (AA) that includes the statement about the user at the browser and her authorization decision and associated data.
  3. A small data that points to the AA called Artifact.

Now, let us see how the basic flow of the OpenID/AB works.

(fig.1 OpenID/AB Basic Flow) OpenID/AB Basic Flow

0. RP prepares an RF that has all the request information/parameters.

  1. RP redirects the user with the RF URL to the OP.
  2. OP fetches the RF.
  3. OP shows the request that was in RF to the user and asks for authorization.
  4. Once approved, OP sends the Browser back via redirect to the RP with the Artifact.
  5. RP uses the Artifact to obtain the AA, that includes the user's authentication status and the authorization result.

If the RP wants to, RP can present the AA or Artifact to the OP to get the update on the data, if the OP and the User allows. (For this to work, the AA MUST be signed by the OP's private key.)

Note: if it does so, the authentication status is void in the second and subsequent responses.

Requst File

Request FIle, together with Authz Assertion, is one of the most important format. It is a JSON file with all the request parameters. It looks like this:

{
    "ns":"http://specs.openid.net/auth/2.0",
    "mode":"direct_req",
    "client_id":"http://example.com/rp/",
    "pubkey":"AzqUFjwldisoOfjw",
    "claimed_id":"http://specs.openid.net/auth/2.0/identifier_select",
    "identifier":"http://specs.openid.net/auth/2.0/identifier_select",
    "redirect_url":"https://example.com/rp/endpoint_url",
    "ns:ax":"http://openid.net/srv/ax/1.1",
    "ax:mode":"fetch_request",
    "ax:fullname":"http://example.com/schema/fullname",
    "ax:age":"http://example.com/schema/age"
}

Let the URL of this file be https://rp.example.com/rf.js#da25d3de1a3b29547e3121ae81d88bc4abd27b78d79b9a9c77209797c66db0f6

The seemingly random value after # is the sha256 hash of the request file.

Note: For request non-repudiation, RF should be signed by Magic Signature.

Authz Assertion (Response)

The other important file is the Authorization Assertion (AA). In this simple case, the OP dubs as a Data Server, so the actual data value is returned also.

It looks like this:

{
    "ns":"http://specs.openid.net/auth/2.0",
    "mode":"id_res",
    "request_file":"https://rp.example.com/rf.js#da25d3de1a3b29547e3121ae81d88bc4abd27b78d79b9a9c77209797c66db0f6",
    "op_endpoint":"https://op.example.com/op_endpoint",
    "claimed_id":"https://example.com/alice#1234",
    "identity":"alice",
    "client_id":"https://rp.example.com/",
    "server_id":"https://op.example.com/",
    "access_token":"aFowj3fdjskOfjeaodskF",
    "ax:mode":"fetch_response",
    "ax:fullname":"John Smith",
    "ax:age":"24",
}

This JSON will be further Magic Signed.

"access_token" works like a unique identifier of this AA, so it can be presented instead of the AA itself. However, that means the OP (Server) has to keep the state. It probably would be better to use the AA as token if statelessness is desired.

How OpenID/AB Works : n>3 Parties Model

In general, OP is not the only Data Server for the person. It is likely to be spread all over. This is the n>3 Parties Model.

Multi-party Data Sharing

Up to Step.5 is the same as the 3 parties model. What is different is from Step 6 onwards.

Instead of getting data from the OP, it goes to Data Source 1, 2, etc.

In this case, the AA will look like this:

{
    "ns":"http://specs.openid.net/auth/2.0",
    "mode":"id_res",
    "request_file":"https://rp.example.com/rf.js#da25d3de1a3b29547e3121ae81d88bc4abd27b78d79b9a9c77209797c66db0f6",
    "op_endpoint":"https://op.example.com/op_endpoint",
    "claimed_id":"https://example.com/alice#1234",
    "identity":"alice",
    "client_id":"https://rp.example.com/",
    "server_id":"https://op.example.com/",
    "access_token":"aFowj3fdjskOfjeaodskF",
    "ax:mode":"fetch_response",
    "ax:fullname":"John Smith",
    "ax:age":"24",
    "ax:endpoints":
        [
            "https://op.example.com/op_endpoint",
            "https://ds1.example.com/",
            "https://ds2.example.com/"
        ]
}

Note the "ax:endpoints" in it. It is an array of the attributes endpoints. The RP can request these endpoints using the AA. Each Data Source (DS) does not have all the data, but they will return whatever they can.

Why do these Data Source can decide that they have permission to release the data?

There are several prerequisite for this to happen.

  • User Identifiers are Shared. It cannot do the PPID within this group of DS.
  • All the DS MUST know that the OP(AM) is authoritative for this identity's data release decision.
  • The AA is signed.

Then, each DS can verify the AA's signature using OP/AM's public key to find out that this AA is authoritative. Since the assertion is passed through the protected channel only, it can act as a shared secret among the DSs to authenticate the RP as well. In addition, the RP can sign the AA and send it to achieve the request non-repudiation. The AAs can be encrypted by the RP's public key for end-to-end protection.

One should also note that 'access_token' is used instead of the AA, DSs MUST first resolve the 'access_token' to the AA by requesting the OP/AM. Otherwise, a DS will never know what was requested and what access has been granted.

Problem Solved?

Now, let us see what problems we have solved among the shortcomings of the OpenID 2.0.

  • Long URL problem
    • Only small data is passed through the Browser. On the request, it is the RF URL 'request_url', and for the response, the Artifact 'code'.
  • Security Problem
    • GET/POST binding cannot attain Level of Assurance 2 (LoA2) because of assertion disclosure
      • Assertions are passed server to server on SSL protected channel, so the assertion disclosure does not happen.
    • Non-repudiation is not possible with GET/POST binding because it does not define Public Key Signature.
      • Using Magic Signature (RSA Signature), AB achieved non-repudiation on both direction.
    • Since GET/POST binding does not define assertion encryption based on recipient public key, it cannot support the store and forward use-case of the assertion.
      • AB supports AA encryption by the public key of the intended recipient.
  • Data Sharing Limitation
    • Only pair-wise data sharing between the OP and RP is possible.
      • Multi-party data sharing is defined.
    • OP to RP server-to-server "push" is defined, but there is no "pull". Even "push" is poorly documented and not well understood.
      • Pull is also achieved.
  • Implementation Complexity
    • Since GET/POST binding does not rely on SSL/TLS, one ends up with Diffie-Helman key exchange etc., which is slow and complex to implement in many scripting language.
      • Strikingly Simple!

Beyond AB to C

Wow. It solved all the problems that I stated at the beginning. So, has all the possible problems been solved?

Unfortunately, not.

In the n>3 parties model, the user identifier had to be shared among all the Data Sources. This is not good from the privacy point of view. Also, AB does not define "what text should be shown to the end user at the authorization page."

AB unfortunately does not solve this problem. It has to wait for ... "C": The Contract eXchange (CX).

I will defer it to a CX introduction page, but here is a sniff of it just as a teaser.

  • In CX, the actual request will be the sequence of the signed RF + signatures hash.
  • Responses are constructed for each party, and encrypted by each party's public key, so PPID for each party will not be exposed to other parties.
  • There is a contract_id. Data request can just state this contract_id. Then, each party gets the Contract and decrypt its own part to find out about whom the request is talking about.
  • There is a log interface for each DS, so that the user can collect all the data release event information.

Sounds interesting?

Other Readings

Updated