[OPENAM-9074] wrong acr_values mapping makes the authorization flow looping Created: 10/Jun/16  Updated: 24/Oct/17  Resolved: 22/Jun/16

Status: Resolved
Project: OpenAM
Component/s: oauth2
Affects Version/s: 13.5.0
Fix Version/s: 12.0.5, 13.5.0

Type: Bug Priority: Major
Reporter: Quentin CASTEL [X] (Inactive) Assignee: Dipu Seminlal
Resolution: Fixed Votes: 0
Labels: 13.5.0-Should-Fix, AME, TESLA
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Relates
relates to OPENAM-9198 Device flow usercode form send twice ... Resolved
Target Version/s:
Support Ticket IDs:
Verified Version/s:

 Description   

How to reproduce

  • Create a oauth2 environment (provider and client)
  • Create a loa mapping
"loaMapping": {
    "chain1": "ldapService"
  },

Note: as OPENAM-9025 is not fixed yet, you can use

curl -X PUT -H "Accept: application/x-www-form-urlencoded" -H "Content-Type: application/json" -H "iplanetDirectoryPro: AQIC5wM2LY4SfczKl0s4FXIuX3VKU5CiIFBTxZZI3oR2Pdw.*AAJTSQACMDEAAlNLABQtNzkzMDc5MTgwNDAwNDgyMjc2OQACUzEAAA..*" -H "Cache-Control: no-cache" -H "Postman-Token: 0dc1f260-0ca9-8181-d2cc-dd657b55964e" -d '{
   "storeOpsTokens":true,
   "alwaysAddClaimsToToken":false,
   "oidcClaimsScript":"36863ffb-40ec-48b9-94b1-9a99f71cc3b5",
   "keypairName":"test",
   "supportedScopes":[
      "openid|",
      "email|Your email address",
      "address|Your postal address",
      "phone|Your telephone number(s)",
      "profile|Your personal information"
   ],
   "responseTypeClasses":[
      "id_token|org.forgerock.openidconnect.IdTokenResponseTypeHandler",
      "code|org.forgerock.oauth2.core.AuthorizationCodeResponseTypeHandler",
      "token|org.forgerock.oauth2.core.TokenResponseTypeHandler"
   ],
   "issueRefreshTokenOnRefreshedToken":false,
   "supportedSubjectTypes":[
      "public"
   ],
   "defaultACR":"",
   "jkwsURI":"",
   "jwtTokenLifetime":3600,
   "scopeImplementationClass":"org.forgerock.openam.oauth2.OpenAMScopeValidator",
   "supportedIDTokenSigningAlgorithms":[
      "ES384",
      "HS256",
      "HS512",
      "ES256",
      "RS256",
      "HS384",
      "ES512"
   ],
   "deviceCodeLifetime":300,
   "devicePollInterval":5,
   "displayNameAttribute":"cn",
   "defaultScopes":[
      "address",
      "phone",
      "openid",
      "profile",
      "email"
   ],
   "supportedIDTokenEncryptionAlgorithms":[
      "RSA1_5"
   ],
   "accessTokenLifetime":3600,
   "customLoginUrlTemplate":"",
   "hashSalt":"",
   "savedConsentAttribute":"",
   "authenticationAttributes":[
      "uid"
   ],
   "tokenSigningECDSAKeyAlias":[
      "ES512|test",
      "ES256|test",
      "ES384|test"
   ],
   "modifiedTimestampAttribute":"",
   "codeLifetime":120,
   "tokenSigningAlgorithm":"HS256",
   "issueRefreshToken":false,
   "supportedIDTokenEncryptionMethods":[
      "A128CBC-HS256",
      "A256CBC-HS512"
   ],
   "generateRegistrationAccessTokens":true,
   "codeVerifierEnforced":false,
   "completionUrl":"",
   "supportedClaims":[
      "phone_number|Phone number",
      "family_name|Family name",
      "given_name|Given name",
      "locale|Locale",
      "email|Email address",
      "profile|Your personal information",
      "zoneinfo|Time zone",
      "address|Postal address",
      "name|Full name"
   ],
   "loaMapping":{
      "chain1":"ldapService"
   },
   "verificationUrl":"",
   "claimsParameterSupported":false,
   "allowDynamicRegistration":false,
   "tokenSigningHmacSharedSecret":"cx/2OTDM4Gx63O9vxxnhSme9BMUzIZU2CP9/Figm5cI=",
   "refreshTokenLifetime":604800,
   "createdTimestampAttribute":"",
   "clientsCanSkipConsent":false,
   "statelessTokensEnabled":false,
   "idTokenInfoClientAuthenticationEnabled":true,
   "_id":"",
   "_type":{
      "_id":"oauth-oidc",
      "name":"OAuth2 Provider",
      "collection":false
   }
}' "http://openam.example.com:13081/openam/json/realm-config/services/oauth-oidc"

Then try the authorization grant flow 'acr_values=wrong_chain'

http://openam.example.com:13081/openam/oauth2/authorize?response_type=code&client_id=myClientID&realm=%2F&scope=openid%20profile&redirect_uri=http%3A%2F%2Fopenam.example.com%3A13081%2Fopenid%2Fcb-basic.html&state=af0ifjsldkj&acr_values=wrong_chain

expected result

A error message telling you that this acr_values doesn't map the arm_mapping

Current result

We currently check if the acr_values is valid with the token authentication contexte. It doesn't so we redirect the user to the login page. => OK

We build the URL like this

 private URI buildDefaultLoginUrl(OAuth2Request request, String gotoUrl, String acrValues, String realm,
            String moduleName, String serviceName, String locale) throws URISyntaxException, ServerException,
            NotFoundException {

        final Request req = request.getRequest();
        final String authURL = getAuthURL(getHttpServletRequest(req));
        final URI authURI = new URI(authURL);
        final Reference loginRef = new Reference(authURI);

        if (!isEmpty(realm)) {
            loginRef.addQueryParameter(OAuth2Constants.Custom.REALM, realm);
        }
        if (!isEmpty(locale)) {
            loginRef.addQueryParameter(LOCALE, locale);
        }

        // Prefer standard acr_values, then module, then service
        if (!isEmpty(acrValues)) {
            final ACRValue chosen = chooseBestAcrValue(request, acrValues.split("\\s+"));
            if (chosen != null) {
                loginRef.addQueryParameter(chosen.method.getIndexType().toString(), chosen.method.getName());

                // Adjust the GOTO url to indicate which acr value was actually chosen
                req.getResourceRef().addQueryParameter(OAuth2Constants.JWTTokenParams.ACR, chosen.acr);
            }
        } else if (!isEmpty(moduleName)) {
            loginRef.addQueryParameter(MODULE, moduleName);
        } else if (!isEmpty(serviceName)) {
            loginRef.addQueryParameter(SERVICE, serviceName);
        }

        loginRef.addQueryParameter(GOTO, gotoUrl);

        return loginRef.toUri();
    }

This is where is is interesting:

 final ACRValue chosen = chooseBestAcrValue(request, acrValues.split("\\s+"));
            if (chosen != null) {

If the ACRValue match with none of the loaMapping, we ignore the acr_value.

Possibility of fix

Solution 1 : we considere that every acr_values should correspond to a chain thanks to the loaMapping

That the solution I prefere, as in my opinion, I considere the request invalid if one of the acr_values isn't mapping a chain.

Solution 2: If a acr_value is wrong, so not mapping found, we ignore this value.

Therefore, we should clean the list of acr_values first before doing

    private void setCurrentAcr(SSOToken token, OAuth2Request request, String acrValuesStr)
            throws NotFoundException, ServerException, SSOException, AccessDeniedException,
            UnsupportedEncodingException, URISyntaxException, ResourceOwnerAuthenticationRequired {


 Comments   
Comment by Jonathan Scudder [ 14/Jun/16 ]

Bug triage: please consult with Phill/JamesP and others regarding the preferred fix

Comment by James Phillpotts [ 17/Jun/16 ]

Looking at the OIDC spec, the following sections are relevant:

It seems to me that the appropriate action is instead of requiring authentication when there is no matching acr for the requested ones, that we instead set the acr claim to 0, as per the second reference above.

Comment by Ľubomír Mlích [ 23/Oct/17 ]

I'm trying to verify this issue in OpenAM 13.0.0-SECURITY-SNAPSHOT Build 7cb4977b53 (2017-October-12 16:24) 

I see standard 13.0 show login screen again as described it would and in debug, there is No ACR value matched. Security patched OpenAM version let me login, but there is no error on screen. In debug I see another No ACR value matched. Is it ok? Thanks.

Comment by Ľubomír Mlích [ 24/Oct/17 ]

Verified in OpenAM 13.0.0-SECURITY-SNAPSHOT Build 7cb4977b53 (2017-October-12 16:24) 

  • there is no error displayed but I can see ACR is set to zero in debug
Generated at Fri Nov 27 06:34:12 UTC 2020 using Jira 7.13.12#713012-sha1:6e07c38070d5191bbf7353952ed38f111754533a.