From e4d664f8b7be292af3ec58282c327425db5a3c11 Mon Sep 17 00:00:00 2001 From: shanggeeth Date: Mon, 12 Aug 2024 15:01:18 +0530 Subject: [PATCH] Add unit tests for Call Choreo and Call Analytics functions for comprehensive payload --- .../analytics/CallAnalyticsFunctionImpl.java | 37 +---- .../CallAnalyticsFunctionImplTest.java | 95 +++++++++++++ .../analytics/analytics-payload-test-sp.xml | 124 +++++++++++++++++ .../analytics/analytics-payload.json | 39 ++++++ .../choreo/CallChoreoFunctionImpl.java | 35 +---- .../choreo/CallChoreoFunctionImplTest.java | 75 +++++++++- .../auth/functions/choreo/choreo-payload.json | 39 ++++++ .../auth/functions/choreo/payload-test-sp.xml | 128 ++++++++++++++++++ .../functions/common/utils/CommonUtils.java | 39 ++++++ .../sequence/JsSequenceHandlerRunner.java | 31 +++++ 10 files changed, 570 insertions(+), 72 deletions(-) create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/analytics/analytics-payload-test-sp.xml create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/analytics/analytics-payload.json create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/choreo/choreo-payload.json create mode 100644 components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/choreo/payload-test-sp.xml diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/analytics/CallAnalyticsFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/analytics/CallAnalyticsFunctionImpl.java index 10ef114c..c8c03875 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/analytics/CallAnalyticsFunctionImpl.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/analytics/CallAnalyticsFunctionImpl.java @@ -41,15 +41,14 @@ import java.io.IOException; import java.net.SocketTimeoutException; import java.net.URL; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import static org.apache.http.HttpHeaders.ACCEPT; import static org.apache.http.HttpHeaders.CONTENT_TYPE; +import static org.wso2.carbon.identity.conditional.auth.functions.common.utils.CommonUtils.getPayloadDataMap; import static org.wso2.carbon.identity.conditional.auth.functions.common.utils.Constants.OUTCOME_FAIL; import static org.wso2.carbon.identity.conditional.auth.functions.common.utils.Constants.OUTCOME_SUCCESS; import static org.wso2.carbon.identity.conditional.auth.functions.common.utils.Constants.OUTCOME_TIMEOUT; @@ -215,38 +214,4 @@ public void cancelled() { }); JsGraphBuilder.addLongWaitProcess(asyncProcess, eventHandlers); } - - private Map getPayloadDataMap(Map payloadData) { - - if (payloadData == null) { - return new HashMap<>(); - } - Map payloadDataMap = new HashMap<>(); - for (Map.Entry entry : payloadData.entrySet()) { - Object value = entry.getValue(); - if (value instanceof Map) { - payloadDataMap.put(entry.getKey(), getPayloadDataMap((Map) value)); - } else if (value instanceof List) { - payloadDataMap.put(entry.getKey(), processList((List) value)); - } else { - payloadDataMap.put(entry.getKey(), value); - } - } - return payloadDataMap; - } - - private List processList(List list) { - - List resultList = new ArrayList<>(); - for (Object item : list) { - if (item instanceof Map) { - resultList.add(getPayloadDataMap((Map) item)); - } if (item instanceof List) { - resultList.add(processList((List) item)); - } else { - resultList.add(item); - } - } - return resultList; - } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/analytics/CallAnalyticsFunctionImplTest.java b/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/analytics/CallAnalyticsFunctionImplTest.java index f5b1856c..e313b075 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/analytics/CallAnalyticsFunctionImplTest.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/analytics/CallAnalyticsFunctionImplTest.java @@ -18,6 +18,8 @@ package org.wso2.carbon.identity.conditional.auth.functions.analytics; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import org.mockito.Mockito; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -28,8 +30,10 @@ import org.wso2.carbon.identity.application.authentication.framework.dao.impl.LongWaitStatusDAOImpl; import org.wso2.carbon.identity.application.authentication.framework.internal.FrameworkServiceDataHolder; import org.wso2.carbon.identity.application.authentication.framework.store.LongWaitStatusStoreService; +import org.wso2.carbon.identity.application.common.model.LocalAndOutboundAuthenticationConfig; import org.wso2.carbon.identity.application.common.model.Property; import org.wso2.carbon.identity.application.common.model.ServiceProvider; +import org.wso2.carbon.identity.application.common.model.script.AuthenticationScriptConfig; import org.wso2.carbon.identity.common.testng.InjectMicroservicePort; import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.common.testng.WithH2Database; @@ -54,6 +58,7 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -65,6 +70,11 @@ @Path("/") public class CallAnalyticsFunctionImplTest extends JsSequenceHandlerAbstractTest { +public static final String ANALYTICS_SERVICE_CHECK_PAYLOAD = "/analytics-service-check-payload"; + public static final String ANALYTICS_PAYLOAD_JSON = "analytics-payload.json"; + public static final String ANALYTICS_PAYLOAD_TEST_SP = "analytics-payload-test-sp.xml"; + public static final String ANALYTICS_PAYLOAD = "analytics-payload.json"; + @WithRealmService private RealmService realmService; @@ -126,6 +136,68 @@ public void testRiskScore() throws JsTestException, NoSuchFieldException, assertEquals(context.getSelectedAcr(), "1", "Expected acr value not found"); } + @Test + public void testAnalyticsPayload() + throws JsTestException, IdentityGovernanceException, NoSuchFieldException, IllegalAccessException { + + IdentityGovernanceService identityGovernanceService = Mockito.mock(IdentityGovernanceService.class); + FunctionsDataHolder functionsDataHolder = Mockito.mock(FunctionsDataHolder.class); + Mockito.when(functionsDataHolder.getIdentityGovernanceService()).thenReturn(identityGovernanceService); + Property property = new Property(); + property.setValue("http://localhost:" + microServicePort); + Mockito.when(identityGovernanceService.getConfiguration(new String[]{AnalyticsEngineConfigImpl.RECEIVER}, + "test_domain")).thenReturn(new Property[]{property}); + + Field functionsDataHolderInstance = FunctionsDataHolder.class.getDeclaredField("instance"); + functionsDataHolderInstance.setAccessible(true); + functionsDataHolderInstance.set(null, functionsDataHolder); + + Field frameworkServiceDataHolderInstance = FrameworkServiceDataHolder.class.getDeclaredField("instance"); + frameworkServiceDataHolderInstance.setAccessible(true); + FrameworkServiceDataHolder availableInstance = (FrameworkServiceDataHolder)frameworkServiceDataHolderInstance.get(null); + + LongWaitStatusDAOImpl daoImpl = new LongWaitStatusDAOImpl(); + CacheBackedLongWaitStatusDAO cacheBackedDao = new CacheBackedLongWaitStatusDAO(daoImpl); + int connectionTimeout = 5000; + LongWaitStatusStoreService longWaitStatusStoreService = + new LongWaitStatusStoreService(cacheBackedDao, connectionTimeout); + availableInstance.setLongWaitStatusStoreService(longWaitStatusStoreService); + + AuthenticationContext context = getAuthenticationContextForPayloadTest(); + + HttpServletRequest req = sequenceHandlerRunner.createHttpServletRequest(); + HttpServletResponse resp = sequenceHandlerRunner.createHttpServletResponse(); + + sequenceHandlerRunner.handle(req, resp, context, "carbon.super"); + + assertNotNull(context.getSelectedAcr()); + assertEquals(context.getSelectedAcr(), "1", "Expected acr value not found"); + + } + + private AuthenticationContext getAuthenticationContextForPayloadTest() + throws JsTestException { + + ServiceProvider sp1 = sequenceHandlerRunner.loadServiceProviderFromResource(ANALYTICS_PAYLOAD_TEST_SP, this); + LocalAndOutboundAuthenticationConfig localAndOutboundAuthenticationConfig = + sp1.getLocalAndOutBoundAuthenticationConfig(); + AuthenticationScriptConfig authenticationScriptConfig = localAndOutboundAuthenticationConfig + .getAuthenticationScriptConfig(); + + String jsonPayload = sequenceHandlerRunner.loadJson(ANALYTICS_PAYLOAD, this).toString(); + String content = authenticationScriptConfig.getContent(); + String newContent = String.format(content, jsonPayload, ANALYTICS_SERVICE_CHECK_PAYLOAD); + authenticationScriptConfig.setContent(newContent); + localAndOutboundAuthenticationConfig.setAuthenticationScriptConfig(authenticationScriptConfig); + sp1.setLocalAndOutBoundAuthenticationConfig(localAndOutboundAuthenticationConfig); + + AuthenticationContext context = sequenceHandlerRunner.createAuthenticationContext(sp1); + SequenceConfig sequenceConfig = sequenceHandlerRunner.getSequenceConfig(context, sp1); + context.setSequenceConfig(sequenceConfig); + context.initializeAnalyticsData(); + return context; + } + @POST @Path("/{appName}/{inputStream}") @Consumes("application/json") @@ -143,4 +215,27 @@ public Map> analyticsReceiver(@PathParam("appName") response.put("event", responseEvent); return response; } + + @POST + @Path(ANALYTICS_SERVICE_CHECK_PAYLOAD) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Map> analyticsReceiverCheckPayload(Map data) throws JsTestException { + + JsonObject expectedPayload = sequenceHandlerRunner.loadJson(ANALYTICS_PAYLOAD_JSON, this); + Gson gson = new Gson(); + String dataStr = gson.toJson(data.get("event")); + JsonObject actualPayload = gson.fromJson(dataStr, JsonObject.class); + + if (expectedPayload.equals(actualPayload)) { + Map responseEvent = new HashMap<>(); + responseEvent.put("riskScore", "1"); + Map> response = new HashMap<>(); + response.put("event", responseEvent); + return response; + } else { + throw new JsTestException("Payloads do not match. " + + String.format("Expected payload: %s, Actual payload: %s", expectedPayload, actualPayload)); + } + } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/analytics/analytics-payload-test-sp.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/analytics/analytics-payload-test-sp.xml new file mode 100644 index 00000000..a18109df --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/analytics/analytics-payload-test-sp.xml @@ -0,0 +1,124 @@ + + + 1 + default + Default Service Provider + + + + default + + + + + + + + + 1 + + + BasicMockAuthenticator + basicauth + true + + + true + true + + + 2 + + + HwkMockAuthenticator + true + HwkMockAuthenticator + + + HwkMockAuthenticator + true + + + + + false + false + + + 3 + + + FptMockAuthenticator + true + FptMockAuthenticator + + + FptMockAuthenticator + true + + + + + false + false + + + 4 + + + MockFallbackAuthenticator + basicauthfallback + true + + + true + true + + + 0) { + Log.info('data.event.riskScore > 0'); + context.selectedAcr = ''+ data.event.riskScore; + } + }, onFail: function (context, data) { + Log.info('fail Called'); + } + }); + } + }); +} + +]]> + flow + + + + + + true + + + diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/analytics/analytics-payload.json b/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/analytics/analytics-payload.json new file mode 100644 index 00000000..1692934b --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.analytics/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/analytics/analytics-payload.json @@ -0,0 +1,39 @@ +{ + "stringKey": "stringValue", + "numberKey": 123, + "booleanKey": true, + "arrayKey": [ + "arrayString", + 456, + false, + { + "nestedObjectInArrayKey": "nestedObjectValue", + "nestedArrayInArrayKey": ["nestedArrayValue1", "nestedArrayValue2"] + } + ], + "objectKey": { + "objectStringKey": "objectStringValue", + "objectNumberKey": 789, + "objectBooleanKey": false, + "nestedObjectKey": { + "nestedObjectStringKey": "nestedObjectStringValue", + "nestedObjectArrayKey": [ + "nestedArrayValue1", + 101112, + true + ] + }, + "arrayOfObjectsKey": [ + { + "arrayOfObjectsStringKey": "arrayOfObjectsStringValue1", + "arrayOfObjectsNumberKey": 131415, + "arrayOfObjectsBooleanKey": true + }, + { + "arrayOfObjectsStringKey": "arrayOfObjectsStringValue2", + "arrayOfObjectsNumberKey": 161718, + "arrayOfObjectsBooleanKey": false + } + ] + } +} \ No newline at end of file diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/choreo/CallChoreoFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/choreo/CallChoreoFunctionImpl.java index df09cb3a..aeb3e1fe 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/choreo/CallChoreoFunctionImpl.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/choreo/CallChoreoFunctionImpl.java @@ -71,6 +71,7 @@ import static org.apache.http.HttpHeaders.ACCEPT; import static org.apache.http.HttpHeaders.CONTENT_TYPE; +import static org.wso2.carbon.identity.conditional.auth.functions.common.utils.CommonUtils.getPayloadDataMap; import static org.wso2.carbon.identity.conditional.auth.functions.common.utils.Constants.OUTCOME_FAIL; import static org.wso2.carbon.identity.conditional.auth.functions.common.utils.Constants.OUTCOME_TIMEOUT; @@ -181,40 +182,6 @@ public void callChoreo(Map connectionMetaData, Map getPayloadDataMap(Map payloadData) { - - if (payloadData == null) { - return new HashMap<>(); - } - Map payloadDataMap = new HashMap<>(); - for (Map.Entry entry : payloadData.entrySet()) { - Object value = entry.getValue(); - if (value instanceof Map) { - payloadDataMap.put(entry.getKey(), getPayloadDataMap((Map) value)); - } else if (value instanceof List) { - payloadDataMap.put(entry.getKey(), processList((List) value)); - } else { - payloadDataMap.put(entry.getKey(), value); - } - } - return payloadDataMap; - } - - private List processList(List list) { - - List resultList = new ArrayList<>(); - for (Object item : list) { - if (item instanceof Map) { - resultList.add(getPayloadDataMap((Map) item)); - } if (item instanceof List) { - resultList.add(processList((List) item)); - } else { - resultList.add(item); - } - } - return resultList; - } - /** * This method decodes access token and compare its expiry time with the current time to decide whether it's * expired. diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/choreo/CallChoreoFunctionImplTest.java b/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/choreo/CallChoreoFunctionImplTest.java index e2ce573f..d2b5ccfa 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/choreo/CallChoreoFunctionImplTest.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/choreo/CallChoreoFunctionImplTest.java @@ -18,6 +18,8 @@ package org.wso2.carbon.identity.conditional.auth.functions.choreo; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JOSEObjectType; import com.nimbusds.jose.JWSAlgorithm; @@ -92,6 +94,7 @@ public class CallChoreoFunctionImplTest extends JsSequenceHandlerAbstractTest { private static final String TOKEN_ENDPOINT_FAILURE = "failure"; private static final AtomicInteger requestCount = new AtomicInteger(0); private static final String CHOREO_SERVICE_SUCCESS_PATH = "/choreo-service-success"; + private static final String CHOREO_SERVICE_CHECK_PAYLOAD = "/choreo-service-check-payload"; private static final String CHOREO_SERVICE_EXPIRE_TOKEN_ONCE = "/choreo-service-token-expired-once"; private static final String CHOREO_SERVICE_EXPIRE_TOKEN_ALWAYS = "/choreo-service-token-expired-always"; private static final String CHOREO_TOKEN_FAILURE = "/token-failure"; @@ -99,6 +102,9 @@ public class CallChoreoFunctionImplTest extends JsSequenceHandlerAbstractTest { private static final String TENANT_DOMAIN = "test_domain"; private static final String CONSUMER_KEY = "dummyKey"; private static final String CONSUMER_SECRET = "dummySecret"; + private static final String PAYLOAD_TEST_SP = "payload-test-sp.xml"; + public static final String CHOREO_PAYLOAD_JSON = "choreo-payload.json"; + public static final String RISK_TEST_SP_XML = "risk-test-sp.xml"; @WithRealmService private RealmService realmService; @@ -290,6 +296,25 @@ public void testCallChoreCachingToken() throws JsTestException, NoSuchFieldExcep } + @Test + public void testCallChoreoPayload() throws JsTestException, + NoSuchFieldException, IllegalAccessException { + + LOG.info("===== Testing callChoreo payload: "); + AuthenticationContext context = getAuthenticationContextForPayloadTest(CHOREO_SERVICE_CHECK_PAYLOAD); + + HttpServletRequest req = sequenceHandlerRunner.createHttpServletRequest(); + HttpServletResponse resp = sequenceHandlerRunner.createHttpServletResponse(); + + setChoreoDomain("localhost"); + setTokenEndpoint(TOKEN_ENDPOINT_SUCCESS); + sequenceHandlerRunner.handle(req, resp, context, "carbon.super"); + + assertNotNull(context.getSelectedAcr()); + assertEquals(context.getSelectedAcr(), "SUCCESS", "Payloads do not match. " + + "Call Choreo function call failed"); + } + /** * Create and returns an authentication context. * @@ -299,7 +324,7 @@ public void testCallChoreCachingToken() throws JsTestException, NoSuchFieldExcep */ private AuthenticationContext getAuthenticationContext(String choreoServiceResourcePath) throws JsTestException { - ServiceProvider sp1 = sequenceHandlerRunner.loadServiceProviderFromResource("risk-test-sp.xml", this); + ServiceProvider sp1 = sequenceHandlerRunner.loadServiceProviderFromResource(RISK_TEST_SP_XML, this); LocalAndOutboundAuthenticationConfig localAndOutboundAuthenticationConfig = sp1.getLocalAndOutBoundAuthenticationConfig(); AuthenticationScriptConfig authenticationScriptConfig = localAndOutboundAuthenticationConfig @@ -318,6 +343,30 @@ private AuthenticationContext getAuthenticationContext(String choreoServiceResou return context; } + private AuthenticationContext getAuthenticationContextForPayloadTest(String choreoServiceResourcePath) + throws JsTestException { + + ServiceProvider sp1 = sequenceHandlerRunner.loadServiceProviderFromResource(PAYLOAD_TEST_SP, this); + LocalAndOutboundAuthenticationConfig localAndOutboundAuthenticationConfig = + sp1.getLocalAndOutBoundAuthenticationConfig(); + AuthenticationScriptConfig authenticationScriptConfig = localAndOutboundAuthenticationConfig + .getAuthenticationScriptConfig(); + + String jsonPayload = sequenceHandlerRunner.loadJson(CHOREO_PAYLOAD_JSON, this).toString(); + String content = authenticationScriptConfig.getContent(); + String newContent = String.format(content, microServicePort, choreoServiceResourcePath, + CONSUMER_KEY, CONSUMER_SECRET, jsonPayload); + authenticationScriptConfig.setContent(newContent); + localAndOutboundAuthenticationConfig.setAuthenticationScriptConfig(authenticationScriptConfig); + sp1.setLocalAndOutBoundAuthenticationConfig(localAndOutboundAuthenticationConfig); + + AuthenticationContext context = sequenceHandlerRunner.createAuthenticationContext(sp1); + SequenceConfig sequenceConfig = sequenceHandlerRunner.getSequenceConfig(context, sp1); + context.setSequenceConfig(sequenceConfig); + context.initializeAnalyticsData(); + return context; + } + private void setChoreoDomain(String domain) { ConfigProvider.getInstance().getChoreoDomains().clear(); @@ -384,13 +433,35 @@ private String generateTestAccessToken(boolean isExpired) throws JOSEException { @Path(CHOREO_SERVICE_SUCCESS_PATH) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) - public Map choreoReceiver(Map data) { + public Map choreoReceiver(Map data) { Map response = new HashMap<>(); response.put("riskScore", "1"); return response; } + @POST + @Path(CHOREO_SERVICE_CHECK_PAYLOAD) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response choreoReceiverCheckPayload(Map data) throws JsTestException { + + JsonObject expectedPayload = sequenceHandlerRunner.loadJson(CHOREO_PAYLOAD_JSON, this); + Gson gson = new Gson(); + String dataStr = gson.toJson(data); + JsonObject actualPayload = gson.fromJson(dataStr, JsonObject.class); + + + if (expectedPayload.equals(actualPayload)) { + return Response + .ok() + .entity(data).build(); + } else { + throw new JsTestException("Payloads do not match. " + + String.format("Expected payload: %s, Actual payload: %s", expectedPayload, actualPayload)); + } + } + /** * This endpoint always returns a 200 OK response with an access token that has not been expired. * Simulates a scenario where the call to the Choreo token endpoint succeed. diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/choreo/choreo-payload.json b/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/choreo/choreo-payload.json new file mode 100644 index 00000000..1692934b --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/choreo/choreo-payload.json @@ -0,0 +1,39 @@ +{ + "stringKey": "stringValue", + "numberKey": 123, + "booleanKey": true, + "arrayKey": [ + "arrayString", + 456, + false, + { + "nestedObjectInArrayKey": "nestedObjectValue", + "nestedArrayInArrayKey": ["nestedArrayValue1", "nestedArrayValue2"] + } + ], + "objectKey": { + "objectStringKey": "objectStringValue", + "objectNumberKey": 789, + "objectBooleanKey": false, + "nestedObjectKey": { + "nestedObjectStringKey": "nestedObjectStringValue", + "nestedObjectArrayKey": [ + "nestedArrayValue1", + 101112, + true + ] + }, + "arrayOfObjectsKey": [ + { + "arrayOfObjectsStringKey": "arrayOfObjectsStringValue1", + "arrayOfObjectsNumberKey": 131415, + "arrayOfObjectsBooleanKey": true + }, + { + "arrayOfObjectsStringKey": "arrayOfObjectsStringValue2", + "arrayOfObjectsNumberKey": 161718, + "arrayOfObjectsBooleanKey": false + } + ] + } +} \ No newline at end of file diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/choreo/payload-test-sp.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/choreo/payload-test-sp.xml new file mode 100644 index 00000000..f1d914ec --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.choreo/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/choreo/payload-test-sp.xml @@ -0,0 +1,128 @@ + + + + 1 + default + Default Service Provider + + + + default + + + + + + + + + 1 + + + BasicMockAuthenticator + basicauth + true + + + true + true + + + 2 + + + HwkMockAuthenticator + true + HwkMockAuthenticator + + + HwkMockAuthenticator + true + + + + + false + false + + + 3 + + + FptMockAuthenticator + true + FptMockAuthenticator + + + FptMockAuthenticator + true + + + + + false + false + + + 4 + + + MockFallbackAuthenticator + basicauthfallback + true + + + true + true + + + + flow + + + + + + true + + + diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.common/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/common/utils/CommonUtils.java b/components/org.wso2.carbon.identity.conditional.auth.functions.common/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/common/utils/CommonUtils.java index ab5571ea..f737e587 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.common/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/common/utils/CommonUtils.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.common/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/common/utils/CommonUtils.java @@ -24,6 +24,11 @@ import org.wso2.carbon.identity.governance.IdentityGovernanceException; import org.wso2.carbon.identity.governance.IdentityGovernanceService; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public class CommonUtils { public static String getConnectorConfig(String key, String tenantDomain) throws IdentityEventException { @@ -44,4 +49,38 @@ public static String getConnectorConfig(String key, String tenantDomain) throws throw new IdentityEventException("Error while getting connector configurations for property :" + key, e); } } + + public static Map getPayloadDataMap(Map payloadData) { + + if (payloadData == null) { + return new HashMap<>(); + } + Map payloadDataMap = new HashMap<>(); + for (Map.Entry entry : payloadData.entrySet()) { + Object value = entry.getValue(); + if (value instanceof Map) { + payloadDataMap.put(entry.getKey(), getPayloadDataMap((Map) value)); + } else if (value instanceof List) { + payloadDataMap.put(entry.getKey(), processList((List) value)); + } else { + payloadDataMap.put(entry.getKey(), value); + } + } + return payloadDataMap; + } + + private static List processList(List list) { + + List resultList = new ArrayList<>(); + for (Object item : list) { + if (item instanceof Map) { + resultList.add(getPayloadDataMap((Map) item)); + } else if (item instanceof List) { + resultList.add(processList((List) item)); + } else { + resultList.add(item); + } + } + return resultList; + } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.test.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/test/utils/sequence/JsSequenceHandlerRunner.java b/components/org.wso2.carbon.identity.conditional.auth.functions.test.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/test/utils/sequence/JsSequenceHandlerRunner.java index 544ce07d..97aac5ef 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.test.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/test/utils/sequence/JsSequenceHandlerRunner.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.test.utils/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/test/utils/sequence/JsSequenceHandlerRunner.java @@ -18,10 +18,17 @@ package org.wso2.carbon.identity.conditional.auth.functions.test.utils.sequence; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.impl.builder.StAXOMBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.json.JSONObject; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.identity.application.authentication.framework.JsFunctionRegistry; import org.wso2.carbon.identity.application.authentication.framework.config.builder.FileBasedConfigurationBuilder; @@ -56,12 +63,14 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.security.Principal; import java.util.Collection; import java.util.Collections; @@ -70,6 +79,7 @@ import java.util.Locale; import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; @@ -104,6 +114,7 @@ public class JsSequenceHandlerRunner { private JsFunctionRegistryImpl jsFunctionRegistry; private URL applicationAuthenticatorConfigFileLocation; + protected static Gson gson = new GsonBuilder().create(); public static final int THREAD_COUNT = 1; public static final long SUPERVISOR_TIMEOUT = 500000L; @@ -247,6 +258,26 @@ public ServiceProvider loadServiceProviderFromResource(String spFileName, Object return ServiceProvider.build(documentElement); } + public JsonObject loadJson(String jsonFileName, Object loader) throws JsTestException { + try (InputStream inputStream = loader.getClass().getResourceAsStream(jsonFileName)) { + if (inputStream == null) { + throw new JsTestException("Resource not found: " + jsonFileName); + } + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + String jsonString = reader.lines().collect(Collectors.joining()); + JsonElement jsonElement = JsonParser.parseString(jsonString); + if (jsonElement.isJsonObject()) { + return jsonElement.getAsJsonObject(); + } else { + throw new JsTestException("The JSON file does not contain a valid JSON object: " + jsonFileName); + } + } + } catch (IOException | JsonSyntaxException e) { + throw new JsTestException("Error in reading or parsing JSON file at: " + jsonFileName, e); + } + } + + public AuthenticationContext createAuthenticationContext(ServiceProvider serviceProvider) { AuthenticationContext authenticationContext = new AuthenticationContext();