OpenID Connect:OAuth 2.0協議之上的簡單身份層

  • OpenID Connect是什麼?OpenID Connect(目前版本是1.0)是OAuth 2.0協議(可參考本人此篇:OAuth 2.0 / RCF6749 協議解讀)之上的簡單身份層,用 API 進行身份交互的框架,允許客戶端根據授權服務器的認證結果最終確認用戶的身份,以及獲取基本的用戶信息;它支持包括Web、移動、JavaScript在內的所有客戶端類型;它是可擴展的協議,允許你使用某些可選功能,如身份數據加密、OpenID提供商發現、會話管理
  • OpenID Connect vs OpenID 2.0:OpenID Connect完成很多與OpenID 2.0相同的任務,是API-friendly,定義了可選的簽名和加密的機制;OAuth 1.0a和OpenID 2.0的集成需要擴展,而OpenID Connect協議本身就建立在OAuth 2.0之上
  • 部分名詞解釋
    1. Relying Party(RP):依賴方,通常是第三方應用程序(客戶端)
    2. OpenID Provider(OP):OpenID 提供方,通常是一個 OpenID 認證服務器,它能爲依賴方提供斷言以證實用戶擁有某個標識
    3. End-User(EU):終端用戶,指持有賬號的人
  • OpenID Connect協議構成
    1. Core – 定義 OpenID Connect 核心功能: 認證建立在OAuth 2.0之上,使用聲明與終端用戶進行信息交互
    2. Discovery – (Optional) Defines how Clients dynamically discover information about OpenID Providers
    3. Dynamic Registration – (Optional) Defines how clients dynamically register with OpenID Providers
    4. OAuth 2.0 Multiple Response Types – 定義了幾種新的OAuth 2.0響應類型
    5. OAuth 2.0 Form Post Response Mode – (Optional) Defines how to return OAuth 2.0 Authorization Response parameters (including OpenID Connect Authentication Response parameters) using HTML form values that are auto-submitted by the User Agent using HTTP POST
    6. Session Management – (Optional) Defines how to manage OpenID Connect sessions, including postMessage-based logout functionality
    7. Front-Channel Logout – (Optional) Defines a front-channel logout mechanism that does not use an OP iframe on RP pages
    8. Back-Channel Logout – (Optional) Defines a logout mechanism that uses direct back-channel communication between the OP and RPs being logged out

    下邊兩條是 Web RPs 實現者的獨立參考指南:

    1. Basic Client Implementer’s Guide – Simple subset of the Core functionality for a web-based Relying Party using the OAuth code flow
    2. Implicit Client Implementer’s Guide – Simple subset of the Core functionality for a web-based Relying Party using the OAuth implicit flow

    協議遷移規範:

    1. OpenID 2.0 to OpenID Connect Migration 1.0 – Defines how to migrate from OpenID 2.0 to OpenID Connect

    OpenID Connect 工作組已啓動新的工作計劃:

    1. OpenID Connect Profile for SCIM Services – (Optional) Defines how to use SCIM with OpenID Connect
    2. OpenID Connect Federation – (Optional) Defines how sets of OPs and RPs can establish trust by utilizing a Federation Operator

  • OpenID Connect的工作流程:下以EU獲取UserInfo爲例來說明,
    1. RP(客戶端)發送一個認證請求給OP;
    2. OP對EU進行身份認證並獲得授權;
    3. OP發送ID Token給RP,通常也同時發送Access Token(爲兼容OAuth 2.0。ID Token其實可以取代Access Token用來完成授權);
    4. RP使用Access Token發送一個請求UserInfo EndPoint;
    5. UserInfo EndPoint返回EU的Claims。

    下邊是關於“ID Token 與 Access Token”的描述來自 User Authentication with OAuth 2.0 [UserInfo Endpoint]:

    It should be noted that clients are not required to use the access token, since the ID Token contains all the necessary information for processing the authentication event. However, in order to provide compatibility with OAuth and match the general tendency for authorizing identity and other API access in parallel, OpenID Connect always issues the ID token along side an OAuth access token.
  • ID Token:它是一種JWT(JSON Web Token)格式數據,主要由以下幾部分構成:
    1. iss:必須。Issuer Identifier,OP的唯一標識,一個區分大小寫的https URL,不包含query和fragment組件
    2. sub:必須。Subject Identifier,iss提供的EU的標識,在iss範圍內唯一,最長爲255個ASCII個字符,區分大小寫
    3. aud:必須。Audience(s),標識ID Token的受衆,必須包含OAuth2的client_id,分大小寫的字符串數組
    4. exp:必須。Expiration time,超過此時間的ID Token會作廢
    5. iat:必須。Issued At Time,JWT的構建的時間
    6. auth_time:AuthenticationTime,EU完成認證的時間。如果RP發送AuthN請求的時候攜帶max_age的參數,則此Claim是必須的
    7. nonce:RP發送認證請求的時候提供的隨機字符串,用來減緩重放攻擊,也可以用來關聯客戶端Session。如果nonce存在,客戶端必須驗證nonce
    8. acr:可選。Authentication Context Class Reference,表示一個認證上下文引用值,可以用來標識認證上下文類
    9. amr:可選。Authentication Methods References,表示一組認證方法
    10. azp:可選。Authorized party,結合aud使用。只有在被認證的一方和受衆(aud)不一致時才使用此值,一般情況下很少使用

    形如:

    {
       "iss": "https://server.example.com",
       "sub": "24400320",
       "aud": "s6BhdRkqt3",
       "nonce": "n-0S6_WzA2Mj",
       "exp": 1311281970,
       "iat": 1311280970,
       "auth_time": 1311280969,
       "acr": "urn:mace:incommon:iap:silver"
    }

     關於協議定義Claims的更多信息參考:http://openid.net/specs/openid-connect-core-1_0.html#Claims。ID Token必須使用JWS進行簽名,如果要用JWE加密也必須先進行JWS簽名

  • JSON Web Signature (JWS):JSON數據進行數字簽名或MACed後再經base64url編碼。

    JWS Compact Serialization如下連接序列:Header.Payload.Signature

    BASE64URL(UTF8(JWS Protected Header)) || '.' ||
    BASE64URL(JWS Payload) || '.' ||
    BASE64URL(JWS Signature)
    1. JWS Protected Header
        {"typ":"JWT",
          "alg":"HS256"}
        編碼後:
        eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
    2. JWS Payload
        {"iss":"joe",
          "exp":1300819380,
          "http://example.com/is_root":true}
        編碼後:
        eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ
    3. JWS Signature
        Signing Input value:
        eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
         .
         eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ
        HMAC SHA-256 key:
        {"kty":"oct",
          "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
         }
        JWS Signature:
        dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
    4. JWS Compact Serialization
        eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
         .  
        eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
         cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
         .
         dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

    JWS JSON Serialization包含如下幾個部分

    1. "protected", with the value BASE64URL(UTF8(JWS Protected Header))
    2. "header", with the value JWS Unprotected Header
    3. "payload", with the value BASE64URL(JWS Payload)
    4. "signature", with the value BASE64URL(JWS Signature)

    General JWS JSON Serialization:

    {
          "payload":"<payload contents>",
          "signatures":[
           {"protected":"<integrity-protected header 1 contents>",
            "header":<non-integrity-protected header 1 contents>,
            "signature":"<signature 1 contents>"},
           ...
           {"protected":"<integrity-protected header N contents>",
            "header":<non-integrity-protected header N contents>,
            "signature":"<signature N contents>"}]
    }

    Flattened JWS JSON Serialization:

    {
          "payload": "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
          "protected":"eyJhbGciOiJFUzI1NiJ9",
          "header": {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
          "signature": "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
    }
  • JSON Web Encryption (JWE)

    JWE Compact Serialization如下連接序列

          BASE64URL(UTF8(JWE Protected Header)) || '.' ||
          BASE64URL(JWE Encrypted Key) || '.' ||
          BASE64URL(JWE Initialization Vector) || '.' ||
          BASE64URL(JWE Ciphertext) || '.' ||
          BASE64URL(JWE Authentication Tag)

    JWE JSON Serialization包含如下幾個部分

          1. "protected", with the value BASE64URL(UTF8(JWE Protected Header))
          2. "unprotected", with the value JWE Shared Unprotected Header
          3. "header", with the value JWE Per-Recipient Unprotected Header
          4. "encrypted_key", with the value BASE64URL(JWE Encrypted Key)
          5. "iv", with the value BASE64URL(JWE Initialization Vector)
          6. "ciphertext", with the value BASE64URL(JWE Ciphertext)
          7. "tag", with the value BASE64URL(JWE Authentication Tag)
          8. "aad", with the value BASE64URL(JWE AAD)

    General JWE JSON Serialization:

    {
          "protected":"<integrity-protected shared header contents>",
          "unprotected":<non-integrity-protected shared header contents>,
          "recipients":[
           {"header":<per-recipient unprotected header 1 contents>,
            "encrypted_key":"<encrypted key 1 contents>"},
           ...
           {"header":<per-recipient unprotected header N contents>,
            "encrypted_key":"<encrypted key N contents>"}],
          "aad":"<additional authenticated data contents>",
          "iv":"<initialization vector contents>",
          "ciphertext":"<ciphertext contents>",
          "tag":"<authentication tag contents>"
    }

    Flattened JWE JSON Serialization:

    {
          "protected":"<integrity-protected header contents>",
          "unprotected":<non-integrity-protected header contents>,
          "header":<more non-integrity-protected header contents>,
          "encrypted_key":"<encrypted key contents>",
          "aad":"<additional authenticated data contents>",
          "iv":"<initialization vector contents>",
          "ciphertext":"<ciphertext contents>",
          "tag":"<authentication tag contents>"
    }

     

  • JSON Web Key (JWK):JWK用於JWS和JWE中,也是一種JSON數據結構,其包含了如下幾項:

    1. "kty" (Key Type) Parameter
    2. "use" (Public Key Use) Parameter
    3. "key_ops" (Key Operations) Parameter
    4. "alg" (Algorithm) Parameter
    5. "kid" (Key ID) Parameter
    6. "x5u" (X.509 URL) Parameter
    7. "x5c" (X.509 Certificate Chain) Parameter
    8. "x5t" (X.509 Certificate SHA-1 Thumbprint) Parameter
    9. "x5t#S256" (X.509 Certificate SHA-256 Thumbprint)

    形如:

         {"kty":"EC",
          "crv":"P-256",
          "x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
          "y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
          "kid":"Public key used in JWS spec Appendix A.3 example"
         }

     

  • Base64編碼:Base64是基於64個可打印字母表(Table 1: The Base64 Alphabet)來表示數據的方法,可用於二進制數據如圖片、視頻、音頻數據的轉換表示,可查看RFC2045~RFC2049,上面有MIME(Multipurpose Internet Mail Extensions)的詳細規範:
    1. 每3個字節一組,再按6bits(2 ^ 6 = 64)爲一組分成4組,即3 * 8bits = 4 * 6bits;
    2. 以6bits的值爲索引查找字母表中對應的字符。最後3字節變成4字節,長度增加33%;
    3. 對於不足3字節的情況用\x00字節補足,最後用尾部加“=”的個數來表示缺少的字節數,即Base64編碼的尾部最多有1~2個“=”。
    在RFC 2045中還規定,輸出每行不超過76字符(CRLF結尾):
    The encoded output stream must be represented in lines of no more than 76 characters each. All line breaks or other characters not found in Table 1 must be ignored by decoding software.
     由於+和/字符在URL中傳遞是不安全的,因此又出現了以-和_來替換+和/的Base64URL編碼:
    由於“=”字符也可能出現在Base64編碼中,但“=”用在URL、Cookie裏面會造成歧義,所以很多Base64編碼把“=”去掉。至於去掉“=”後如何解碼呢?正常Base64編碼後的序列字符數一定是4的倍數,如果結果不是,則可反推去掉了多少個“=”

     

  • 相關參考

    1. OIDC(OpenId Connect)身份認證授權(核心部分)

    2. RFC 7515 - JSON Web Signature (JWS)
    3. RFC 7516 - JSON Web Encryption (JWE)

    4. RFC 7517 - JSON Web Key (JWK)

     

     


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章