@@ -80,6 +80,7 @@ public class EsignetUtil extends AdminTestUtil {
8080
8181 private static final Logger logger = Logger .getLogger (EsignetUtil .class );
8282 public static String pluginName = null ;
83+ public static String esignetServerProfile = null ;
8384 private static Faker faker = new Faker ();
8485 private static String fullNameForSunBirdR = generateFullNameForSunBirdR ();
8586 private static String dobForSunBirdR = generateDobForSunBirdR ();
@@ -135,6 +136,51 @@ public static String getIdentityPluginNameFromEsignetActuator() {
135136
136137 return pluginName ;
137138 }
139+
140+ public static String getEsignetServerProfileFromActuator () {
141+ if (esignetServerProfile != null && !esignetServerProfile .isBlank ()) {
142+ return esignetServerProfile ;
143+ }
144+ esignetServerProfile = getValueFromEsignetActuator (EsignetConstants .CLASS_PATH_APPLICATION_PROPERTIES ,
145+ EsignetConstants .MOSIP_ESIGNET_SERVER_PROFILE );
146+ if (esignetServerProfile == null ) {
147+ esignetServerProfile = "" ;
148+ logger .warn ("Esignet server profile not found from actuator; defaulting to empty" );
149+ } else {
150+ logger .info ("Esignet server profile from actuator = " + esignetServerProfile );
151+ }
152+ return esignetServerProfile ;
153+ }
154+
155+ private static boolean isFapi2ServerProfile () {
156+ return EsignetConstants .FAPI2_0_SERVER_PROFILE .equalsIgnoreCase (getEsignetServerProfileFromActuator ());
157+ }
158+
159+ private static boolean isFapiTestCase (TestCaseDTO testCaseDTO ) {
160+ if (testCaseDTO == null ) {
161+ return false ;
162+ }
163+ String inputTemplate = testCaseDTO .getInputTemplate ();
164+ if (inputTemplate != null && inputTemplate .contains (EsignetConstants .FAPI_TEST_CASE_PATH )) {
165+ return true ;
166+ }
167+ String outputTemplate = testCaseDTO .getOutputTemplate ();
168+ if (outputTemplate != null && outputTemplate .contains (EsignetConstants .FAPI_TEST_CASE_PATH )) {
169+ return true ;
170+ }
171+ String uniqueIdentifier = testCaseDTO .getUniqueIdentifier ();
172+ if (uniqueIdentifier != null && uniqueIdentifier .contains ("_FAPI_" )) {
173+ return true ;
174+ }
175+ String testCaseName = testCaseDTO .getTestCaseName ();
176+ if (testCaseName != null
177+ && testCaseName .contains (EsignetConstants .FAPI_PREREQUISITE_TEST_CASE_MARKER )) {
178+ return true ;
179+ }
180+ String description = testCaseDTO .getDescription ();
181+ return description != null && description .toLowerCase ().contains ("for fapi" );
182+ }
183+
138184 public static String getPluginName () {
139185 try {
140186 String pluginServiceName = EsignetUtil .getIdentityPluginNameFromEsignetActuator ().toLowerCase ();
@@ -196,7 +242,21 @@ public static String isTestCaseValidForExecution(TestCaseDTO testCaseDTO) {
196242 if (MosipTestRunner .skipAll == true ) {
197243 throw new SkipException (GlobalConstants .PRE_REQUISITE_FAILED_MESSAGE );
198244 }
199-
245+
246+ if (isFapi2ServerProfile () && !isFapiTestCase (testCaseDTO )) {
247+ String pluginServiceName = getIdentityPluginNameFromEsignetActuator ().toLowerCase ();
248+ String endpoint = testCaseDTO .getEndPoint ();
249+ if (pluginServiceName .contains ("mockauthenticationservice" )) {
250+ // mock + fapi2.0: skip all non-FAPI tests
251+ throw new SkipException (GlobalConstants .FEATURE_NOT_SUPPORTED_MESSAGE );
252+ }
253+ if (pluginServiceName .contains ("idaauthenticatorimpl" )
254+ && endpoint != null
255+ && (endpoint .contains ("/esignet/" ) || endpoint .contains ("$GETENDPOINTFROMWELLKNOWN$" ))) {
256+ // mosipid + fapi2.0: skip non-FAPI esignet tests; allow setup endpoints (PMS/partner/identity)
257+ throw new SkipException (GlobalConstants .FEATURE_NOT_SUPPORTED_MESSAGE );
258+ }
259+ }
200260
201261 if (getIdentityPluginNameFromEsignetActuator ().toLowerCase ().contains ("mockauthenticationservice" )) {
202262 // TO DO - need to conform whether esignet distinguishes between UIN and VID. BAsed on that need to remove VID test case from YAML.
@@ -220,15 +280,16 @@ public static String isTestCaseValidForExecution(TestCaseDTO testCaseDTO) {
220280 || testCaseName .contains ("ESignet_CreateOIDCClient_StatusCode_Diff_Token_Neg" ))) {
221281 throw new SkipException (GlobalConstants .FEATURE_NOT_SUPPORTED_MESSAGE );
222282 }
223- if ((testCaseName .contains ("_UpdateOIDCClientV3_MOSIPID_" )
224- || testCaseName .contains ("_OAuthDetailsRequest_V3_MOSIPID_" )
225- || testCaseName .contains ("_AuthenticateUser_V3_MOSIPID_" )
226- || testCaseName .contains ("_AuthorizationCode_MOSIPID_" )
227- || testCaseName .contains ("_GenerateToken_MOSIPID_" )
228- || testCaseName .contains ("_GetOidcUserInfo_MOSIPID_" )
229- || testCaseName .contains ("FAPIPatchClientConfig_MOSIPID_" ))) {
230- throw new SkipException (GlobalConstants .FEATURE_NOT_SUPPORTED_MESSAGE );
231- }
283+ if ((testCaseName .contains ("_UpdateOIDCClientV3_MOSIPID_" )
284+ || testCaseName .contains ("_OAuthDetailsRequest_V3_MOSIPID_" )
285+ || testCaseName .contains ("_AuthenticateUser_V3_MOSIPID_" )
286+ || testCaseName .contains ("_AuthorizationCode_MOSIPID_" )
287+ || testCaseName .contains ("_GenerateToken_MOSIPID_" )
288+ || testCaseName .contains ("_GetOidcUserInfo_MOSIPID_" )
289+ || testCaseName .contains ("FAPIPatchClientConfig_MOSIPID_" )
290+ || testCaseName .contains ("PKCEPatchClientConfig_MOSIPID_" ))) {
291+ throw new SkipException (GlobalConstants .FEATURE_NOT_SUPPORTED_MESSAGE );
292+ }
232293
233294 } else if (getIdentityPluginNameFromEsignetActuator ().toLowerCase ().contains ("idaauthenticatorimpl" )) {
234295 // Let run test cases eSignet & MOSIP API calls --- both UIN and VID
@@ -255,24 +316,25 @@ public static String isTestCaseValidForExecution(TestCaseDTO testCaseDTO) {
255316 || testCaseName .equals ("ESignet_PartialUpdateOIDCClient_MOCK_Missing_kid_value_Neg" )
256317 || testCaseName .equals ("ESignet_PartialUpdateOIDCClient_MOCK_Duplicate_EncKey_forUserInfoUpdateJWE_Neg" )
257318 || testCaseName .equals ("ESignet_PartialUpdateOIDCClient_MOCK_Different_Encryption_alg_value_Pos" )
258- || testCaseName .equals ("ESignet_CreateOIDCClientFAPI_all_Valid_Smoke_sid" )
259- || testCaseName .equals ("ESignet_CreateOIDCClientFAPI_all_Valid_forUserInfoJWE_Smoke_sid" )
260- || testCaseName .equals ("ESignet_FAPIPartialUpdateOIDCClient_all_Valid_forUserInfoJWE_Smoke_sid" ))
319+ || testCaseName .equals ("ESignet_CreateOIDCClientFAPI_all_Valid_Smoke_sid" )
320+ || testCaseName .equals ("ESignet_CreateOIDCClientFAPI_all_Valid_forUserInfoJWE_Smoke_sid" )
321+ || testCaseName .equals ("ESignet_FAPIPartialUpdateOIDCClient_all_Valid_forUserInfoJWE_Smoke_sid" )
322+ || testCaseName .equals ("ESignet_CreateOIDCClient_PKCE_JWE_Valid_Smoke_sid" ))
261323 && (endpoint .contains ("/v1/esignet/client-mgmt/client" )
262324 || endpoint .contains ("/v1/esignet/client-mgmt/client/{clientId}" )
263325 || endpoint .contains ("/v1/esignet/client-mgmt/oauth-client" )))) {
264326 throw new SkipException (GlobalConstants .FEATURE_NOT_SUPPORTED_MESSAGE );
265327 }
266328
267- if ((testCaseName .contains ("_CreateOIDCClientV3_MOCK_" )
268- || testCaseName .contains ("_UpdateOIDCClientV3_MOCK_" )
269- || testCaseName .contains ("_OAuthDetailsRequest_V3_MOCK_" )
270- || testCaseName .contains ("_AuthenticateUser_V3_MOCK_" )
271- || testCaseName .contains ("_AuthorizationCode_MOCK_" )
272- || testCaseName .contains ("_GenerateToken_MOCK_" )
273- || testCaseName .contains ("_GetOidcUserInfo_MOCK_" ))) {
274- throw new SkipException (GlobalConstants .FEATURE_NOT_SUPPORTED_MESSAGE );
275- }
329+ if ((testCaseName .contains ("_CreateOIDCClientV3_MOCK_" )
330+ || testCaseName .contains ("_UpdateOIDCClientV3_MOCK_" )
331+ || testCaseName .contains ("_OAuthDetailsRequest_V3_MOCK_" )
332+ || testCaseName .contains ("_AuthenticateUser_V3_MOCK_" )
333+ || testCaseName .contains ("_AuthorizationCode_MOCK_" )
334+ || testCaseName .contains ("_GenerateToken_MOCK_" )
335+ || testCaseName .contains ("_GetOidcUserInfo_MOCK_" ))) {
336+ throw new SkipException (GlobalConstants .FEATURE_NOT_SUPPORTED_MESSAGE );
337+ }
276338
277339 JSONArray individualBiometricsArray = new JSONArray (
278340 getValueFromAuthActuator ("json-property" , "individualBiometrics" ));
@@ -494,35 +556,11 @@ public static String inputstringKeyWordHandeler(String jsonString, String testCa
494556 }
495557 }
496558
497- if (jsonString .contains ("$CODE_CHALLENGE$" )
498- || jsonString .contains ("$CODE_VERIFIER$" )
499- || jsonString .contains ("$CODE_CHALLENGE_METHOD$" )) {
500-
501- Map <String , String > pkce ;
502-
503- String key = "GLOBAL_PKCE" ;
559+ jsonString = resolvePkceTokens (jsonString , "GLOBAL_PKCE" ,
560+ "$CODE_CHALLENGE$" , "$CODE_VERIFIER$" , "$CODE_CHALLENGE_METHOD$" );
504561
505- if (pkceCache .containsKey (key )) {
506- pkce = pkceCache .get (key );
507- logger .info ("Reusing PKCE" );
508- } else {
509- pkce = generatePKCE ();
510- pkceCache .put (key , pkce );
511- logger .info ("Generated new PKCE" );
512- }
513-
514- if (jsonString .contains ("$CODE_CHALLENGE$" )) {
515- jsonString = replaceKeywordValue (jsonString , "$CODE_CHALLENGE$" , pkce .get ("code_challenge" ));
516- }
517-
518- if (jsonString .contains ("$CODE_VERIFIER$" )) {
519- jsonString = replaceKeywordValue (jsonString , "$CODE_VERIFIER$" , pkce .get ("code_verifier" ));
520- }
521-
522- if (jsonString .contains ("$CODE_CHALLENGE_METHOD$" )) {
523- jsonString = replaceKeywordValue (jsonString , "$CODE_CHALLENGE_METHOD$" , pkce .get ("method" ));
524- }
525- }
562+ jsonString = resolvePkceTokens (jsonString , "PKCE_JWE_FLOW" ,
563+ "$CODE_CHALLENGE_PKCE_JWE$" , "$CODE_VERIFIER_PKCE_JWE$" , "$CODE_CHALLENGE_METHOD_PKCE_JWE$" );
526564
527565 if (jsonString .contains ("$BINDINGJWKKEY$" )) {
528566 String jwkKey = "" ;
@@ -825,6 +863,17 @@ public static String inputstringKeyWordHandeler(String jsonString, String testCa
825863 jsonString = replaceKeywordValue (jsonString , "$OIDC_JWK_KEY_FAPI_JWE$" , jwkKey );
826864 }
827865
866+ if (jsonString .contains ("$OIDC_JWK_KEY_PKCE_JWE$" )) {
867+ String jwkKey = "" ;
868+ if (getTriggerESignetKeyGenForPKCEJWE ()) {
869+ jwkKey = JWKKeyUtil .generateAndCacheJWKKey (OIDC_JWK_FOR_PKCE_JWE );
870+ setTriggerESignetKeyGenForPKCEJWE (false );
871+ } else {
872+ jwkKey = JWKKeyUtil .getJWKKey (OIDC_JWK_FOR_PKCE_JWE );
873+ }
874+ jsonString = replaceKeywordValue (jsonString , "$OIDC_JWK_KEY_PKCE_JWE$" , jwkKey );
875+ }
876+
828877 if (jsonString .contains ("$OIDC_JWK_KEY_FAPI$" )) {
829878 String jwkKey = "" ;
830879 if (getTriggerESignetKeyGenForFAPI ()) {
@@ -1088,6 +1137,36 @@ public static String inputstringKeyWordHandeler(String jsonString, String testCa
10881137 }
10891138 }
10901139
1140+ if (jsonString .contains ("$CLIENT_ASSERTION_PKCE_JWE_JWT$" )) {
1141+ String oidcJWKKeyString = JWKKeyUtil .getJWKKey (OIDC_JWK_FOR_PKCE_JWE );
1142+ logger .info ("oidcJWKKeyString =" + oidcJWKKeyString );
1143+ try {
1144+ oidc_JWK_Key_For_PKCE_JWE = RSAKey .parse (oidcJWKKeyString );
1145+ logger .info ("oidc_JWK_Key_For_PKCE_JWE =" + oidc_JWK_Key_For_PKCE_JWE );
1146+ } catch (java .text .ParseException e ) {
1147+ logger .error (e .getMessage ());
1148+ }
1149+
1150+ JSONObject root = new JSONObject (jsonString );
1151+ String clientId = root .optString ("client_id" , null );
1152+ String audKey = null ;
1153+
1154+ if (root .has ("aud_key" )) {
1155+ audKey = root .optString ("aud_key" , null );
1156+ root .remove ("aud_key" );
1157+ jsonString = root .toString ();
1158+ }
1159+
1160+ String tempUrl = getValueFromEsignetWellKnownEndPoint (audKey , EsignetConfigManager .getEsignetBaseUrl ());
1161+
1162+ if (clientId != null ) {
1163+ jsonString = replaceKeywordValue (jsonString , "$CLIENT_ASSERTION_PKCE_JWE_JWT$" ,
1164+ signJWKKey (clientId , oidc_JWK_Key_For_PKCE_JWE , tempUrl ));
1165+ } else {
1166+ logger .error ("Client ID not found in JSON for $CLIENT_ASSERTION_PKCE_JWE_JWT$." );
1167+ }
1168+ }
1169+
10911170 if (jsonString .contains ("$CLIENT_ASSERTION_FAPI_JWT$" )) {
10921171 String fapiJwkKeyName = getFapiJwkKeyName (testCaseName );
10931172 String oidcJWKKeyString = JWKKeyUtil .getJWKKey (fapiJwkKeyName );
@@ -2019,6 +2098,7 @@ public static String getValueFromEsignetWellKnownEndPoint(String key, String bas
20192098 protected static final String OIDC_JWK_FOR_DPoP = "oidcJWKForDPoP" ;
20202099 protected static final String OIDC_JWK_FOR_FAPI = "oidcJWKForFAPI" ;
20212100 protected static final String OIDC_JWK_FOR_FAPI_JWE = "oidcJWKForFAPIJWE" ;
2101+ protected static final String OIDC_JWK_FOR_PKCE_JWE = "oidcJWKForPKCEJWE" ;
20222102
20232103 protected static RSAKey oidcJWKKey1 = null ;
20242104 protected static RSAKey oidcJWKKey3 = null ;
@@ -2037,6 +2117,7 @@ public static String getValueFromEsignetWellKnownEndPoint(String key, String bas
20372117 protected static RSAKey oidc_JWK_Key_For_DPoP = null ;
20382118 protected static RSAKey oidc_JWK_Key_For_FAPI = null ;
20392119 protected static RSAKey oidc_JWK_Key_For_FAPI_JWE = null ;
2120+ protected static RSAKey oidc_JWK_Key_For_PKCE_JWE = null ;
20402121
20412122 protected static boolean triggerESignetKeyGen1 = true ;
20422123 protected static boolean triggerESignetKeyGen2 = true ;
@@ -2079,6 +2160,7 @@ public static String getValueFromEsignetWellKnownEndPoint(String key, String bas
20792160 protected static boolean triggerESignetKeyGenForDPoP = true ;
20802161 protected static boolean triggerESignetKeyGenForFAPI = true ;
20812162 protected static boolean triggerESignetKeyGenForFAPIJWE = true ;
2163+ protected static boolean triggerESignetKeyGenForPKCEJWE = true ;
20822164
20832165 private static String getFapiJwkKeyName (String testCaseName ) {
20842166 if (testCaseName != null
@@ -2199,6 +2281,14 @@ private static boolean getTriggerESignetKeyGenForFAPIJWE() {
21992281 private static void setTriggerESignetKeyGenForFAPIJWE (boolean value ) {
22002282 triggerESignetKeyGenForFAPIJWE = value ;
22012283 }
2284+
2285+ private static boolean getTriggerESignetKeyGenForPKCEJWE () {
2286+ return triggerESignetKeyGenForPKCEJWE ;
2287+ }
2288+
2289+ private static void setTriggerESignetKeyGenForPKCEJWE (boolean value ) {
2290+ triggerESignetKeyGenForPKCEJWE = value ;
2291+ }
22022292
22032293 private static void settriggerESignetKeyGen2 (boolean value ) {
22042294 triggerESignetKeyGen2 = value ;
@@ -2807,6 +2897,40 @@ public static List<String> extractTokensFromResponse(String responseBody) throws
28072897 return tokens ;
28082898 }
28092899
2900+ private static String resolvePkceTokens (String jsonString ,
2901+ String cacheKey ,
2902+ String challengeToken ,
2903+ String verifierToken ,
2904+ String methodToken ) {
2905+
2906+ if (!jsonString .contains (challengeToken )
2907+ && !jsonString .contains (verifierToken )
2908+ && !jsonString .contains (methodToken )) {
2909+ return jsonString ;
2910+ }
2911+
2912+ Map <String , String > pkce ;
2913+ if (pkceCache .containsKey (cacheKey )) {
2914+ pkce = pkceCache .get (cacheKey );
2915+ logger .info ("Reusing PKCE for " + cacheKey );
2916+ } else {
2917+ pkce = generatePKCE ();
2918+ pkceCache .put (cacheKey , pkce );
2919+ logger .info ("Generated new PKCE for " + cacheKey );
2920+ }
2921+
2922+ if (jsonString .contains (challengeToken )) {
2923+ jsonString = replaceKeywordValue (jsonString , challengeToken , pkce .get ("code_challenge" ));
2924+ }
2925+ if (jsonString .contains (verifierToken )) {
2926+ jsonString = replaceKeywordValue (jsonString , verifierToken , pkce .get ("code_verifier" ));
2927+ }
2928+ if (jsonString .contains (methodToken )) {
2929+ jsonString = replaceKeywordValue (jsonString , methodToken , pkce .get ("method" ));
2930+ }
2931+ return jsonString ;
2932+ }
2933+
28102934 public static Map <String , String > generatePKCE () {
28112935 try {
28122936 byte [] randomBytes = new byte [32 ];
0 commit comments