Access Manager IDP Server OAuth Access Token fails validation by Azure API Management Services

  • 7024487
  • 16-Mar-2020
  • 17-Mar-2020

Environment

  • Access Manager 4.4.x
  • Access Manager 4.5.x
  • Microsoft Azure API Management Services

Situation

  • Access Manager IDP Server has been configured for OAuth
  • Client application makes use of the OAuth Credential flow
  • Microsoft Azure API Management Services fails validation for Access Tokens generated by NAM with: "JWT Validation Failed: IDX10609: Decryption failed. No Keys tried: token"

Resolution

  1. Configure the "Resource Server" with "Do not encrypt" or "Encrypt using Resource Server Key.
    The client application has to be modified to generate a request including the "resourceServer" query parameter.

    Example:
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    curl -v -b c -c c -k "https://idpa.kgast.nam.com:8443/nidp/oauth/nam/authz?response_type=token&resourceServer=Identity+Provider&redirect_uri=https://192.168.0.195:8443/netiq-playground/oauth2client&client_id=e3371584-cc69-41c6-9aef-3074585ad613&client_secret=omdGIgupEoQy7M87G8QztssYxuCUAOm3El5TRsTFMbxlJk0-OYAoNxFo82LL-jfHlkr36n9PEpMij5xas-ifPw&scope=Gast"
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  2. Another option to decrypt the Access Token can be used by making use of the OAuth Uerinfo endpoint at:
    "[IDP BasURL]/nidp/oauth/nam/userinfo"

Cause

  1. By default the JWT Token send by NAM is encrypted. With a nested JWT the signature is part of the encrypted payload. In order to validate the OAuth Token Signature the Client would have first to decrypt which is not possible as the required encryption keys is not available shared with the default NAM Resource Server to external consumers by any endpoint / Reference

  2. The "Resource Server" configuration allows to disable / enable encryption and define the keys used for encryption.



    1. Note: The already existing "Identity Provider" is not the default Resource Server for OAuth.
      Any configuration for encryption has not impact on the default behavior

    2. A Scope configured below a Resource Server is a global scope and not tied to the Resource Server. This means just requesting a scope which has been configured below a given Resource Server will not apply the Resource Server settings. This is misleading by the concept of the iManager GUI

Additional Information

  • jwks_uri:   "https://[IDO BaseURL]/nidp/oauth/nam/keys"
    Note: with NAM this endpoint only defines the signing keys / certificates



    REQUIRED. URL of the OP's JSON Web Key Set [JWK] document. This contains the signing key(s) the RP uses to validate signatures from the OP. The JWK Set MAY also contain the Server's encryption key(s), which are used by RPs to encrypt requests to the Server. When both signing and encryption keys are made available, a use (Key Use) parameter value is REQUIRED for all keys in the referenced JWK Set to indicate each key's intended usage. Although some algorithms allow the same key to be used for both signatures and encryption, doing so is NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be used to provide X.509 representations of keys provided. When used, the bare key values MUST still be present and MUST match those in the certificate.

    kty      – Key Type – Identifies the family of algorithms used with this key
    alg      – Algorithm – Identifies the specific algorithm
    use      – Usage – ‘sig’ for signing keys, ‘enc’ for encryption keys
    x5t
          – X.509 Certificate Thumbprint – Used to identify specific certificates
    kid      – Key Identifier – Acts as an ‘alias’ for the key
    x5c
          – X.509 Certificate Chain – Chain of certificates used for verification.
    x5tS256  – X.509 Certificate SHA-256 Thumbprint Header Parameter


  • RFC 7519 at: https://tools.ietf.org/html/rfc7519 defines

    5.2.  "cty" (Content Type) Header Parameter
    The "cty" (content type) Header Parameter defined by [JWS] and [JWE]  is used by this specification to convey structural information about  the JWT. In the normal case in which nested signing or encryption operations are not employed, the use of this Header Parameter is NOT  RECOMMENDED.  In the case that nested signing or encryption is  employed, this Header Parameter MUST be present; in this case, the value MUST be "JWT", to indicate that a Nested JWT is carried in this JWT.  While media type names are not case sensitive, it is RECOMMENDED that "JWT" always be spelled using uppercase characters for compatibility with legacy implementations.  See Appendix A.2 for  an example of a Nested JWT. The inner signed JWT is identical to the example in Appendix A.2 of   [JWS].  Therefore, its computation is not repeated here.  This example then encrypts this inner JWT to the recipient using RSAES-PKCS1-v1_5 and AES_128_CBC_HMAC_SHA_256.


    The following example JOSE Header declares that:
    • The Content Encryption Key is encrypted to the recipient using the RSAES-PKCS1-v1_5 algorithm to produce the JWE Encrypted Key.
    • Authenticated encryption is performed on the plaintext using the AES_128_CBC_HMAC_SHA_256 algorithm to produce the JWE Ciphertext and the JWE Authentication Tag.
    • The plaintext is itself a JWT. {"alg":"RSA1_5","enc":"A128CBC-HS256","cty":"JWT"}

  • The JWT Access Token by NAM is a nested JWT which is first signed and then encrypted.

  • Possible impact by not encrypting the JWT

    The JWT Access Token is always signed and therefore the contents is protected from getting altered. If the communication is using SSL (which is required) there is not risk in transit. Having said this the JWT can provide claims (most likely what is not yet correctly configured for your application due to the error you are seeing). These claims can provide information which you do not like to provide to the user (while using implicit flow). Therefore an encrypted JWT would help to work around this.

    Example:

    {
     "iss": "https://idpa.kgast.nam.com:8443/nidp/oauth/nam",
     "jti": "a0a1d582-86d5-4541-90b3-f2c662b8b0de",
     "aud": "e3371584-cc69-41c6-9aef-3074585ad613",
     "exp": 1584016035,
     "iat": 1584012435,
     "nbf": 1584012405,
     "sub": "80a2c4e12d63db11ae0f0001021ee75e",
     "_pvt": "JXoODIztf4u3sZ2oar3Tm5mFs+YHAt19hUuU/1wBJuG64H3/MAz6fxn10yU5BDD25LLxHgAdvwEoWEr+dARFVAKRBiPJjAjyPTi7Knlafx7zHp08XLv1BNox7BCiF4e1hJTraEvkUrmNx5JmUSvQFYb+AkiinuezmZ4KQeuuFxZmpicosGVK5NM2kg2vmGS51Ny5adWNAYfK5V2ehpOBZwec042E+N0/JD25k6spWxh9MPAUs2DBQo3lcPAV2KlaJBrwd/qY2SDQup+Hlhrf4AiccHjla9oyPgCiwh803EC0LR8oQAwnNgNRIepphM2RIDcQ+VQiibzguVbCtrJDYUVp7PwrcDaj3g6oNjRjgKp+AdO9QnnT2Gp2Cs+9V4yYvkn1c6cQIas8NesHAYa9EtJuQYqYSXxrjJprSv5ci4dcZc+BKwZaAHgbzkJVEwWDqN1V7UnwtPPRUA0LOYbe2AeeccWTQb2RvoiZuOmos7QORfuAS9xB7SvR24nB6wVark5sCiFfOhPGpUUXpPbvWOJ1HjeHzOSBZt3+76H/PJ8=.7",
     "scope": [
       "Gast"
     ],
     "name": "john.doe",
     "given_name": "John",
     "_target": "Identity Provider"
    }

    The Access Token itself is opaque and is therefore not much of use unless you get access to the Refresh Token allowing you to request a new Access Token. Using the "/nidp/oauth/nam/userinfo" will allow you to get all information in case you use and encrypted Access Token.