📜 ⬆️ ⬇️

Briefly about OpenID Connect

Slowly, but inevitably, SAML-based SSO solutions change over to OpenID stack solutions. Recently, Google has implemented support for the OpenID Connect protocol on its servers. How much it can be acceptable for your project and how to work with it is rather difficult to assess by protocol specifications. The article of one of the authors of the specification in my blog, which translation I provide to the audience of the habr, should make this decision a little easier. In order to simplify understanding, some points were added on my own, so that you don’t have to read the references to the technologies used, but I still recommend reading some of them.


When you read the OpenID Connect specification, you may experience rather unpleasant feelings from slight fright to utter disappointment. All this happens because they are written in the “dry” specification language, and for the most part they describe boundary cases, exceptions, etc. However, when you translate them into a normal human language and switch to specific cases, everything becomes quite obvious. So let's get started! (Remarque: most of the text coincides with the original sentence written by David Recordon. Basically, my edits touched on only some of the names of the parameters and other trivia)


Creating an OpenID Connect Request


In order for a client to make an OpenID Connect request, it must have the following server information:



The client builds an OAuth 2.0 request to get a token.


To turn an OAuth 2.0 request into an OpenID Connect request, simply add the OpenID key as one of the required data sets (the scope parameter). By setting the OpenID key in the parameter, the client requests an identifier for the user, as well as an authentication context. If you want to get a user profile URL, name or photo, you can request additional data sets (for example, a profile). The server (and user) can select profile information available to the client. If the client wants to receive the user's email address, he must add the “email” key in the request. The same applies to the address (address) and phone (phone).
For example:


GET /authorize?grant_type=token%20id_token&scope=openid%20proflie&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 Host: server.example.com 

Although it may not be necessary to pre-register your client with the server, it is likely that the servers will have different restrictions and client requirements for requests for user information.


Getting an OpenID Connect response


If the user is authorized by a client request, the client will receive a token. The OAuth 2.0 authorization response typically includes two parameters: access_token and id_token . The information in id_token is encoded and includes a JSON object with the following fields:



The id_token parameter represents an easy way to make sure that the data received by the client through the User-Agent streams (or other unreliable channels) has not been changed. The parameter is signed by the server using a client key that was previously transmitted through a trusted channel. This encoding is called JSON Web Token (about JWT in brief and draft specification ). For example, here is the line:


 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 

It consists of three parts which are separated by dots.
The first part is the header (Header), this is a JSON object encoded by Base64url and describing the algorithm and type of token:


 { "alg": "HS256", "typ": "JWT" } 

The second part is the payload (Payload), this is also the JSON object encoded by Base64url:


 { "sub": "1234567890", "name": "John Doe", "admin": true } 

The third part of the server got the following:


 __ (HS256) ( base64UrlEncode( ) + "." + base64UrlEncode( ), _ ) 

Please note that the base64url encoding, unlike base64, uses two other characters and does not contain indents.
The authorization server should issue confirmations of user identifiers only within their domains. The client, in turn, must make sure that aud corresponds to his client_id, and iss corresponds to the domain (including the sub-domain) of the issuer in client_id. The authorization server is responsible for managing its own local namespace and ensures local uniqueness and non-repeatability (non-assignability) of each user_id.
When a client saves a user ID, it must save a tuple of user_id and iss in its local repository. The user_id parameter must not exceed 255 ASCII characters in length.
To verify the authenticity of the data, the client can verify the signature. If the client does not verify the signature, it must execute an HTTP request to the identity verification point to verify it. - a little incomprehensible why he should do it


Access to user information (optional)


User information is a regular OAuth 2.0 resource that is returned along with the token as a JSON document. The client makes an HTTPS "GET" request at the address providing user information and includes the token as a parameter.
The response is a JSON object that contains some (or all) of the following reserved keys (json-object):



The server can optionally add additional data to this response (for example, such as portable contacts ) as long as they do not change the reserved OpenID Connect keys. (Note: there are more clearly defined keys, but for brevity, I will omit their description.)


Opening (optional)


When using OpenID Connect, it is likely that the client may have either buttons for registration via popular services, or a text field for entering an email address or URL. OpenID Connect does not directly solve NASCAR problem
(The NASCAR problem is a reference to a jumble of web site brand icons through which to enter, highlighting the similarity of the login page with collages of sponsored ad stickers on track cars in NASCAR races).
The purpose of the open and register stages for the client is to obtain the address of the authorization server, the final address of the token issuing point, the client identifier, the client secret, and the user data API. If the client is pre-registered on the server, this information will already be known. Otherwise, the client will need to get them using the opening step.
The user presses a button on the client to select a server. In this case, the client developer will be able to select the preferred servers and thus, already knowing their authorization addresses (and, possibly, other information). The client may or may not be pre-registered.
In another case, the user (or User-Agent acting on his behalf) enters the URL or email address. To do this, the client will need to perform detection and determine whether the authorization server URL is valid. Steps:


  1. Let's analyze the data entry by the user to find out if this is an email address or URL. If it is an email address, do nothing. If there is no schema, assume the HTTPS protocol.
  2. Restore the identifier by reconstructing the various parts.
    For example:
    https://joe.example.com -> https://joe.example.com/
    example.com -> https://example.com/
    joe@example.com -> joe@example.com
  3. We retrieve the domain and make a WebFinger call via TLS / SSL.
    WebFinger is used to obtain information about people or other entities on the Internet using standard HTTP methods over a secure channel. WebFinger returns a JSON object that describes the requested entity.
     GET /.well-known/webfinger?resource=acct%3Ajoe%40example.com&rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer HTTP/1.1 Host: example.com HTTP/1.1 200 OK Content-Type: application/jrd+json { "subject": "acct:joe@example.com", "links": [{ "rel": "http://openid.net/specs/connect/1.0/issuer", "href": "https://server.example.com" }] } 
  4. In order to obtain a specific URL, the client adds the "/.well-known/openid-configuration" to the issuer, and receives the issuer configuration file via TLS / SSL as follows:
     GET /.well-known/openid-configuration HTTP/1.1 Host: server.example.com 

The response is a JSON object that includes the endpoint and other information.
For example:


 { "authorization_endpoint": "https://server.example.com/connect/authorize", "issuer" : "https://server.example.com", "token_endpoint": "https://server.example.com/connect/token", "token_endpoint_auth_types_supported":["client_secret_basic", "private_key_jwt"], "userinfo_endpoint": "https://server.example.com/connect/user", "check_id_endpoint": "https://server.example.com/connect/check_id", "registration_endpoint": "https://server.example.com/connect/register" } 

Unregistered customers and dynamic registration (optional)


Regardless of the discovery mechanism used, the client may or may not already be registered with the server. Servers may have different restrictions on what information clients can receive depending on whether they are pre-registered (which implies acceptance of the terms of service) or the client uses dynamic registration.
If the client does not have a valid client identifier and key, he can make the following HTTPS POST request to the server registration address (see Open) with the requested parameters in JSON format in the body of the POST request: redirect_uris - Array of URL addresses to receive OpenID responses.
For example:


 POST /connect/register HTTP/1.1 Content-Type: application/json Accept: application/json Host: server.example.com { "redirect_uris": ["https://client.example.org/callback", "https://client.example.org/callback2"] } 

Before responding to requests, the server must check if the URL is a callback outside of this OpenID stream. If yes, the server will send the information in response to the error. The server will need to develop a policy to handle such cases where the transmitted redirect_uri were previously registered by the client developer when making dynamic registration requests. This behavior may mean, for example, that new dynamic registration requests with these redirect_uri will lead to an error, but requests using dynamic registrations already implemented will continue to work until they become obsolete.
To provide dynamic association, the server includes the following JSON response parameters:



The client needs to keep its dynamic registration data to work with server tokens. For each dynamic registration, the client will need to store the client identifier, client key, expiration time, user URL, supported streams, and the user information API. The expiration time should be stored as an absolute time or a mark that the registration will last forever.
As you can see, the basic processes of the OpenID Connect web client are fairly simple, and as simple as those originally proposed. At the same time, additional functionality may be used, such as querying specific data sets, rather than the default set. These additional features are available when they are needed and do not turn simple interactions into major problems for customers with a large number of OpenID providers.


')

Source: https://habr.com/ru/post/281406/


All Articles