IBM Verify

 View Only

Proof Key For Code Exchange: Implementing PKCE through Advanced Mapping Rule In IBM Verify Access Relying Party

By Adarsh Nair posted Wed January 24, 2024 03:08 AM

  

Co Authored By Tushar Prasad

Challenge

Authentication and Authorization are one of the pillars in Identity fabric. It becomes important for organizations to strengthen each and every thread. OpenID connect is one of the important protocols which provide Single Sign On and one of the integration points which helps organizations running a multi cloud or hybrid cloud environment to seamlessly consume identities.

In this scenario of openID connect, this article discusses a solution on strengthening on how an OpenID relying party connects to an OpenID Provider and implementing an interception attack resistant solution.

INTERACTION Diagram:

Topic:
Implementing Proof Key For Code Exchange for IBM Security Verify Access Relying Party Flow

Demonstration: IBM Security Verify SaaS is chosen as an OIDC OpenID Provider


Relying Party: IBM Security Verify Access
OIDC OP: Verify SaaS

Introduction of PKCE:

Proof Key for Code Exchange (PKCE) support is a capability (defined in RFC 7636) that adds security when performing the authorization code flow.

It addresses following security concerns for clients:

·       Clients cannot store client_secret (Single Page Applications, native apps).

·     Prevents Authorization Code Interception Attack where a malicious client (e.g native app) intercepts the authorization code returned from the authorization endpoint and uses it to obtain the access token.

How PKCE Works:

Clients generate random string and perform (BASE64URL (SHA256  (random string))) on this string. 

The Hash(code_challenge) is sent in Authorize request along with Hash method used (code_challenge_method).

The initial random string(code_verifier) is sent in the token request.

The Authorization server validates the hash of the code_verifier against the code_challenge using the code_challenge_method.

On successful validation, token is returned to client.

How PKCE addresses security concerns:

Clients will have to present code_verifier in the token request. The hash of the code_verifier is validated against the code_challenge sent by the client in the initial authorize request. 

Pre-requisites

    IBM Security Verify Relying Party Federation is already required to be set. The link will help to achieve how to set that.
       https://www.ibm.com/support/pages/ibm-security-access-manager-federation-cookbook

·      IBM Verify Access Java doc needs to be referred as all methods to generate code_challenge is used

Flow:

The processing flow is as follows:

1.  Client generates a code_verifier, and computes code_challenge using code_challenge_method.

2.  Client makes request to /authorize.

3.  Authorization server performs standard OAuth request validation for /authorize.

4.  Authorization server checks for presence of code_challenge and code_challenge_method.

5.  Authorization server stores code_challenge and code_challenge_method against authorization code.

6.  Authorization server returns authorization code response.

7.  Client presents authorization code to /token including the additional code_verifier.

8.  Authorization server performs standard OAuth request validation for /token.

9.  Authorization server generates its own code_challenge, using the presented code_verifier, and the stored code_challenge_method.

10. Authorization server compares its generated code_challenge, to the value which was presented in the initial request to /authorize(and stored against the authorization code).

11.   If the two match, then an access_token is issued. If the two do not, the request is rejected.

High Level STEPS:

    Import mapping rules:

      OIDC_addPKCEAttributes.js
      OIDC_oidc_adv_pkce.js 

  • Make sure advanced mapping rule is used in Federation

ISVA Relying Party Configuration:

            Import Mapping Rules

     Federations-> Mapping Rules

Mapping Rule Description:

In this OIDC integration between Verify Access (Relying Party) and IBM Verify SaaS(OP), following mapping rules are used.

                                             i.     OIDCRP (oidc_rp.js) -> generic , given here as an example

                                           ii.     oidc_adv_pkce -> Generic that comes with product with tweak to include pkce

                                         iii.     AddPKCEAttributes -> logic that contains generating PKCE

    Mapping Rule addPKCEAttributes

  • This mapping rule is the core of Generating Proof Key for code exchange , code verifier and code challenge.Main parts of the rule.It checks whether its a call to be made to /authorize endpoint Generates code verifier and code challenge and stores code verifier into ext cache to be used during token endpoint call.(check notes later for alternate way to store it).

function getCodeVerifierandChallenge() {





var hashval="";

codeverifier=OAuthMappingExtUtils.generateRandomString(randomstringlength);

hashval = OAuthMappingExtUtils.SHA256Sum(codeverifier);

hashofverifier = BASE64Utility.encode(hashval, false);

codechallenge=hashofverifier.toString().replace('+','-').replace('/','_').replace('=','');

return [codeverifier,codechallenge]

}

if(operation == "authorize"){





var state = stsuu.getContextAttributes().getAttributeValueByNameAndType("state","urn:ibm:SAM:oidc:rp:authorize:req:param");

var lookupkey = state+"_codeverifier";





IDMappingExtUtils.traceString("oidc_rp_adv pkce generation:\n " + "\n");





verifychallenge = getCodeVerifierandChallenge()





codeverifier = verifychallenge[0];

codechallenge = verifychallenge[1]





extcache.put(lookupkey,codeverifier, ttl);





stsuu.addContextAttribute(new Attribute("code_challenge", "urn:ibm:SAM:oidc:rp:authorize:req:param", codechallenge));

stsuu.addContextAttribute(new Attribute("code_challenge_method", "urn:ibm:SAM:oidc:rp:authorize:req:param", code_challenge_method));





}

·       It stores generated code verifier into external cache wherein code_challenge_method is S256

·       Lookupkey is chosen here to be state concatenation with a fixed string which is available at /authorize endpoint

·      ISVA relying party checks and does the following call during /token endpoint call

if(operation == "token"){

var state = stsuu.getContextAttributes().getAttributeValueByNameAndType("state","urn:ibm:SAM:oidc:rp:authorize:rsp:param");





var lookupkey = state+"_codeverifier";

try{

var tokenchallenge = extcache.getAndRemove(lookupkey);

}

catch(error)

{

IDMappingExtUtils.traceString("Error During GetandRemove " +error);

}






var codechallengeintoken = new com.tivoli.am.fim.trustserver.sts.uuser.Attribute("code_verifier", "urn:ibm:SAM:oidc:rp:token:req:param" , tokenchallenge);

stsuu.addContextAttribute(codechallengeintoken);





}

·     Extcache.getAndRemove() is to get the stored code verifier which is passed to the /token endpoint call.

·     All the above are part of addPKCEAttributes

Mapping Rule: oidc_adv_pkce

·     Any existing advanced ISVA relying party mapping rule can be augmented with PCKE capabilities by putting these

importMappingRule("addPKCEAttributes");

//invoke pkce rule

const use_pkce=true;





if(use_pkce)

{

if(operation == "authorize" || operation== "token")

{

addPKCEAttributes();

}

}

Mapping Rule: OIDCRP 

  • It’s an identity mapping rule
  • In case you already not using one then you can use a sample from
  •  System-> File Downloads->federation->mapping_rules-> oidc_rp.js  with below changes

Before:

var sub = stsuu.getAttributeContainer().getAttributeValueByName("sub");
  
 After:
 var sub = stsuu.getAttributeContainer().getAttributeValueByName("email");

Alternative approach to store key lookup instead of extcache.put(lookupkey,codeverifier, ttl);

IDMappingExtUtils -> into user sessions

 

setSPSSessionData(java.lang.String key, java.lang.String value)

removeSPSSessionData(java.lang.String key)  

Configuration Steps:

The configuration steps defined in this blog can be used to integrate with IBM Verify ,IBM Verify Access and other OP Providers as well.

Prerequisites:

Note below items from IBM Verify tenant:

1.   Client ID
Applications->Applications->Select the OIDC Application Settings -> API access


e.g

2.  Metadata endpoint:
Applications->Applications->Select the OIDC Application Settings -> Sign-on

e.g.

Create Federation:

Federation -> Federations







Partner Configuration:

Configure Reverse Proxy for Federation:








Flow in Action:

Below is the Kickoff URL used to initiate the OIDC flow

Kickoff URL:

https://oidcrp106:444/isam/sps/oidc/rp/oidcrp/kickoff/verifyop?Target=https://oidcrp106:444/

Authorize call:

GET

https://xx.verify.ibm.com/v1.0/endpoint/default/authorize?redirect_uri=https://oidcrp106:444/isam/sps/oidc/rp/oidcrp/redirect/verifyop&code_challenge=HvQiJkzKLXbLROLL1FXfQfspx5VRwTRRPNWTnliGmJY&response_type=code&state=y5HQPVTgFB&scope=openid&code_challenge_method=S256&client_id=bf871bc2-0782-46f0-87ad-31d900d572e3

        

Following can be observed in the trace log.
Authorization Request:

 [11/8/23, 3:36:56:870 EST] 0000018f id=00000000 om.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils > traceString ENTRY ****** Code Verifier: slF6NlnA2zVx4ss1j5AV

[11/8/23, 3:36:56:870 EST] 0000018f id=00000000 om.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils < traceString RETURN

[11/8/23, 3:36:56:870 EST] 0000018f id=00000000 i.am.fim.trustserver.sts.utilities.IDMappingExtCacheDMAPImpl > put ENTRY y5HQPVTgFB_codeverifier slF6NlnA2zVx4ss1j5AV 300

[11/8/23, 3:36:56:873 EST] 0000018f id=00000000 i.am.fim.trustserver.sts.utilities.IDMappingExtCacheDMAPImpl < put RETURN

[11/8/23, 3:36:56:873 EST] 0000018f id=00000000 om.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils > traceString ENTRY ****** Setting inside codeverifier: slF6NlnA2zVx4ss1j5AV challenge method:  S256

[11/8/23, 3:36:56:873 EST] 0000018f id=00000000 om.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils < traceString RETURN

[11/8/23, 3:36:56:874 EST] 0000018f id=00000000 om.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils > traceString ENTRY

 OIDC kickoff request parameters are:

kickoff attribute name: method

kickoff attribute value: GET

kickoff attribute name: Target

kickoff attribute value: https://oidcrp106:444/

 /authorize url is: https://axxverify.ibm.com/v1.0/endpoint/default/authorize

 OIDC authorize request parameters are:

request attribute: redirect_uri=https://oidcrp106:444/isam/sps/oidc/rp/oidcrp/redirect/verifyop

request attribute: code_challenge=HvQiJkzKLXbLROLL1FXfQfspx5VRwTRRPNWTnliGmJY

request attribute: response_type=code

request attribute: state=y5HQPVTgFB

request attribute: scope=openid

request attribute: code_challenge_method=S256

request attribute: client_id=bf871bc2-0782-46f0-87ad-31d900d572e3


The Token request and response are Backchannel calls.

Token Request:

[11/8/23, 3:39:13:873 EST] 0000018e id=00000000 .oidc10.protocol.delegate.rp.OidcRelyingPartyLandingDelegate 1 getInitialParameters Adding token request value: code_verifier=[slF6NlnA2zVx4ss1j5AV]

[11/8/23, 3:39:13:873 EST] 0000018e id=00000000 com.tivoli.am.fim.oidc10.rp.OidcRelyingParty                 > doTokenExchange ENTRY PJ0i0GhFMQMUi_D12lVczH1BF8xtZPFdflHPitnnILA.8V1Z0uUFs0gl69z_dTzGDm_UqEyTZrp1NUAZc5FMASdTY2Wt4xGQbJNVXy14MqUrjniFjB50d8TGjfZeAML5Tg https://oidcrp106:444/isam/sps/oidc/rp/oidcrp/redirect/verifyop y5HQPVTgFB MAP{code_verifier=[slF6NlnA2zVx4ss1j5AV],}

[11/8/23, 3:39:13:873 EST] 0000018e id=00000000 com.tivoli.am.fim.soap.client.HttpClientImpl                 1 HttpClientImpl URLEndPoint = https://xx.verify.ibm.com/v1.0/endpoint/default/token Timeout = 0

[11/8/23, 3:39:13:873 EST] 0000018e id=00000000 com.tivoli.am.fim.soap.client.HttpClientImpl                 1 HttpClientImpl Using Basic Authentication with User Id = bf871bc2-0782-46f0-87ad-31d900d572e3



Token Response:

[11/8/23, 3:39:14:274 EST] 0000018e id=00000000 com.tivoli.am.fim.oidc10.rp.OidcRelyingParty                 < doTokenExchange RETURN {"access_token":"Exk9WfO9f0K2lEsUZR8P8sT32aiubpL3Ka0E6NUv","scope":"openid","grant_id":"9f70f38b-0b5c-4ede-8306-83a63b1e08ae","id_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6InNlcnZlciIsInR5cCI6IkpXVCJ9.<<SNIPPED OUT>>.hJVSMTnbAQNyA2ajV02UGRYYZMcSxJVw9S1nG79UQuae9rXy6tnMmkBmvujj0UCyOnOI7Y8xmSsTS2XCz9h48g-vD_1S4E-AGuYudAc_f4GTWhqAibLLUk7JNe35lDOZ2ICV-owZaEe4tb8GeLqmAEr4_t0hmDfxvxsrbjuM5-Op21NuMpwnxwLIyd8kk3B6E8HBrYlsbNoVDVwDrqoAwI-pHfm3qZ6yGX79rGd5UALzuHnEgV2kUVrVeUqWOEI3W_LZSPtlOHX2Wiiklfs1ytv43uJaT17seNcosAMGG1N0Q_Gl9vi0O610p5rYFfrtFWeJ2VxvIKb5i-d90gMd6g","token_type":"Bearer","expires_in":7199}




PFA :

1. OIDC_addPKCEAttributes.js
                 
 https://github.com/IBM-Security/isam-support/blob/master/src/oauth/RelyingPartyPKCE/Implement_PKCE_Verify_Access_addPKCEAttributes.js

2. OIDC_oidc_adv_pkce.js
                   https://github.com/IBM-Security/isam-support/blob/master/src/oauth/RelyingPartyPKCE/Implement_PKCE_Verify_Access_oidc_adv_pkce.js



Summary

The steps will help to enable IBM Security Verify Access Relying Party to be able to use PKCE against any OpenID provider whether it’s a mutli cloud or a hybrid cloud environment and thus enhancing the security by making Authorization code flow secure and resistant to interception attack.The steps are plug and play into existing Relying Party flow in Verify Access.



0 comments
76 views

Permalink