diff --git a/.github/workflows/pr-builder.yml b/.github/workflows/pr-builder.yml index 8573247c..aa98b438 100644 --- a/.github/workflows/pr-builder.yml +++ b/.github/workflows/pr-builder.yml @@ -25,7 +25,7 @@ jobs: - name: Set up Adopt JDK 11 uses: actions/setup-java@v2 with: - java-version: "11" + java-version: [ 11.0.19+7 ] distribution: "adopt" - name: Cache local Maven repository id: cache-maven-m2 diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/pom.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.http/pom.xml index 0adb68fa..7d479110 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.http/pom.xml +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/pom.xml @@ -133,6 +133,7 @@ javax.servlet.*; version="${imp.pkg.version.javax.servlet}", + org.apache.commons.collections, org.apache.commons.io, org.apache.commons.lang, org.apache.commons.logging, @@ -140,10 +141,12 @@ org.apache.http.impl, org.apache.http.util, org.apache.http.client, + org.apache.http.client.entity, org.apache.http.client.methods, org.apache.http.client.config, org.apache.http.impl.client, org.apache.http.conn, + org.apache.http.message, org.json.simple, org.json.simple.parser, org.apache.http, diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/AbstractHTTPFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/AbstractHTTPFunction.java index 3552338e..58fb58aa 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/AbstractHTTPFunction.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/AbstractHTTPFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.com). + * Copyright (c) 2021, WSO2 LLC. (http://www.wso2.com). * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -20,6 +20,7 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.http.Header; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpUriRequest; @@ -42,6 +43,8 @@ import java.util.List; import java.util.Map; +import static org.apache.http.HttpHeaders.ACCEPT; + /** * Abstract class for handling http calls. */ @@ -49,7 +52,10 @@ public abstract class AbstractHTTPFunction { private static final Log LOG = LogFactory.getLog(AbstractHTTPFunction.class); protected static final String TYPE_APPLICATION_JSON = "application/json"; + protected static final String TYPE_APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded"; + protected static final String TYPE_TEXT_PLAIN = "text/plain"; private static final char DOMAIN_SEPARATOR = '.'; + private static final String RESPONSE = "response"; private final List allowedDomains; private CloseableHttpClient client; @@ -73,15 +79,15 @@ protected void executeHttpMethod(HttpUriRequest request, Map eve JSONObject json = null; int responseCode; String outcome; - String epUrl = null; + String endpointURL = null; if (request.getURI() != null) { - epUrl = request.getURI().toString(); + endpointURL = request.getURI().toString(); } if (!isValidRequestDomain(request.getURI())) { outcome = Constants.OUTCOME_FAIL; - LOG.error("Provided Url does not contain a allowed domain. Invalid Url: " + epUrl); + LOG.error("Provided Url does not contain a allowed domain. Invalid Url: " + endpointURL); asyncReturn.accept(context, Collections.emptyMap(), outcome); return; } @@ -90,21 +96,30 @@ protected void executeHttpMethod(HttpUriRequest request, Map eve responseCode = response.getStatusLine().getStatusCode(); if (responseCode >= 200 && responseCode < 300) { outcome = Constants.OUTCOME_SUCCESS; - String jsonString = EntityUtils.toString(response.getEntity()); - JSONParser parser = new JSONParser(); - json = (JSONObject) parser.parse(jsonString); + if (response.getEntity() != null) { + Header contentType = response.getEntity().getContentType(); + String jsonString = EntityUtils.toString(response.getEntity()); + if (contentType != null && contentType.getValue().contains(TYPE_TEXT_PLAIN)) { + // For 'text/plain', put the response body into the JSON object as a single field. + json = new JSONObject(); + json.put(RESPONSE, jsonString); + } else { + JSONParser parser = new JSONParser(); + json = (JSONObject) parser.parse(jsonString); + } + } } else { outcome = Constants.OUTCOME_FAIL; } } catch (IllegalArgumentException e) { - LOG.error("Invalid Url: " + epUrl, e); + LOG.error("Invalid Url: " + endpointURL, e); outcome = Constants.OUTCOME_FAIL; } catch (ConnectTimeoutException e) { - LOG.error("Error while waiting to connect to " + epUrl, e); + LOG.error("Error while waiting to connect to " + endpointURL, e); outcome = Constants.OUTCOME_TIMEOUT; } catch (SocketTimeoutException e) { - LOG.error("Error while waiting for data from " + epUrl, e); + LOG.error("Error while waiting for data from " + endpointURL, e); outcome = Constants.OUTCOME_TIMEOUT; } catch (IOException e) { LOG.error("Error while calling endpoint. ", e); @@ -172,4 +187,35 @@ private String getParentDomainFromUrl(URI url) { } return parentDomain; } + + /** + * Validate the headers. + * + * @param headers Map of headers. + * @return Map of headers. + */ + protected Map validateHeaders(Map headers) { + + for (Map.Entry entry : headers.entrySet()) { + if (!(entry.getValue() instanceof String)) { + throw new IllegalArgumentException("Header values must be of type String"); + } + } + return (Map) headers; + } + + /** + * Set headers to the request. + * Default Accept header is set to application/json. + * + * @param request HttpUriRequest. + * @param headers Map of headers. + */ + protected void setHeaders(HttpUriRequest request, Map headers) { + + headers.putIfAbsent(ACCEPT, TYPE_APPLICATION_JSON); + headers.entrySet().stream() + .filter(entry -> StringUtils.isNotBlank(entry.getKey()) && !entry.getKey().equals("null")) + .forEach(entry -> request.setHeader(entry.getKey(), entry.getValue())); + } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunction.java index 17942af1..87d04fab 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunction.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -29,8 +29,10 @@ public interface HTTPGetFunction { /** * POST data to the given endpoint. * - * @param epUrl Endpoint url. - * @param eventHandlers event handlers. + * @param endpointURL Endpoint url. + * @param params Parameters. + * 1. headers headers (optional). + * 2. eventHandlers event handlers. */ - void httpGet(String epUrl, Map eventHandlers); + void httpGet(String endpointURL, Object... params); } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunctionImpl.java index 27edf666..5d2016c3 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunctionImpl.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunctionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -18,10 +18,12 @@ package org.wso2.carbon.identity.conditional.auth.functions.http; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.client.methods.HttpGet; +import java.util.HashMap; import java.util.Map; import static org.apache.http.HttpHeaders.ACCEPT; @@ -39,10 +41,37 @@ public HTTPGetFunctionImpl() { } @Override - public void httpGet(String epUrl, Map eventHandlers) { + public void httpGet(String endpointURL, Object... params) { + + Map eventHandlers; + Map headers = new HashMap<>(); + + switch (params.length) { + case 1: + if (params[0] instanceof Map) { + eventHandlers = (Map) params[0]; + } else { + throw new IllegalArgumentException("Invalid argument type. Expected eventHandlers " + + "(Map)."); + } + break; + case 2: + if (params[0] instanceof Map && params[1] instanceof Map ) { + headers = validateHeaders((Map) params[0]); + eventHandlers = (Map) params[1]; + } else { + throw new IllegalArgumentException("Invalid argument types. Expected headers (Map) " + + "and eventHandlers (Map) respectively."); + } + break; + default: + throw new IllegalArgumentException("Invalid number of arguments. Expected 1 or 2, but got: " + + params.length + "."); + } + + HttpGet request = new HttpGet(endpointURL); + setHeaders(request, headers); - HttpGet request = new HttpGet(epUrl); - request.setHeader(ACCEPT, TYPE_APPLICATION_JSON); executeHttpMethod(request, eventHandlers); } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunction.java b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunction.java index 4749c268..ec1efbc7 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunction.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -30,9 +30,11 @@ public interface HTTPPostFunction { /** * POST data to the given endpoint. * - * @param epUrl Endpoint url. - * @param payloadData payload data. - * @param eventHandlers event handlers. + * @param endpointURL Endpoint url. + * @param params parameters. + * 1. payloadData payload data. + * 2. headers headers (optional). + * 3. eventHandlers event handlers. */ - void httpPost(String epUrl, Map payloadData, Map eventHandlers); + void httpPost(String endpointURL, Object... params); } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunctionImpl.java b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunctionImpl.java index 923375be..f8becd3f 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunctionImpl.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunctionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -18,13 +18,21 @@ package org.wso2.carbon.identity.conditional.auth.functions.http; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; +import org.apache.http.message.BasicNameValuePair; import org.json.simple.JSONObject; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; import static org.apache.http.HttpHeaders.ACCEPT; @@ -44,17 +52,68 @@ public HTTPPostFunctionImpl() { } @Override - public void httpPost(String epUrl, Map payloadData, Map eventHandlers) { + public void httpPost(String endpointURL, Object... params) { - HttpPost request = new HttpPost(epUrl); - request.setHeader(ACCEPT, TYPE_APPLICATION_JSON); - request.setHeader(CONTENT_TYPE, TYPE_APPLICATION_JSON); + Map eventHandlers; + Map payloadData = new HashMap<>(); + Map headers = new HashMap<>(); - JSONObject jsonObject = new JSONObject(); - for (Map.Entry dataElements : payloadData.entrySet()) { - jsonObject.put(dataElements.getKey(), dataElements.getValue()); + switch (params.length) { + case 1: + if (params[0] instanceof Map) { + eventHandlers = (Map) params[0]; + } else { + throw new IllegalArgumentException("Invalid argument type. Expected eventHandlers " + + "(Map)."); + } + break; + case 2: + if (params[0] instanceof Map && params[1] instanceof Map) { + payloadData = (Map) params[0]; + eventHandlers = (Map) params[1]; + } else { + throw new IllegalArgumentException("Invalid argument types. Expected payloadData and eventHandlers " + + "(both of type Map) respectively."); + } + break; + case 3: + if (params[0] instanceof Map && params[1] instanceof Map && params[2] instanceof Map) { + payloadData = (Map) params[0]; + headers = validateHeaders((Map) params[1]); + eventHandlers = (Map) params[2]; + } else { + throw new IllegalArgumentException("Invalid argument type. Expected payloadData " + + "(Map), headers (Map), and eventHandlers " + + "(Map) respectively."); + } + break; + default: + throw new IllegalArgumentException("Invalid number of arguments. Expected 1, 2, or 3. Found: " + + params.length + "."); + } + + HttpPost request = new HttpPost(endpointURL); + headers.putIfAbsent(CONTENT_TYPE, TYPE_APPLICATION_JSON); + setHeaders(request, headers); + + if (MapUtils.isNotEmpty(payloadData)) { + /* + For the header "Content-Type : application/x-www-form-urlencoded" request body data is set to + UrlEncodedFormEntity format. For the other cases request body data is set to StringEntity format. + */ + if (TYPE_APPLICATION_FORM_URLENCODED.equals(headers.get(CONTENT_TYPE))) { + List entities = new ArrayList<>(); + for (Map.Entry dataElements : payloadData.entrySet()) { + String value = (dataElements.getValue() != null) ? dataElements.getValue().toString() : null; + entities.add(new BasicNameValuePair(dataElements.getKey(), value)); + } + request.setEntity(new UrlEncodedFormEntity(entities, StandardCharsets.UTF_8)); + } else { + JSONObject jsonObject = new JSONObject(); + jsonObject.putAll(payloadData); + request.setEntity(new StringEntity(jsonObject.toJSONString(), StandardCharsets.UTF_8)); } - request.setEntity(new StringEntity(jsonObject.toJSONString(), StandardCharsets.UTF_8)); - executeHttpMethod(request, eventHandlers); + } + executeHttpMethod(request, eventHandlers); } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/internal/HTTPFunctionsServiceComponent.java b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/internal/HTTPFunctionsServiceComponent.java index f2335bea..2c60b636 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/internal/HTTPFunctionsServiceComponent.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/main/java/org/wso2/carbon/identity/conditional/auth/functions/http/internal/HTTPFunctionsServiceComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunctionImplTest.java b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunctionImplTest.java index 97261250..cf5ebe68 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunctionImplTest.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPGetFunctionImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.com). + * Copyright (c) 2021, WSO2 LLC. (http://www.wso2.com). * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.conditional.auth.functions.http; import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.wso2.carbon.identity.application.authentication.framework.config.model.SequenceConfig; @@ -45,9 +46,14 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; import javax.ws.rs.Path; import javax.ws.rs.Produces; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.doNothing; import static org.testng.Assert.assertEquals; @WithCarbonHome @@ -58,11 +64,14 @@ public class HTTPGetFunctionImplTest extends JsSequenceHandlerAbstractTest { private static final String TEST_SP_CONFIG = "http-get-test-sp.xml"; + private static final String TEST_HEADERS = "http-get-test-headers.xml"; private static final String TENANT_DOMAIN = "carbon.super"; private static final String STATUS = "status"; private static final String SUCCESS = "SUCCESS"; private static final String FAILED = "FAILED"; private static final String ALLOWED_DOMAIN = "abc"; + private static final String AUTHORIZATION = "Authorization"; + private HTTPGetFunctionImpl httpGetFunction; @InjectMicroservicePort private int microServicePort; @@ -78,6 +87,10 @@ protected void initClass() throws Exception { new LongWaitStatusStoreService(cacheBackedDao, connectionTimeout); FrameworkServiceDataHolder.getInstance().setLongWaitStatusStoreService(longWaitStatusStoreService); sequenceHandlerRunner.registerJsFunction("httpGet", new HTTPGetFunctionImpl()); + + // Mocking the executeHttpMethod method to avoid actual http calls. + httpGetFunction = spy(new HTTPGetFunctionImpl()); + doNothing().when(httpGetFunction).executeHttpMethod(any(), any()); } @AfterClass @@ -86,11 +99,17 @@ protected void tearDown() { unsetAllowedDomains(); } + @AfterMethod + protected void tearDownMethod() { + + reset(httpGetFunction); + } + @Test public void testHttpGetMethod() throws JsTestException { - String requestUrl = getRequestUrl(); - String result = executeHttpGetFunction(requestUrl); + String requestUrl = getRequestUrl("dummy-get"); + String result = executeHttpGetFunction(requestUrl, TEST_SP_CONFIG); assertEquals(result, SUCCESS, "The http get request was not successful. Result from request: " + result); } @@ -100,13 +119,50 @@ public void testHttpGetMethodUrlValidation() throws JsTestException, NoSuchField sequenceHandlerRunner.registerJsFunction("httpGet", new HTTPGetFunctionImpl()); setAllowedDomain(ALLOWED_DOMAIN); - String requestUrl = getRequestUrl(); - String result = executeHttpGetFunction(requestUrl); + String requestUrl = getRequestUrl("dummy-get"); + String result = executeHttpGetFunction(requestUrl, TEST_SP_CONFIG); assertEquals(result, FAILED, "The http get request should fail but it was successful. Result from request: " + result); } + /** + * Test http get method with headers. + * Check if the headers are sent with the request. + * + * @throws JsTestException + */ + @Test + public void testHttpGetMethodWithHeaders() throws JsTestException { + + String requestUrl = getRequestUrl("dummy-get-with-headers"); + String result = executeHttpGetFunction(requestUrl, TEST_HEADERS); + + assertEquals(result, SUCCESS, "The http get request was not successful. Result from request: " + result); + } + + /** + * Tests the behavior of the httpGet function when provided with null headers. + * + * @throws IllegalArgumentException if the provided arguments are not valid. + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testHttpGetWithNullHeaders() { + Map eventHandlers = new HashMap<>(); + httpGetFunction.httpGet(getRequestUrl("dummy-get"), null, eventHandlers); + } + + /** + * Tests the behavior of the httpGet function when invalid number of arguments are provided. + * + * @throws IllegalArgumentException if the provided arguments are not valid. + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testHttpGetWithInvalidNumberOfArguments() { + Map eventHandlers = new HashMap<>(); + httpGetFunction.httpGet(getRequestUrl("dummy-get"), eventHandlers, eventHandlers, eventHandlers); + } + private void setAllowedDomain(String domain) { ConfigProvider.getInstance().getAllowedDomainsForHttpFunctions().add(domain); @@ -117,14 +173,14 @@ private void unsetAllowedDomains() { ConfigProvider.getInstance().getAllowedDomainsForHttpFunctions().clear(); } - private String getRequestUrl() { + private String getRequestUrl(String path) { - return "http://localhost:" + microServicePort + "/dummy-get"; + return "http://localhost:" + microServicePort + "/" + path; } - private String executeHttpGetFunction(String requestUrl) throws JsTestException { + private String executeHttpGetFunction(String requestUrl, String adaptiveAuthScript) throws JsTestException { - ServiceProvider sp = sequenceHandlerRunner.loadServiceProviderFromResource(TEST_SP_CONFIG, this); + ServiceProvider sp = sequenceHandlerRunner.loadServiceProviderFromResource(adaptiveAuthScript, this); updateSPAuthScriptRequestUrl(sp, requestUrl); AuthenticationContext context = sequenceHandlerRunner.createAuthenticationContext(sp); @@ -163,4 +219,18 @@ public Map dummyGet() { response.put(STATUS, SUCCESS); return response; } + + @GET + @Path("/dummy-get-with-headers") + @Produces("application/json") + public Map dummyGetWithHeaders(@HeaderParam(AUTHORIZATION) String authorization) { + + Map response = new HashMap<>(); + if (authorization != null) { + response.put(STATUS, SUCCESS); + } else { + response.put(STATUS, FAILED); + } + return response; + } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunctionImplTest.java b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunctionImplTest.java index 41ffcc8b..963f3e8d 100644 --- a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunctionImplTest.java +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/java/org/wso2/carbon/identity/conditional/auth/functions/http/HTTPPostFunctionImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.com). + * Copyright (c) 2021, WSO2 LLC. (http://www.wso2.com). * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.conditional.auth.functions.http; import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.wso2.carbon.identity.application.authentication.framework.config.model.SequenceConfig; @@ -45,10 +46,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.Consumes; -import javax.ws.rs.POST; +import javax.ws.rs.HeaderParam; import javax.ws.rs.Path; +import javax.ws.rs.POST; import javax.ws.rs.Produces; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.doNothing; import static org.testng.Assert.assertEquals; @WithCarbonHome @@ -59,12 +65,15 @@ public class HTTPPostFunctionImplTest extends JsSequenceHandlerAbstractTest { private static final String TEST_SP_CONFIG = "http-post-test-sp.xml"; + private static final String TEST_HEADERS = "http-post-test-headers.xml"; private static final String TENANT_DOMAIN = "carbon.super"; private static final String STATUS = "status"; private static final String SUCCESS = "SUCCESS"; private static final String FAILED = "FAILED"; private static final String EMAIL = "email"; private static final String ALLOWED_DOMAIN = "abc"; + private static final String AUTHORIZATION = "Authorization"; + private HTTPPostFunctionImpl httpPostFunction; @InjectMicroservicePort private int microServicePort; @@ -80,6 +89,10 @@ protected void initClass() throws Exception { new LongWaitStatusStoreService(cacheBackedDao, connectionTimeout); FrameworkServiceDataHolder.getInstance().setLongWaitStatusStoreService(longWaitStatusStoreService); sequenceHandlerRunner.registerJsFunction("httpPost", new HTTPPostFunctionImpl()); + + // Mocking the executeHttpMethod method to avoid actual http calls. + httpPostFunction = spy(new HTTPPostFunctionImpl()); + doNothing().when(httpPostFunction).executeHttpMethod(any(), any()); } @AfterClass @@ -88,11 +101,17 @@ protected void tearDown() { unsetAllowedDomains(); } + @AfterMethod + protected void tearDownTest() { + + reset(httpPostFunction); + } + @Test public void testHttpPostMethod() throws JsTestException { - String requestUrl = getRequestUrl(); - String result = executeHttpPostFunction(requestUrl); + String requestUrl = getRequestUrl("dummy-post"); + String result = executeHttpPostFunction(requestUrl, TEST_SP_CONFIG); assertEquals(result, SUCCESS, "The http post request was not successful. Result from request: " + result); } @@ -101,13 +120,55 @@ public void testHttpPostMethod() throws JsTestException { public void testHttpPostMethodUrlValidation() throws JsTestException, NoSuchFieldException, IllegalAccessException { setAllowedDomain(ALLOWED_DOMAIN); - String requestUrl = getRequestUrl(); - String result = executeHttpPostFunction(requestUrl); + String requestUrl = getRequestUrl("dummy-post"); + String result = executeHttpPostFunction(requestUrl, TEST_SP_CONFIG); assertEquals(result, FAILED, "The http post request should fail but it was successful. Result from request: " + result); } + /** + * Test httpPost with headers. + * Check if the headers are sent with the request. + * + * @throws JsTestException + */ + @Test + public void testHttpPostWithHeaders() throws JsTestException { + + String requestUrl = getRequestUrl("dummy-post-headers"); + String result = executeHttpPostFunction(requestUrl, TEST_HEADERS); + assertEquals(result, SUCCESS, "The http post request was not successful. Result from request: " + + result); + } + + /** + * Tests the behavior of the httpPost function when provided with null headers. + * + * @throws IllegalArgumentException if the provided arguments are not valid. + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testHttpPostWithNullHeaders() { + + Map payloadData = new HashMap<>(); + Map eventHandlers = new HashMap<>(); + httpPostFunction.httpPost(getRequestUrl("dummy-post"), payloadData, null, eventHandlers); + } + + /** + * Tests the behavior of the httpPost function when provided with invalid number of arguments. + * + * @throws IllegalArgumentException if the provided arguments are not valid. + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testHttpPostWithInvalidNumberOfArguments() { + + Map payloadData = new HashMap<>(); + Map headers = new HashMap<>(); + Map eventHandlers = new HashMap<>(); + httpPostFunction.httpPost(getRequestUrl("dummy-post"), payloadData, headers, eventHandlers, eventHandlers); + } + private void setAllowedDomain(String domain) { ConfigProvider.getInstance().getAllowedDomainsForHttpFunctions().add(domain); @@ -118,14 +179,14 @@ private void unsetAllowedDomains() { ConfigProvider.getInstance().getAllowedDomainsForHttpFunctions().clear(); } - private String getRequestUrl() { + private String getRequestUrl(String path) { - return "http://localhost:" + microServicePort + "/dummy-post"; + return "http://localhost:" + microServicePort + "/" + path; } - private String executeHttpPostFunction(String requestUrl) throws JsTestException { + private String executeHttpPostFunction(String requestUrl, String adaptiveAuthScript) throws JsTestException { - ServiceProvider sp = sequenceHandlerRunner.loadServiceProviderFromResource(TEST_SP_CONFIG, this); + ServiceProvider sp = sequenceHandlerRunner.loadServiceProviderFromResource(adaptiveAuthScript, this); updateSPAuthScriptRequestUrl(sp, requestUrl); AuthenticationContext context = sequenceHandlerRunner.createAuthenticationContext(sp); @@ -169,4 +230,26 @@ public Map dummyPost(Map data) { } return response; } + + /** + * Dummy post method to test payload and headers. + * Check if the payload data and headers are sent with the request. + * @param authorization + * @param data + * @return + */ + @POST + @Path("/dummy-post-headers") + @Produces("application/json") + @Consumes("application/json") + public Map dummyPostWithHeaders(@HeaderParam(AUTHORIZATION) String authorization, Map data) { + + Map response = new HashMap<>(); + if (data.containsKey(EMAIL) && authorization != null) { + response.put(STATUS, SUCCESS); + } else { + response.put(STATUS, FAILED); + } + return response; + } } diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/http/http-get-test-headers.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/http/http-get-test-headers.xml new file mode 100644 index 00000000..742a7f3e --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/http/http-get-test-headers.xml @@ -0,0 +1,79 @@ + + + + 1 + default + Default Service Provider + + + + default + + + + + + + + + 1 + + + BasicMockAuthenticator + basicauth + true + + + true + true + + + + flow + + + + + + true + + + diff --git a/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/http/http-post-test-headers.xml b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/http/http-post-test-headers.xml new file mode 100644 index 00000000..5599c869 --- /dev/null +++ b/components/org.wso2.carbon.identity.conditional.auth.functions.http/src/test/resources/org/wso2/carbon/identity/conditional/auth/functions/http/http-post-test-headers.xml @@ -0,0 +1,82 @@ + + + + 1 + default + Default Service Provider + + + + default + + + + + + + + + 1 + + + BasicMockAuthenticator + basicauth + true + + + true + true + + + + flow + + + + + + true + + +