diff --git a/Esignet/README.md b/Esignet/README.md index cc240323..c05493da 100644 --- a/Esignet/README.md +++ b/Esignet/README.md @@ -4,8 +4,8 @@ 1. Management API Endpoints 2. UI API Endpoints 3. OIDC API Endpoints - 4. Wallet Binding Endpoints - + 4. Wallet Binding Endpoints + 5. VCI API Endpoint * Open source Tools used, 1. [Apache JMeter](https://jmeter.apache.org/) @@ -22,13 +22,15 @@ * Create Identities in MOSIP Authentication System (Setup) : This thread contains the authorization api's for regproc and idrepo from which the auth token will be generated. There is set of 4 api's generate RID, generate UIN, add identity and add VID. From here we will get the VID which can be further used as individual id. These 4 api's are present in the loop controller where we can define the number of samples for creating identities in which "addIdentitySetup" is used as a variable. -* Create OIDC Client in MOSIP Authentication System (Setup) : This thread contains a JSR223 sampler(Generate Key Pair) from which will get a public-private key pair. The public key generated will be used in the OIDC client api to generate client id's which will be registered for both IDA and eSignet. The private key generated from the sampler will be used in another JSR223 sampler(Generate Client Assertion) present in the OIDC Token (Execution). Generated client id's and there respective private key will be stored in a file which will be used further in the required api's. + +* Create OIDC Client in MOSIP Authentication System (Setup) : This thread contains a JSR223 sampler(Generate Key Pair) from which will get a public-private key pair. The public key generated will be used in the OIDC client api to generate client id's which will be registered for both IDA and Esignet. The private key generated from the sampler will be used in another JSR223 sampler(Generate Client Assertion) present in the OIDC Token (Execution). Generated client id's and there respective private key will be stored in a file which will be used further in the required api's. + * In the above Create OIDC Client in MOSIP Authentication System (Setup) check for the Policy name and Auth partner id for the particular env in which we are executing the scripts. The policy name provided must be associated with the correct Auth partner id. * For execution purpose neeed to check for the mentioned properties: - * eSignet default properties: Update the value for the properties according to the execution setup. Perform the execution for eSignet api's with redis setup. So check for the redis setup accordingly. + * esignet default properties: Update the value for the properties according to the execution setup. Perform the execution for Esignet api's with redis setup. So check for the redis setup accordingly. mosip.esignet.cache.size - Enabled while not using the redis setup. Can keep the cache size around more than 100k. mosip.esignet.cache.expire-in-seconds - 86400 @@ -85,14 +87,18 @@ 9.25.6 + ### Execution points for eSignet Management API's + * Management - Create OIDC Client (Execution) : This thread group will directly execute in which we are using a counter which will generate unique client id. Because we can't generate same duplicate cliend id. * Management - Update OIDC Client : * Management Update OIDC Client (Preparation) - In this the above mentioned Create OIDC Client API will be used to generate a large number of OIDC client id samples which will get stored in a file and will be used in the execution. * Management Update OIDC Client (Execution) - Thread will use the client id file generated in the preparation part. We can reuse the file for multiple runs and the number of preparation samples should be greater or equal to the number of execution samples. + ### Execution points for eSignet UI API's + * UI - OAuth Details : * OAuth Details (Execution) - Client id created from Create OIDC Client in MOSIP Authentication System (Setup) will be loaded. Total samples created during execution can be higher in number as compared to the samples present in the file. @@ -124,7 +130,9 @@ * Link Authorization Code (Preparation) - This thread includes 6 api's OAuth Details, Generate Link Code, Link Transaction, Send OTP Linked Auth, linked authenication and linked consent api. Transaction id and linked code must be same as the one received from oauth-details and generate link code api respectively. * Link Authorization Code (Execution) - Transaction id and linked code will be used from the preparation part. + ### Execution points for eSignet OIDC API's + * OIDC - Authorization : Its a GET API with no preparations and application will do a browser redirect to this endpoint with all required details passed as query parameters. * OIDC - Token : @@ -137,7 +145,13 @@ * OIDC - Configuration (Execution) : Open ID Connect dynamic provider discovery is not supported currently, this endpoint is only for facilitating the OIDC provider details in a standard way. -* OIDC - JSON Web Key Set (Execution) : Endpoint to fetch all the public keys of the eSignet server.Returns public key set in the JWKS format. + +* OIDC - JSON Web Key Set (Execution) : Endpoint to fetch all the public keys of the Esignet server.Returns public key set in the JWKS format. + +### Execution points for eSignet VCI API +* VCI - Get Credential (Praparation) - For the preparation we need 5 api's OAuth Details, Send OTP, Authentication, Authorization Code and Token Endpoint api from which a access token will be generated. Will also use a JSR223 Post processor in which we are having a groovy code which is generating a proof jwt value which will be used in the execution. Both access token and proof jwt values will be stored in a text file which will be used for execution. + +* VCI - Get Credential (Execution) - In this thread group will have the get credential endpoint API for execution which will use the generated access token and proof jwt values from the preparation part. We cant use the preparation file for multiple runs so the total number of samples generated from preparation should be equal or higher in number as compared to execution. ### Execution points for eSignet Wallet Binding API's @@ -149,3 +163,4 @@ * Wallet Binding (Execution) - In this thread will pass the auth factor type as "WLA". Also, a JWT format binding public key which will be generated from a code written in JSR223 preprocessor. Will use the file generated from the preparation and it can't be used multiple times. + diff --git a/Esignet/scripts/Esignet_Helper_Script.jmx b/Esignet/scripts/Esignet_Helper_Script.jmx index f065b4a1..1a378ee6 100644 --- a/Esignet/scripts/Esignet_Helper_Script.jmx +++ b/Esignet/scripts/Esignet_Helper_Script.jmx @@ -45,6 +45,7 @@ = + clientIdMobile mpartner-default-mobile @@ -61,6 +62,7 @@ = + @@ -161,6 +163,7 @@ + true @@ -244,6 +247,7 @@ + false diff --git a/Esignet/scripts/Esignet_Test_Script.jmx b/Esignet/scripts/Esignet_Test_Script.jmx index 4dd93401..741e3be5 100644 --- a/Esignet/scripts/Esignet_Test_Script.jmx +++ b/Esignet/scripts/Esignet_Test_Script.jmx @@ -155,6 +155,18 @@ = + + delay + 3000 + = + + + scopeVci + mosip_identity_vc_ldp + = + + + walletPartnerId 787 @@ -166,6 +178,7 @@ = + @@ -182,6 +195,7 @@ + , @@ -195,6 +209,7 @@ + continue @@ -1387,7 +1402,13 @@ vars.put("utcTime", utcTime); }, "nonce": "973eieljzng", "state": "eree2311", + + "claimsLocales": "en", + "codeChallenge" : "${codeChallenge}", + "codeChallengeMethod" : "S256" + "claimsLocales": "en" + } } = @@ -1398,7 +1419,11 @@ vars.put("utcTime", utcTime); ${serverPortNo} ${protocol} + + /v1/esignet/authorization/v2/oauth-details + /v1/esignet/authorization/oauth-details + POST true false @@ -1446,6 +1471,33 @@ vars.put("utcTime", utcTime); 2 + + + groovy + + + true + import org.apache.commons.codec.binary.Base64; +import java.security.SecureRandom; +import java.security.MessageDigest; + +SecureRandom secureRandom = new SecureRandom(); +byte[] codeVerifierBytes = new byte[32]; // 256 bits +secureRandom.nextBytes(codeVerifierBytes); + +String codeVerifier = Base64.encodeBase64URLSafeString(codeVerifierBytes); +vars.put("codeVerifier", codeVerifier); +log.info("codeVerifier: " + codeVerifier); + +MessageDigest digest = MessageDigest.getInstance("SHA-256"); +byte[] hash = digest.digest(codeVerifier.getBytes("UTF-8")); +String codeChallenge = Base64.encodeBase64URLSafeString(hash); +vars.put("codeChallenge", codeChallenge); +log.info("codeChallenge: " + codeChallenge); + + + + @@ -1524,7 +1576,13 @@ vars.put("utcTime", utcTime); }, "nonce": "973eieljzng", "state": "eree2311", + + "claimsLocales": "en", + "codeChallenge" : "${codeChallenge}", + "codeChallengeMethod" : "S256" + "claimsLocales": "en" + } } = @@ -1535,7 +1593,11 @@ vars.put("utcTime", utcTime); ${serverPortNo} ${protocol} + + /v1/esignet/authorization/v2/oauth-details + /v1/esignet/authorization/oauth-details + POST true false @@ -1583,6 +1645,33 @@ vars.put("utcTime", utcTime); 2 + + + groovy + + + true + import org.apache.commons.codec.binary.Base64; +import java.security.SecureRandom; +import java.security.MessageDigest; + +SecureRandom secureRandom = new SecureRandom(); +byte[] codeVerifierBytes = new byte[32]; // 256 bits +secureRandom.nextBytes(codeVerifierBytes); + +String codeVerifier = Base64.encodeBase64URLSafeString(codeVerifierBytes); +vars.put("codeVerifier", codeVerifier); +log.info("codeVerifier: " + codeVerifier); + +MessageDigest digest = MessageDigest.getInstance("SHA-256"); +byte[] hash = digest.digest(codeVerifier.getBytes("UTF-8")); +String codeChallenge = Base64.encodeBase64URLSafeString(hash); +vars.put("codeChallenge", codeChallenge); +log.info("codeChallenge: " + codeChallenge); + + + + false transactionID @@ -1872,7 +1961,13 @@ vars.put("utcTime", utcTime); }, "nonce": "973eieljzng", "state": "eree2311", + + "claimsLocales": "en", + "codeChallenge" : "${codeChallenge}", + "codeChallengeMethod" : "S256" + "claimsLocales": "en" + } } = @@ -1883,7 +1978,11 @@ vars.put("utcTime", utcTime); ${serverPortNo} ${protocol} + + /v1/esignet/authorization/v2/oauth-details + /v1/esignet/authorization/oauth-details + POST true false @@ -1931,6 +2030,33 @@ vars.put("utcTime", utcTime); 2 + + + groovy + + + true + import org.apache.commons.codec.binary.Base64; +import java.security.SecureRandom; +import java.security.MessageDigest; + +SecureRandom secureRandom = new SecureRandom(); +byte[] codeVerifierBytes = new byte[32]; // 256 bits +secureRandom.nextBytes(codeVerifierBytes); + +String codeVerifier = Base64.encodeBase64URLSafeString(codeVerifierBytes); +vars.put("codeVerifier", codeVerifier); +log.info("codeVerifier: " + codeVerifier); + +MessageDigest digest = MessageDigest.getInstance("SHA-256"); +byte[] hash = digest.digest(codeVerifier.getBytes("UTF-8")); +String codeChallenge = Base64.encodeBase64URLSafeString(hash); +vars.put("codeChallenge", codeChallenge); +log.info("codeChallenge: " + codeChallenge); + + + + false tidAuthEndpoint @@ -2292,7 +2418,13 @@ vars.put("utcTime", utcTime); }, "nonce": "973eieljzng", "state": "eree2311", + + "claimsLocales": "en", + "codeChallenge" : "${codeChallenge}", + "codeChallengeMethod" : "S256" + "claimsLocales": "en" + } } = @@ -2303,7 +2435,11 @@ vars.put("utcTime", utcTime); ${serverPortNo} ${protocol} + + /v1/esignet/authorization/v2/oauth-details + /v1/esignet/authorization/oauth-details + POST true false @@ -2351,6 +2487,33 @@ vars.put("utcTime", utcTime); 2 + + + groovy + + + true + import org.apache.commons.codec.binary.Base64; +import java.security.SecureRandom; +import java.security.MessageDigest; + +SecureRandom secureRandom = new SecureRandom(); +byte[] codeVerifierBytes = new byte[32]; // 256 bits +secureRandom.nextBytes(codeVerifierBytes); + +String codeVerifier = Base64.encodeBase64URLSafeString(codeVerifierBytes); +vars.put("codeVerifier", codeVerifier); +log.info("codeVerifier: " + codeVerifier); + +MessageDigest digest = MessageDigest.getInstance("SHA-256"); +byte[] hash = digest.digest(codeVerifier.getBytes("UTF-8")); +String codeChallenge = Base64.encodeBase64URLSafeString(hash); +vars.put("codeChallenge", codeChallenge); +log.info("codeChallenge: " + codeChallenge); + + + + false transactionIdAuthCodePrep @@ -2911,7 +3074,13 @@ vars.put("utcTime", utcTime); }, "nonce": "973eieljzng", "state": "eree2311", + + "claimsLocales": "en", + "codeChallenge" : "${codeChallenge}", + "codeChallengeMethod" : "S256" + "claimsLocales": "en" + } } = @@ -2922,7 +3091,11 @@ vars.put("utcTime", utcTime); ${serverPortNo} ${protocol} + + /v1/esignet/authorization/v2/oauth-details + /v1/esignet/authorization/oauth-details + POST true false @@ -2970,6 +3143,33 @@ vars.put("utcTime", utcTime); 2 + + + groovy + + + true + import org.apache.commons.codec.binary.Base64; +import java.security.SecureRandom; +import java.security.MessageDigest; + +SecureRandom secureRandom = new SecureRandom(); +byte[] codeVerifierBytes = new byte[32]; // 256 bits +secureRandom.nextBytes(codeVerifierBytes); + +String codeVerifier = Base64.encodeBase64URLSafeString(codeVerifierBytes); +vars.put("codeVerifier", codeVerifier); +log.info("codeVerifier: " + codeVerifier); + +MessageDigest digest = MessageDigest.getInstance("SHA-256"); +byte[] hash = digest.digest(codeVerifier.getBytes("UTF-8")); +String codeChallenge = Base64.encodeBase64URLSafeString(hash); +vars.put("codeChallenge", codeChallenge); +log.info("codeChallenge: " + codeChallenge); + + + + false tidTokenPrep @@ -3287,7 +3487,11 @@ function encodeBase64Url(value) { false + + ${__StringToFile(code_authorization_code_endpoint.txt,${code}\,${tokenClientId}\,${tokenPrivateKey},${codeVerifier}\n,true,)} + ${__StringToFile(code_authorization_code_endpoint.txt,${code}\,${tokenClientId}\,${tokenPrivateKey}\n,true,)} + @@ -3315,7 +3519,11 @@ function encodeBase64Url(value) { true shareMode.all false + + tokenEndpointCode,tokenEndpointClientId,tokenEncodedPrivateKey,codeVerifier + tokenEndpointCode,tokenEndpointClientId,tokenEncodedPrivateKey + @@ -3434,13 +3642,26 @@ vars.put("utcTime", utcTime); true redirect_uri + + + false + ${codeVerifier} + = + true + code_verifier + + ${serverIP} ${serverPortNo} ${protocol} + + /v1/esignet/oauth/v2/token + /v1/esignet/oauth/token + POST true false @@ -3570,7 +3791,13 @@ vars.put("utcTime", utcTime); }, "nonce": "973eieljzng", "state": "eree2311", + + "claimsLocales": "en", + "codeChallenge" : "${codeChallenge}", + "codeChallengeMethod" : "S256" + "claimsLocales": "en" + } } = @@ -3581,7 +3808,11 @@ vars.put("utcTime", utcTime); ${serverPortNo} ${protocol} + + /v1/esignet/authorization/v2/oauth-details + /v1/esignet/authorization/oauth-details + POST true false @@ -3629,6 +3860,33 @@ vars.put("utcTime", utcTime); 2 + + + groovy + + + true + import org.apache.commons.codec.binary.Base64; +import java.security.SecureRandom; +import java.security.MessageDigest; + +SecureRandom secureRandom = new SecureRandom(); +byte[] codeVerifierBytes = new byte[32]; // 256 bits +secureRandom.nextBytes(codeVerifierBytes); + +String codeVerifier = Base64.encodeBase64URLSafeString(codeVerifierBytes); +vars.put("codeVerifier", codeVerifier); +log.info("codeVerifier: " + codeVerifier); + +MessageDigest digest = MessageDigest.getInstance("SHA-256"); +byte[] hash = digest.digest(codeVerifier.getBytes("UTF-8")); +String codeChallenge = Base64.encodeBase64URLSafeString(hash); +vars.put("codeChallenge", codeChallenge); +log.info("codeChallenge: " + codeChallenge); + + + + false tidUserInfoPrep @@ -4045,13 +4303,26 @@ vars.put("clientAssertionJWT", JWT); true redirect_uri + + + false + ${codeVerifier} + = + true + code_verifier + + ${serverIP} ${serverPortNo} ${protocol} + + /v1/esignet/oauth/v2/token + /v1/esignet/oauth/token + POST true false @@ -7489,7 +7760,11 @@ vars.put("utcTime", utcTime); + + + + continue false @@ -7503,16 +7778,39 @@ vars.put("utcTime", utcTime); true + + + , + + ./client_id_esignet.csv + true + false + true + shareMode.all + false + oAuthDetailsEndpointClientId,encodedPrivateKey + + + + , + + ./individualid_esignet1.txt + , ./individualid_esignet.txt + true false true shareMode.all false + + credentialIndividualId + sendBindingOtpIndividualId + @@ -7529,7 +7827,11 @@ String utcTime = dateFormat.format(cal.getTime()); vars.put("utcTime", utcTime); + + + + true @@ -7538,8 +7840,23 @@ vars.put("utcTime", utcTime); { "requestTime": "${utcTime}Z", "request": { + + "clientId": "${oAuthDetailsEndpointClientId}", + "scope": "${scopeVci}", + "responseType": "code", + "redirectUri": "${redirectUri}", + "display": "popup", + "prompt": "login", + "acrValues": "${acrValues}", + "nonce" : "973eieljzng", + "state" : "eree2311", + "claimsLocales" : "en", + "codeChallenge" : "${codeChallenge}", + "codeChallengeMethod" : "S256" + "individualId" : "${sendBindingOtpIndividualId}", "otpChannels" : ["email"] + } } = @@ -7550,7 +7867,11 @@ vars.put("utcTime", utcTime); ${serverPortNo} ${protocol} + + /v1/esignet/authorization/v2/oauth-details + /v1/esignet/binding/binding-otp + POST true false @@ -7568,6 +7889,14 @@ vars.put("utcTime", utcTime); application/json + + X-XSRF-TOKEN + ${loadCsrfToken} + + + Cookie + XSRF-TOKEN=${loadCsrfToken} + PARTNER-ID ${walletPartnerId} @@ -7578,6 +7907,7 @@ vars.put("utcTime", utcTime); Authorization Bearer ${authTokenMobile} + @@ -7602,6 +7932,44 @@ vars.put("utcTime", utcTime); 2 + + + false + tidVci + "transactionId":"(.*?)" + $1$ + transactionID not found + 1 + + + + groovy + + + true + import org.apache.commons.codec.binary.Base64; +import java.security.SecureRandom; +import java.security.MessageDigest; + +SecureRandom secureRandom = new SecureRandom(); +byte[] codeVerifierBytes = new byte[32]; // 256 bits +secureRandom.nextBytes(codeVerifierBytes); + +String codeVerifier = Base64.encodeBase64URLSafeString(codeVerifierBytes); +vars.put("codeVerifier", codeVerifier); +log.info("codeVerifier: " + codeVerifier); + +MessageDigest digest = MessageDigest.getInstance("SHA-256"); +byte[] hash = digest.digest(codeVerifier.getBytes("UTF-8")); +String codeChallenge = Base64.encodeBase64URLSafeString(hash); +vars.put("codeChallenge", codeChallenge); +log.info("codeChallenge: " + codeChallenge); + + + + + + @@ -7645,18 +8013,30 @@ vars.put("utcTime", utcTime); + true false { + + "requestTime": "${utcTime}Z", + "request": { + "transactionId": "${tidVci}", + "individualId": "${credentialIndividualId}", + "otpChannels": ["EMAIL"], + "captchaToken" : "" + } +} + "requestTime": "${utcTime}Z", "request": { "individualId" : "${sendBindingOtpIndividualId}", "otpChannels" : ["email"] } } + = @@ -7665,7 +8045,11 @@ vars.put("utcTime", utcTime); ${serverPortNo} ${protocol} + + /v1/esignet/authorization/send-otp + /v1/esignet/binding/binding-otp + POST true false @@ -7683,6 +8067,22 @@ vars.put("utcTime", utcTime); application/json + + X-XSRF-TOKEN + ${loadCsrfToken} + + + Cookie + XSRF-TOKEN=${loadCsrfToken} + + + oauth-details-hash + ${hashValue} + + + oauth-details-key + ${tidVci} + PARTNER-ID ${walletPartnerId} @@ -7693,6 +8093,7 @@ vars.put("utcTime", utcTime); Authorization Bearer ${authTokenMobile} + @@ -7717,43 +8118,143 @@ vars.put("utcTime", utcTime); 2 - - - - false - ${__StringToFile(wallet_binding_individual_id.txt,${sendBindingOtpIndividualId}\n,true,)} - + + + false + tidSendOtpVci + "transactionId":"(.*?)" + $1$ + transactionID not found + 1 + - - - - continue - - false - 1 - - 1 - 1 - false - - - true - - - - , - - ./wallet_binding_individual_id.txt - true - false - true - shareMode.all - false - walletBindingIndividualId - - - - + + javascript + + + true + // Import the required Java classes +var Base64 = Java.type('java.util.Base64'); +var StandardCharsets = Java.type('java.nio.charset.StandardCharsets'); + +// Retrieve the previous response value +var jsonResponse = prev.getResponseDataAsString(); + +// Print the previous response value +log.info("Previous Response: " + jsonResponse); + +// Parse the JSON response +var jsonObject = JSON.parse(jsonResponse); +var responseObjectString = JSON.stringify(jsonObject.response); + +log.info("Previous Response: " + responseObjectString); + +// Convert JSON to base64 URL-encoded SHA-256 hash +var sha256Hash = hashSHA256(responseObjectString); +var base64UrlEncodedHash = encodeBase64Url(sha256Hash); + +//Print the sha256 value +log.info("sha256Hash Value: " + sha256Hash); + +// Print the final hash value +log.info("Final Hash Value: " + base64UrlEncodedHash); + +// Set the new variable value in JMeter +vars.put("hashValue", base64UrlEncodedHash); + +// Function to compute the SHA-256 hash +function hashSHA256(value) { + var messageDigest = Java.type('java.security.MessageDigest').getInstance('SHA-256'); + var bytes = (value).getBytes(StandardCharsets.UTF_8); + var digest = messageDigest.digest(bytes); + return digest; +} + +// Function to base64 URL-encode the hash value +function encodeBase64Url(value) { + var base64 = Base64.getUrlEncoder().withoutPadding().encodeToString(value); + return base64; +} + + + + + true + + + + false + { + "requestTime": "${utcTime}Z", + "request": { + "transactionId": "${tidSendOtpVci}", + "individualId": "${credentialIndividualId}", + "challengeList": [ + { + "authFactorType": "OTP", + "challenge": "111111", + "format": "alpha-numeric" + } + ] + } +} + = + + + + ${serverIP} + ${serverPortNo} + ${protocol} + + /v1/esignet/authorization/v2/authenticate + POST + true + false + true + false + + + + + + + + + + false + ${__StringToFile(wallet_binding_individual_id.txt,${sendBindingOtpIndividualId}\n,true,)} + + + + + + continue + + false + 1 + + 1 + 1 + false + + + true + + + + , + + ./wallet_binding_individual_id.txt + true + false + true + shareMode.all + false + walletBindingIndividualId + + + + false import java.text.SimpleDateFormat; @@ -7849,6 +8350,7 @@ log.info("Public Key: ${vars.get("bindingPublicKey")}") + @@ -7863,17 +8365,104 @@ log.info("Public Key: ${vars.get("bindingPublicKey")}") Cookie XSRF-TOKEN=${loadCsrfToken} + + + oauth-details-hash + ${hashValue} + + + oauth-details-key + ${tidSendOtpVci} + + + + + + + "errors":[] + + + Assertion.response_data + false + 16 + + + + + 200 + + + Assertion.response_code + false + 2 + + + + false + tidAuthCodeVci + "transactionId":"(.*?)" + $1$ + transactionID not found + 1 + + + + + true + + + + false + { + "requestTime": "${utcTime}Z", + "request": { + "transactionId": "${tidAuthCodeVci}", + "permittedAuthorizeScopes": [], + "acceptedClaims": [ + ${acceptedClaims} + ] + } +} + = + + + + ${serverIP} + ${serverPortNo} + ${protocol} + + /v1/esignet/authorization/auth-code + POST + true + false + true + false + + + + + + + - PARTNER-ID - ${walletPartnerId} + Content-Type + application/json - PARTNER-API-KEY - ${walletPartnerApiKey} + X-XSRF-TOKEN + ${loadCsrfToken} - Authorization - Bearer ${authTokenMobile} + Cookie + XSRF-TOKEN=${loadCsrfToken} + + + oauth-details-hash + ${hashValue} + + + oauth-details-key + ${tidAuthCodeVci} @@ -7898,6 +8487,386 @@ log.info("Public Key: ${vars.get("bindingPublicKey")}") 2 + + false + codeVci + "code":"(.*?)" + $1$ + Code not found + 1 + + + + + true + + + +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemReader; +import io.jsonwebtoken.*; +import java.util.Date; +import io.jsonwebtoken.security.Keys; +import java.security.KeyPair; + +java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + +String clientId = vars.get("oAuthDetailsEndpointClientId") ; +log.info("clientId: " + clientId); + +String pemPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n"+ vars.get("encodedPrivateKey") +"\n-----END RSA PRIVATE KEY-----" ; + +String audience = "${protocol}"+ ":" + "//" + "${serverIpEsignet}" +"/v1/esignet/oauth/token" ; + +PemReader pemReader = new PemReader(new StringReader (pemPrivateKey)); +PemObject pemObject = pemReader.readPemObject(); +KeyFactory kf = KeyFactory.getInstance("RSA"); +byte[] content = pemObject.getContent (); +PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(content); +PrivateKey pk = kf.generatePrivate (keySpec); +//The RS256 signature algorithm will be used to sign the token in this example +SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256; +//Set the Issued date and expiry date to now +long nowMillis = System.currentTimeMillis(); +Date now = new Date(nowMillis); +long expMillis = nowMillis + ${jwtExpireInterval}; +Date exp = new Date(expMillis); + +//Build the JWT with the JwtBuilder +JwtBuilder builder = Jwts.builder() + .signWith(signatureAlgorithm,pk) + .setIssuedAt(now) + .setExpiration(exp) + .setIssuer(clientId) + .setSubject(clientId) + .setAudience(audience); + +//Save the JWT in the compact string in the jmeter variables +log.info(builder.compact().toString()); +String JWT = builder.compact().toString(); +vars.put("clientAssertionJWT", JWT); +log.info("clientAssertionJWT: ${vars.get("clientAssertionJWT")}") + groovy + + + + + + + false + authorization_code + = + true + grant_type + + + false + ${codeVci} + = + true + code + + + false + ${oAuthDetailsEndpointClientId} + = + true + client_id + + + false + urn:ietf:params:oauth:client-assertion-type:jwt-bearer + = + true + client_assertion_type + + + false + ${clientAssertionJWT} + = + true + client_assertion + + + false + ${redirectUri} + = + true + redirect_uri + + + false + ${codeVerifier} + = + true + code_verifier + + + + ${serverIP} + ${serverPortNo} + ${protocol} + + /v1/esignet/oauth/v2/token + POST + true + false + true + false + + + + + + + + + Content-Type + application/x-www-form-urlencoded + + + + + + + "token_type":"Bearer","access_token": + + + Assertion.response_data + false + 16 + + + + + 200 + + + Assertion.response_code + false + 2 + + + + false + accessToken + "access_token":"(.*?)" + $1$ + access_token not found + 1 + + + + false + cNonce + "c_nonce":"(.*?)" + $1$ + cNonce not found + 1 + + + + groovy + + + true + // Import necessary libraries +import java.security.KeyFactory; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import com.nimbusds.jose.util.JSONObjectUtils; +import net.minidev.json.JSONObject; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; +import java.security.PrivateKey; +import java.security.spec.InvalidKeySpecException; +import io.jsonwebtoken.*; +import java.util.Date; +import java.security.KeyPair; + +def keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256) +def privateKey = keyPair.private +def publicKey = keyPair.public + +vars.put("holderPrivateKey", privateKey.getEncoded().encodeBase64().toString()) + +// Create JSON representation of RSA public key +def rsaPublicKeyJson = [ + "kty": "RSA", + "n" : Base64.getUrlEncoder().withoutPadding().encodeToString(publicKey.getModulus().toByteArray()), + "e" : Base64.getUrlEncoder().withoutPadding().encodeToString(publicKey.getPublicExponent().toByteArray()), + "alg": "RS256", + "use": "sig" +] + +vars.put("holderPublicKey", JSONObjectUtils.toJSONString(rsaPublicKeyJson)) +// Set headers for JWT +def header = [ + "alg": "RS256", + "typ": "openid4vci-proof+jwt", + "jwk": rsaPublicKeyJson +] + + +String audience = "${protocol}"+ ":" + "//" + "${serverIpEsignet}" +"/v1/esignet" ; +log.info("audience: " + audience); +String clientId = vars.get("oAuthDetailsEndpointClientId") ; +log.info("clientId: " + clientId); +long nowMillis = System.currentTimeMillis(); +Date now = new Date(nowMillis); + +// Set JWT payload +def payload = [ + "nonce": vars.get("cNonce") +] + +//Build the JWT with the JwtBuilder +JwtBuilder builder = Jwts.builder() + .setHeader(header) + .setClaims(payload) + .setIssuedAt(now) + .setIssuer(clientId) + .setAudience(audience) + .setExpiration(new Date(System.currentTimeMillis() + 600000)) + .signWith(SignatureAlgorithm.RS256,privateKey); + +String JWT = builder.compact().toString(); +vars.put("proofJwt", JWT) +log.info("proofJwt: ${vars.get("proofJwt")}") + + + + + + + false + ${__StringToFile(accesstoken_proofjwt_credential_endpoint_vci.txt,${accessToken}\,${proofJwt}\n,true,)} + + + + + + continue + + false + 1 + + 1 + 1 + false + + + true + + + + , + + ./accesstoken_proofjwt_credential_endpoint_vci.txt + true + false + true + shareMode.all + false + accessToken,proofJwt + + + + true + + + + false + { + "format": "ldp_vc", + "credential_definition" : { "type" : ["VerifiableCredential", "MOSIPVerifiableCredential"], "@context" : ["https://www.w3.org/2018/credentials/v1"]}, + "proof": { + "proof_type": "jwt", + "jwt": "${proofJwt}" + } +} + = + + + + ${serverIP} + ${serverPortNo} + ${protocol} + + /v1/esignet/vci/credential + POST + true + false + true + false + + + + + + + + + Content-Type + application/json + + + X-XSRF-TOKEN + ${loadCsrfToken} + + + Cookie + XSRF-TOKEN=${loadCsrfToken} + + + Authorization + Bearer ${accessToken} + + + PARTNER-ID + ${walletPartnerId} + + + PARTNER-API-KEY + ${walletPartnerApiKey} + + + Authorization + Bearer ${authTokenMobile} + + + + + + + + + {"format":"ldp_vc","credential": + + "errors":[] + + + + Assertion.response_data + false + 16 + + + + + 200 + + + Assertion.response_code + false + 2 + +