Uploaded image for project: 'OpenAM'
  1. OpenAM
  2. OPENAM-15044

OpenID connect id_token bearer Module Unable to obtain SSO Token due to OpenIDResolver Caching

    Details

    • Sprint:
      AM Sustaining Sprint 64, AM Sustaining Sprint 65
    • Story Points:
      3
    • Needs backport:
      No
    • Support Ticket IDs:
    • Needs QA verification:
      No
    • Functional tests:
      No
    • Are the reproduction steps defined?:
      Yes and I used the same an in the description

      Description

      Bug description

      When 2 or more openid connect id_token bearer modules share the same jwk_url configuration value but different issuer, one of the modules would not be able to authenticate and obtain the SSO Token ID.

      How to reproduce the issue

      1. Setup 3 AM instances (named as AM1, AM2, AM3)
        • AM1 : test.example.com:8080
          Setup AM1 instance normally (default configuration) (this instance does not link to AM 2 & AM 3)
        •  

      AM2 : am.example.com:18080
      Setup AM2 instance (default configuration)

        • AM3 : pm.example.com:28080
          Setup AM3 instance (custom configuration)
          Add to existing deployment (enter AM2 url)
      1. For AM2 instance :
        1.  Create OpenID Connect with default setting ([Realm] >Configure OAuth Provider >Configure OpenID connect)
        2. Create OAuth2.0 Agent called myClientID  ([Realm]>Applications >OAuth 2.0)
          Redirection URIs : http://www.google.com.sg
          Scope(s) : openid
          Grant Types: Implicit
        3. Obtained the jwk_uri json using /oauth2/connect/jwk_uri endpoint
      1. For AM 1 instance:
        1. Copy the jwk_uri json(obtained in 2.3) and place them in a common folder to access (for example: /path/to/tomcat/examples/)
        2. Create an openid connect id_token bearer called amtest (this id_token bearer should match id token obtain from AM1) (refer to img1)
        3. Create another openid connect id_token bearer called pmtest (this id_token bearer should match id token obtain from AM2) (refer to img2)
      1. Obtain JWT token from AM 2 instance :
      eyJ0eXAiOiJKV1QiLCJraWQiOiJ3VTNpZklJYUxPVUFSZVJCL0ZHNmVNMVAxUU09IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkZW1vIiwiYXVkaXRUcmFja2luZ0lkIjoiYzQ5ZWM3ZTgtN2YwYi00YTdmLTk1N2ItYzA4OGM0M2U0Yjg3LTIzNTciLCJpc3MiOiJodHRwOi8vYW0uZXhhbXBsZS5jb206MTgwODAvb3BlbmFtL29hdXRoMiIsInRva2VuTmFtZSI6ImlkX3Rva2VuIiwibm9uY2UiOiIxMjM0IiwiYXVkIjoibXlDbGllbnRJRCIsImFjciI6IjAiLCJvcmcuZm9yZ2Vyb2NrLm9wZW5pZGNvbm5lY3Qub3BzIjoiM1pjTm5vYUUtc0lzT2Y1U29LU2FxRG9yazdnIiwiYXpwIjoibXlDbGllbnRJRCIsImF1dGhfdGltZSI6MTU1OTc4MDM5NCwicmVhbG0iOiIvIiwiZXhwIjoxNTU5Nzg0MDAwLCJ0b2tlblR5cGUiOiJKV1RUb2tlbiIsImlhdCI6MTU1OTc4MDQwMH0.j2OR3AlyOFudpTZdw5e9oUc7gTD3uklRuqhFh5mdLDCS6bXJg_JYOgi7sVqD9U7IZGCy1XTo-75buA0CZ71wnxMuCw1EekcetfochNxI_eIovZNPlwd1DWLaAXKhE1FtIIViRI7i0KrgPG7syiGSaP3YcBvP-mr8V2SJ4jyYEnDSRjn9fYKxvACXJP6W8f8Goc2ZU22aZruQfO6AZq4gvN-yaIlJcZVCRf6WHVHovXGEphZZ9nz9kH-ZK_6mWQs7O9_mFydv-7SLgtEOy0zbC2SwvxZ4QLH3USzYfV1d0dO8TXrfDLGtJgUQGt0Ohaps80fyEqdKIg-O_BnMioAo-A
      
      1. Obtain JWT token from AM 3 instance:
      eyJ0eXAiOiJKV1QiLCJraWQiOiJ3VTNpZklJYUxPVUFSZVJCL0ZHNmVNMVAxUU09IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkZW1vIiwiYXVkaXRUcmFja2luZ0lkIjoiZjNmMTNmNjUtZjVmMi00NzY4LTlmNmMtYzQ2YTIwNmJiNDJjLTE3NDUiLCJpc3MiOiJodHRwOi8vcG0uZXhhbXBsZS5jb206MjgwODAvb3BlbmFtL29hdXRoMiIsInRva2VuTmFtZSI6ImlkX3Rva2VuIiwibm9uY2UiOiIxMjM0IiwiYXVkIjoibXlDbGllbnRJRCIsImFjciI6IjAiLCJvcmcuZm9yZ2Vyb2NrLm9wZW5pZGNvbm5lY3Qub3BzIjoiUldXUHJmb2Y4U1RkSUlVRmZzbHJQRTcyMVBVIiwiYXpwIjoibXlDbGllbnRJRCIsImF1dGhfdGltZSI6MTU1OTc4MDM5NCwicmVhbG0iOiIvIiwiZXhwIjoxNTU5Nzg0MzE4LCJ0b2tlblR5cGUiOiJKV1RUb2tlbiIsImlhdCI6MTU1OTc4MDcxOH0.h6hUVCDMOikQ70My3nzL6uf1NLi7c1mDWHeq_6-8z2SCMOSORPURFX2jjsxKzd3UkWlw9YGNEWgk2SwC0GuEZsVy2hVJiPenKkB92yOjELUSM7ONXlbUnLK4QWNrY9si7RX6GMSjeom1bkP9Zg3zs5BbQkskpgJfBirZ_ydUUUACMDxJSDPc0SXGBCI07XLEpRjahqjF0hknoZ_xXPeQ_zsdpODNMnIx-c2H6XurCQW-lfg69DVL7dKj1_ySdgZRvL_yYeeVee6W9Tt33mBtV6NiMZJQ-BVkFdCSRcW2NyjPGMlZ3CSmnFYXn_I6eo4keyq2vZaFPgEYHRkviDsNuQ

      Case Scenario 1:

      1. Authenticate with AM 1 amtest module (Able to obtain SSO Token ID):
      curl -X POST \
        'http://test.example.com:8080/openam/json/realms/root/authenticate?authIndexType=module&authIndexValue=amtest' \
        -H 'Accept-API-Version: resource=2.0,protocol=1.0' \
        -H 'oidc_id_token: eyJ0eXAiOiJKV1QiLCJraWQiOiJ3VTNpZklJYUxPVUFSZVJCL0ZHNmVNMVAxUU09IiwiYWxnIjoiUlMyNTYifQ...........j2OR3AlyOFudpTZdw5e9oUc7gTD3uklRuqhFh5mdLDCS6bXJg_JYOgi7sVqD9U7IZGCy1XTo-75buA0CZ71wnxMuCw1EekcetfochNxI_eIovZNPlwd1DWLaAXKhE1FtIIViRI7i0KrgPG7syiGSaP3YcBvP-mr8V2SJ4jyYEnDSRjn9fYKxvACXJP6W8f8Goc2ZU22aZruQfO6AZq4gvN-yaIlJcZVCRf6WHVHovXGEphZZ9nz9kH-ZK_6mWQs7O9_mFydv-7SLgtEOy0zbC2SwvxZ4QLH3USzYfV1d0dO8TXrfDLGtJgUQGt0Ohaps80fyEqdKIg-O_BnMioAo-A' \
        -d '{}'
      
      {
          "tokenId": "wz3-EJWothjkyDQK_DAJ1b5mUXc.*AAJTSQACMDEAAlNLABxGazZpdlo5Z1JwbDdKSnlKb0ppM1FzbUpPdEk9AAR0eXBlAANDVFMAAlMxAAA.*",
          "successUrl": "/openam/console",
          "realm": "/"
      }
      
      1. Authenticate with AM 1 pmtest module:
      curl -X POST \
        'http://test.example.com:8080/openam/json/realms/root/authenticate?authIndexType=module&authIndexValue=pmtest' \
        -H 'Accept-API-Version: resource=2.0,protocol=1.0' \
        -H 'oidc_id_token: eyJ0eXAiOiJKV1QiLCJraWQiOiJ3VTNpZklJYUxPVUFSZVJCL0ZHNmVNMVAxUU09IiwiYWxnIjoiUlMyNTYifQ...........h6hUVCDMOikQ70My3nzL6uf1NLi7c1mDWHeq_6-8z2SCMOSORPURFX2jjsxKzd3UkWlw9YGNEWgk2SwC0GuEZsVy2hVJiPenKkB92yOjELUSM7ONXlbUnLK4QWNrY9si7RX6GMSjeom1bkP9Zg3zs5BbQkskpgJfBirZ_ydUUUACMDxJSDPc0SXGBCI07XLEpRjahqjF0hknoZ_xXPeQ_zsdpODNMnIx-c2H6XurCQW-lfg69DVL7dKj1_ySdgZRvL_yYeeVee6W9Tt33mBtV6NiMZJQ-BVkFdCSRcW2NyjPGMlZ3CSmnFYXn_I6eo4keyq2vZaFPgEYHRkviDsNuQ' \
        -d '{}'
      

      Case Scenario 2:

      1. Authenticate with AM 1 pmtest module (Able to obtain SSO Token ID):
      curl -X POST \
        'http://test.example.com:8080/openam/json/realms/root/authenticate?authIndexType=module&authIndexValue=pmtest' \
        -H 'Accept-API-Version: resource=2.0,protocol=1.0' \
        -H 'oidc_id_token: eyJ0eXAiOiJKV1QiLCJraWQiOiJ3VTNpZklJYUxPVUFSZVJCL0ZHNmVNMVAxUU09IiwiYWxnIjoiUlMyNTYifQ...........h6hUVCDMOikQ70My3nzL6uf1NLi7c1mDWHeq_6-8z2SCMOSORPURFX2jjsxKzd3UkWlw9YGNEWgk2SwC0GuEZsVy2hVJiPenKkB92yOjELUSM7ONXlbUnLK4QWNrY9si7RX6GMSjeom1bkP9Zg3zs5BbQkskpgJfBirZ_ydUUUACMDxJSDPc0SXGBCI07XLEpRjahqjF0hknoZ_xXPeQ_zsdpODNMnIx-c2H6XurCQW-lfg69DVL7dKj1_ySdgZRvL_yYeeVee6W9Tt33mBtV6NiMZJQ-BVkFdCSRcW2NyjPGMlZ3CSmnFYXn_I6eo4keyq2vZaFPgEYHRkviDsNuQ' \
        -d '{}'
      
      {
          "tokenId": "d1Xf9cK7uyEcsuuLTP4Fvp4wpd0.*AAJTSQACMDEAAlNLABxvNHNSblZ1ZGdJWDVNSDB2b0tsRVhQbVErTTg9AAR0eXBlAANDVFMAAlMxAAA.*",
          "successUrl": "/openam/console",
          "realm": "/"
      }
      
      1. Authenticate with AM 1 amtest module:
      curl -X POST \
        'http://test.example.com:8080/openam/json/realms/root/authenticate?authIndexType=module&authIndexValue=amtest' \
        -H 'Accept-API-Version: resource=2.0,protocol=1.0' \
        -H 'oidc_id_token: eyJ0eXAiOiJKV1QiLCJraWQiOiJ3VTNpZklJYUxPVUFSZVJCL0ZHNmVNMVAxUU09IiwiYWxnIjoiUlMyNTYifQ...........j2OR3AlyOFudpTZdw5e9oUc7gTD3uklRuqhFh5mdLDCS6bXJg_JYOgi7sVqD9U7IZGCy1XTo-75buA0CZ71wnxMuCw1EekcetfochNxI_eIovZNPlwd1DWLaAXKhE1FtIIViRI7i0KrgPG7syiGSaP3YcBvP-mr8V2SJ4jyYEnDSRjn9fYKxvACXJP6W8f8Goc2ZU22aZruQfO6AZq4gvN-yaIlJcZVCRf6WHVHovXGEphZZ9nz9kH-ZK_6mWQs7O9_mFydv-7SLgtEOy0zbC2SwvxZ4QLH3USzYfV1d0dO8TXrfDLGtJgUQGt0Ohaps80fyEqdKIg-O_BnMioAo-A' \
        -d '{}'
      
      Expected behaviour
      {
          "tokenId": "..........",
          "successUrl": "/openam/console",
          "realm": "/"
      }
      Current behaviour
      {
          "code": 401,
          "reason": "Unauthorized",
          "message": "Authentication Failed"
      }
      

       

      Code analysis

      Resolver for the same configuration value would not create a new resolver. Instead, it would obtain the resolver from caching which mapped to different issuer. Hence, when verifying the identify of the issuer, it would have the invalid issuer mismatch.

      org/forgerock/openam/authentication/modules/oidc/JwtHandler.java
      // See if a resolver is present corresponding to jwt issuer, and if not, add, then dispatch validation to
      // resolver.
      OpenIdResolver resolver = null;
      try {
      ..........
              resolver = openIdResolverCache.getResolverForIssuer(config.getCryptoContextValue()); 
          }
          if (resolver == null) {
      .........
              resolver = openIdResolverCache.createResolver(jwtClaimSetIssuer, config.getCryptoContextType(),
                      cryptoContextValue, config.getCryptoContextUrlValue()); 
          }
      ..........
      try {
          resolver.validateIdentity(signedJwt);
      } catch (OpenIdConnectVerificationException oice)
      ..........
      org/forgerock/commons/forgerock-openid-resolver/24.0.1/forgerock-openid-resolver-24.0.1.jar!/org/forgerock/oauth/resolvers/BaseOpenIdResolver.class
      private void verifyIssuer(String issuerName) throws InvalidIssException {
          if (!this.issuer.equals(issuerName)) {
              throw new InvalidIssException("Invalid issuer");
          }
      }
      .........
      
      public void validateIdentity(SignedJwt idClaim) throws OpenIdConnectVerificationException {
              if (idClaim == null) {
                  throw new OpenIdConnectVerificationException("A valid SignedJWT must be supplied to the resolver");
              } else {
                  this.verifyIssuer(idClaim.getClaimsSet().getIssuer());
                  this.verifyExpiration(idClaim.getClaimsSet().getExpirationTime());
              }
          }
      
          public String getIssuer() {
              return this.issuer;
          }
      }

       

       

      Workaround/ How to avoid this situation with AM

      If you have a client application which will use more than one OAuth2 agent, then publish the same JWKS_URI for all of them. Don't try to create a dedicated JWKS_URI for each of them, that's unnecessary.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                lawrence.yarham Lawrence Yarham
                Reporter:
                wanning.tan WanNing Tan
              • Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: