diff --git a/CHANGELOG.md b/CHANGELOG.md index 2af2b0857..ea946cf39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). + +# [1.14.7] In progress +## Fixed + + +### Added +-allow APIM cli to connect to API Manager protected by Cloudflare (See issue [#505](https://github.com/Axway-API-Management-Plus/apim-cli/issues/505)) + + - Added new paramater named customHeaders to handle additonal headers. + E.g ./apim.sh api get -n CalculatorService3 -o json -h localhost -u apiadmin -customHeaders abc:xyz + # [1.14.6] 2024-10-11 ## Fixed - Importing SOAP API with different endpoints (for import and for runtime calls) (See issue [#501](https://github.com/Axway-API-Management-Plus/apim-cli/issues/501)) diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/lib/CoreCLIOptions.java b/modules/apim-adapter/src/main/java/com/axway/apim/lib/CoreCLIOptions.java index 18a56f4d1..55da673ac 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/lib/CoreCLIOptions.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/lib/CoreCLIOptions.java @@ -40,6 +40,7 @@ public Parameters getParams() throws AppException { params.setTimeout(getValue("timeout")); params.setDisableCompression(hasOption("disableCompression")); params.setOverrideSpecBasePath(hasOption("overrideSpecBasePath")); + params.setCustomHeaders(getValue("customHeaders")); return params; } @@ -152,7 +153,11 @@ public void addOptions() { option = new Option("overrideSpecBasePath", "Override API Specification ( open api, Swagger 2) using backendBasepath"); option.setRequired(false); - addOption(option); + cliOptions.addOption(option); + + option = new Option("customHeaders", true,"Custom http headers added while calling API manager in case it is protected with Gateway"); + option.setRequired(false); + cliOptions.addOption(option); } @Override diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/lib/CoreParameters.java b/modules/apim-adapter/src/main/java/com/axway/apim/lib/CoreParameters.java index c28631b46..81c58ca4e 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/lib/CoreParameters.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/lib/CoreParameters.java @@ -73,6 +73,7 @@ public static Mode valueOfDefault(String key) { private int timeout; private boolean disableCompression; private boolean overrideSpecBasePath; + private String customHeaders; public CoreParameters() { instance = this; @@ -456,6 +457,14 @@ public void setOverrideSpecBasePath(boolean overrideSpecBasePath) { this.overrideSpecBasePath = overrideSpecBasePath; } + public String getCustomHeaders() { + return customHeaders; + } + + public void setCustomHeaders(String customHeaders) { + this.customHeaders = customHeaders; + } + @Override public String toString() { return "[hostname=" + hostname + ", username=" + username + ", stage=" + stage + "]"; diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/lib/utils/rest/APIMHttpClient.java b/modules/apim-adapter/src/main/java/com/axway/apim/lib/utils/rest/APIMHttpClient.java index 93f03cd27..9037b6470 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/lib/utils/rest/APIMHttpClient.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/lib/utils/rest/APIMHttpClient.java @@ -3,6 +3,7 @@ import com.axway.apim.lib.CoreParameters; import com.axway.apim.lib.error.AppException; import com.axway.apim.lib.error.ErrorCode; +import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; @@ -25,11 +26,15 @@ import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.DefaultProxyRoutePlanner; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeader; import org.apache.http.ssl.SSLContextBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; /** * The interface to the API-Manager itself responsible to set up the underlying HTTPS-Communication. @@ -71,9 +76,9 @@ private void createConnection(URI uri) throws AppException { builder.loadTrustMaterial(null, new TrustAllStrategy()); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(builder.build(), new NoopHostnameVerifier()); Registry r = RegistryBuilder.create() - .register(uri.getScheme(), sslConnectionSocketFactory) - .register("http", PlainConnectionSocketFactory.INSTANCE) - .build(); + .register(uri.getScheme(), sslConnectionSocketFactory) + .register("http", PlainConnectionSocketFactory.INSTANCE) + .build(); httpClientConnectionManager = new PoolingHttpClientConnectionManager(r); httpClientConnectionManager.setMaxTotal(5); @@ -88,14 +93,14 @@ private void createConnection(URI uri) throws AppException { int timeout = params.getTimeout(); LOG.debug("API Manager CLI http client timeout : {}", timeout); RequestConfig.Builder defaultRequestConfig = RequestConfig.custom() - .setConnectTimeout(timeout) - .setSocketTimeout(timeout) - .setConnectionRequestTimeout(timeout) - .setCookieSpec(CookieSpecs.STANDARD); + .setConnectTimeout(timeout) + .setSocketTimeout(timeout) + .setConnectionRequestTimeout(timeout) + .setCookieSpec(CookieSpecs.STANDARD); HttpClientBuilder clientBuilder = HttpClientBuilder.create() - .disableRedirectHandling() - .setConnectionManager(httpClientConnectionManager) - .useSystemProperties(); + .disableRedirectHandling() + .setConnectionManager(httpClientConnectionManager) + .useSystemProperties(); // Check if a proxy is configured if (params.getProxyHost() != null) { @@ -114,12 +119,32 @@ private void createConnection(URI uri) throws AppException { if (params.isDisableCompression()) clientBuilder.disableContentCompression(); clientBuilder.setDefaultRequestConfig(defaultRequestConfig.build()); + String customHeader = params.getCustomHeaders(); + if (customHeader != null) { + List
headers = splitStringToHttpHeaders(customHeader); + clientBuilder.setDefaultHeaders(headers); + } this.httpClient = clientBuilder.build(); } catch (Exception e) { throw new AppException("Can't create connection to API-Manager.", ErrorCode.API_MANAGER_COMMUNICATION); } } + public List
splitStringToHttpHeaders(String input) { + List
headers = new ArrayList<>(); + String[] headersArray = input.split(","); + for (String headerStr : headersArray) { + StringTokenizer tokenizer = new StringTokenizer(headerStr, ":"); + while (tokenizer.hasMoreTokens()) { + String key = tokenizer.nextToken(); + String value = tokenizer.nextToken(); + Header header = new BasicHeader(key, value); + headers.add(header); + } + } + return headers; + } + public HttpClient getHttpClient() { return httpClient; } diff --git a/modules/apim-adapter/src/test/java/com/axway/lib/CoreCLIOptionsTest.java b/modules/apim-adapter/src/test/java/com/axway/lib/CoreCLIOptionsTest.java index a2b2c2bdb..6c21bc538 100644 --- a/modules/apim-adapter/src/test/java/com/axway/lib/CoreCLIOptionsTest.java +++ b/modules/apim-adapter/src/test/java/com/axway/lib/CoreCLIOptionsTest.java @@ -126,4 +126,23 @@ public void testDisableCompressionNegative() throws AppException { Assert.assertEquals(params.isDisableCompression(), false); } + + @Test + public void testCustomHeaders() throws AppException { + String[] args = {"-customHeaders", "abc:xyz"}; + CLIOptions options = SampleCLIOptions.create(args); + CoreParameters params = (CoreParameters) options.getParams(); + System.out.println(params.getCustomHeaders()); + Assert.assertEquals(params.getCustomHeaders(), "abc:xyz"); + + } + + @Test + public void testCustomHeadersNegative() throws AppException { + String[] args = {""}; + CLIOptions options = SampleCLIOptions.create(args); + CoreParameters params = (CoreParameters) options.getParams(); + Assert.assertNull(params.getCustomHeaders()); + + } } diff --git a/modules/apim-adapter/src/test/java/com/axway/lib/EnvironmentPropertiesTest.java b/modules/apim-adapter/src/test/java/com/axway/lib/EnvironmentPropertiesTest.java index 062806166..d4d1a9b65 100644 --- a/modules/apim-adapter/src/test/java/com/axway/lib/EnvironmentPropertiesTest.java +++ b/modules/apim-adapter/src/test/java/com/axway/lib/EnvironmentPropertiesTest.java @@ -74,4 +74,14 @@ public void testEnvironmentWithOSEnvVariables() { Assert.assertEquals("http://${env.HOSTNAME}:${env.PORT.TRAFFIC}", EnvironmentProperties.resolveValueWithEnvVars("http://${env.HOSTNAME}:${env.PORT.TRAFFIC}")); Assert.assertNotNull(EnvironmentProperties.resolveValueWithEnvVars("${PATH}")); } + + @Test + public void testCustomHeader() { + String cliHome = System.getenv("AXWAY_APIM_CLI_HOME"); + if(cliHome != null) { + EnvironmentProperties properties = new EnvironmentProperties("anyOtherStage"); + Assert.assertEquals(properties.get("headers"), "cf-token:xyz123"); + } + } + } diff --git a/modules/apim-adapter/src/test/java/com/axway/lib/utils/rest/APIMHttpClientTest.java b/modules/apim-adapter/src/test/java/com/axway/lib/utils/rest/APIMHttpClientTest.java new file mode 100644 index 000000000..316bcde55 --- /dev/null +++ b/modules/apim-adapter/src/test/java/com/axway/lib/utils/rest/APIMHttpClientTest.java @@ -0,0 +1,41 @@ +package com.axway.lib.utils.rest; + +import com.axway.apim.WiremockWrapper; +import com.axway.apim.lib.StandardImportParams; +import com.axway.apim.lib.error.AppException; +import com.axway.apim.lib.utils.rest.APIMHttpClient; +import org.apache.http.Header; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.List; + +public class APIMHttpClientTest extends WiremockWrapper { + + @BeforeClass + public void initWiremock() { + super.initWiremock(); + } + + @AfterClass + public void close() { + super.close(); + } + + @Test + public void splitStringToHttpHeaders() throws AppException { + StandardImportParams coreParameters = new StandardImportParams(); + coreParameters.setHostname("localhost"); + coreParameters.setUsername("apiadmin"); + coreParameters.setPassword(" "); + String customHeader = "cf-access-token:xyz133"; + APIMHttpClient apimHttpClient = APIMHttpClient.getInstance(); + List
headers = apimHttpClient.splitStringToHttpHeaders(customHeader); + Assert.assertEquals(headers.size(), 1); + Assert.assertEquals(headers.get(0).getName(), "cf-access-token"); + Assert.assertEquals(headers.get(0).getValue(), "xyz133"); + + } +} diff --git a/modules/apis/src/main/java/com/axway/apim/APIImportApp.java b/modules/apis/src/main/java/com/axway/apim/APIImportApp.java index bf90f3c31..7450d63ca 100644 --- a/modules/apis/src/main/java/com/axway/apim/APIImportApp.java +++ b/modules/apis/src/main/java/com/axway/apim/APIImportApp.java @@ -67,7 +67,9 @@ public int importAPI(APIImportParams params) { List filters = new ArrayList<>(); // If we don't have an AdminAccount available, we ignore published APIs - For OrgAdmins // the unpublished or pending APIs become the actual API - if (!APIManagerAdapter.getInstance().hasAdminAccount()) { + boolean isAdminAccount = APIManagerAdapter.getInstance().hasAdminAccount(); + boolean orgAdminSelfService = APIManagerAdapter.getInstance().getConfigAdapter().getConfig(isAdminAccount).getOadminSelfServiceEnabled(); + if (!isAdminAccount && !orgAdminSelfService) { filters.add(new BasicNameValuePair("field", "state")); filters.add(new BasicNameValuePair("op", "ne")); filters.add(new BasicNameValuePair("value", "published")); diff --git a/modules/apis/src/main/java/com/axway/apim/api/export/lib/params/APIUpgradeAccessParams.java b/modules/apis/src/main/java/com/axway/apim/api/export/lib/params/APIUpgradeAccessParams.java index e6d60283b..68253504f 100644 --- a/modules/apis/src/main/java/com/axway/apim/api/export/lib/params/APIUpgradeAccessParams.java +++ b/modules/apis/src/main/java/com/axway/apim/api/export/lib/params/APIUpgradeAccessParams.java @@ -8,83 +8,99 @@ import com.axway.apim.lib.utils.Utils; public class APIUpgradeAccessParams extends APIExportParams implements Parameters, APIFilterParams { - - private String referenceAPIId; - private String referenceAPIName; - private String referenceAPIVersion; - private String referenceAPIOrganization; - - private Boolean referenceAPIDeprecate = false; - private Boolean referenceAPIRetire = false; - private Long referenceAPIRetirementDate; - - private API referenceAPI; - - public API getReferenceAPI() { - return referenceAPI; - } - public void setReferenceAPI(API referenceAPI) { - this.referenceAPI = referenceAPI; - } - public Boolean getReferenceAPIDeprecate() { - return referenceAPIDeprecate; - } - public void setReferenceAPIDeprecate(Boolean referenceAPIDeprecate) { - this.referenceAPIDeprecate = referenceAPIDeprecate; - } - public Boolean getReferenceAPIRetire() { - return referenceAPIRetire; - } - public void setReferenceAPIRetire(Boolean referenceAPIRetire) { - this.referenceAPIRetire = referenceAPIRetire; - } - public Long getReferenceAPIRetirementDate() { - return referenceAPIRetirementDate; - } - public void setReferenceAPIRetirementDate(String referenceAPIRetirementDate) throws AppException { - if(referenceAPIRetirementDate == null) return; - this.referenceAPIRetirementDate = Utils.getParsedDate(referenceAPIRetirementDate); - } - public String getReferenceAPIId() { - return referenceAPIId; - } - public void setReferenceAPIId(String referenceAPIId) { - this.referenceAPIId = referenceAPIId; - } - public String getReferenceAPIName() { - return referenceAPIName; - } - public void setReferenceAPIName(String referenceAPIName) { - this.referenceAPIName = referenceAPIName; - } - public String getReferenceAPIVersion() { - return referenceAPIVersion; - } - public void setReferenceAPIVersion(String referenceAPIVersion) { - this.referenceAPIVersion = referenceAPIVersion; - } - public String getReferenceAPIOrganization() { - return referenceAPIOrganization; - } - public void setReferenceAPIOrganization(String referenceAPIOrganization) { - this.referenceAPIOrganization = referenceAPIOrganization; - } - - public APIFilter getReferenceAPIFilter() { - return new APIFilter.Builder() - .hasApiId(getReferenceAPIId()) - .hasApiPath(getApiPath()) - .hasName(getReferenceAPIName()) - .hasVHost(getReferenceAPIVersion()) - .hasOrganization(getReferenceAPIOrganization()) - .hasState(API.STATE_PUBLISHED) - .build(); - } - @Override - public void validateRequiredParameters() throws AppException { - super.validateRequiredParameters(); - if(getReferenceAPIRetire()!=null && getReferenceAPIRetirementDate()==null) { - throw new AppException("If API should be retired, a retirement date is required.", ErrorCode.MISSING_PARAMETER); - } - } + + private String referenceAPIId; + private String referenceAPIName; + private String referenceAPIVersion; + private String referenceAPIOrganization; + + private Boolean referenceAPIDeprecate = false; + private Boolean referenceAPIRetire = false; + private Long referenceAPIRetirementDate; + + private API referenceAPI; + + public API getReferenceAPI() { + return referenceAPI; + } + + public void setReferenceAPI(API referenceAPI) { + this.referenceAPI = referenceAPI; + } + + public Boolean getReferenceAPIDeprecate() { + return referenceAPIDeprecate; + } + + public void setReferenceAPIDeprecate(Boolean referenceAPIDeprecate) { + this.referenceAPIDeprecate = referenceAPIDeprecate; + } + + public Boolean getReferenceAPIRetire() { + return referenceAPIRetire; + } + + public void setReferenceAPIRetire(Boolean referenceAPIRetire) { + this.referenceAPIRetire = referenceAPIRetire; + } + + public Long getReferenceAPIRetirementDate() { + return referenceAPIRetirementDate; + } + + public void setReferenceAPIRetirementDate(String referenceAPIRetirementDate) throws AppException { + if (referenceAPIRetirementDate == null) return; + this.referenceAPIRetirementDate = Utils.getParsedDate(referenceAPIRetirementDate); + } + + public String getReferenceAPIId() { + return referenceAPIId; + } + + public void setReferenceAPIId(String referenceAPIId) { + this.referenceAPIId = referenceAPIId; + } + + public String getReferenceAPIName() { + return referenceAPIName; + } + + public void setReferenceAPIName(String referenceAPIName) { + this.referenceAPIName = referenceAPIName; + } + + public String getReferenceAPIVersion() { + return referenceAPIVersion; + } + + public void setReferenceAPIVersion(String referenceAPIVersion) { + this.referenceAPIVersion = referenceAPIVersion; + } + + public String getReferenceAPIOrganization() { + return referenceAPIOrganization; + } + + public void setReferenceAPIOrganization(String referenceAPIOrganization) { + this.referenceAPIOrganization = referenceAPIOrganization; + } + + public APIFilter getReferenceAPIFilter() { + return new APIFilter.Builder() + .hasApiId(getReferenceAPIId()) + .hasApiPath(getApiPath()) + .hasName(getReferenceAPIName()) + .hasVHost(getReferenceAPIVersion()) + .hasOrganization(getReferenceAPIOrganization()) + .hasState(API.STATE_PUBLISHED) + .build(); + } + + @Override + public void validateRequiredParameters() throws AppException { + super.validateRequiredParameters(); + if (getReferenceAPIRetire() != null && getReferenceAPIRetirementDate() == null) { + throw new AppException("If API should be retired, a retirement date is required.", ErrorCode.MISSING_PARAMETER); + } + } } diff --git a/modules/apis/src/test/resources/env.anyOtherStage.properties b/modules/apis/src/test/resources/env.anyOtherStage.properties index a5a334516..26dee40e5 100644 --- a/modules/apis/src/test/resources/env.anyOtherStage.properties +++ b/modules/apis/src/test/resources/env.anyOtherStage.properties @@ -3,4 +3,5 @@ password=anyOtherPassword thisKeyExists=HellImHere -OS_MAIN_AND_STAGE_ENV_PROPERTY=valueFromAnyOtherStageEnv \ No newline at end of file +OS_MAIN_AND_STAGE_ENV_PROPERTY=valueFromAnyOtherStageEnv +headers=cf-token:xyz123