diff --git a/.github/daemon-default.json b/.github/daemon-default.json deleted file mode 100644 index d226ade7e..000000000 --- a/.github/daemon-default.json +++ /dev/null @@ -1 +0,0 @@ -{"insecure-registries": ["docker-registry.demo.axway.com"], "debug": true} diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index b63be69c0..408dc1b99 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -8,10 +8,10 @@ env: CACHE_FILE_APIM: api-manager_7_7_20240530.cache.tar CACHE_FILE_CASSANDRA: cassandra_4_0_13.cache.tar FED_FILE: swagger-promote-7.7-20240530.fed - LOG_LEVEL: info + LOG_LEVEL: debug jobs: - build: + integration-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -58,9 +58,9 @@ jobs: run: | mkdir licenses echo ${{ secrets.APIM_LIC }} | base64 -di > licenses/apim.lic - docker-compose run --rm start_cassandra - docker-compose run --rm start_apimgmt - docker-compose logs --tail 30 apimgmt + docker compose run --rm start_cassandra + docker compose run --rm start_apimgmt + docker compose logs --tail 30 apimgmt - name: Maven APIM Integration Test run: mvn verify -P integration-tests diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9878338ce..000000000 --- a/.travis.yml +++ /dev/null @@ -1,57 +0,0 @@ -language: java -# Run integration tests only, as Unit-Tests ran before installation of the API-Manager test instance -script: "mvn verify -P integration-tests" - -services: - - docker - -env: - global: - - CACHE_DIR=$HOME/docker - - APIM_DOCKER_IMAGE=docker-registry.demo.axway.com/swagger-promote/api-mgr-with-policies:7.7-20220830 - - CASSANDRA_DOCKER_IMAGE=cassandra:2.2.12 - - CACHE_FILE_APIM=$CACHE_DIR/api-manager_7_7_20220830.cache.tar.gz - - CACHE_FILE_CASSANDRA=$CACHE_DIR/cassandra_2_2_12.cache.tar.gz - - CACHE_FILE_WAIT_FOR_DEPENDENCIES=$CACHE_DIR/wait-for-dependencies.cache.tar.gz - - counter=0 - # Variable to test the OS-Environment variable replace - - OS=TravisCI - -cache: - directories: - - $CACHE_DIR - - '$HOME/.m2/repository' - -before_install: - # Avoid installation if unit-tests fail anyway - - mvn clean test - - - if [ ! -f /etc/docker/daemon.json ]; then sudo cp -v .github/daemon-default.json /etc/docker/daemon.json; fi - - if [ ! -f $CACHE_FILE_APIM ]; then sudo cat /etc/default/docker; fi - - if [ ! -f $CACHE_FILE_APIM ]; then echo \"Restarting Docker-Daemon\"; sudo service docker restart; sudo systemctl status docker.service; sudo journalctl -xe; fi - - #- sudo apt-get update - #- sudo apt-get install curl - # All files in this folder will be cached for the next build - - mkdir -p $CACHE_DIR - # Downloading the APIM-Docker-Image takes too long (Timeout 10 minutes) - Externalized to make use of travis_wait - # In this script, we are either using the cached version or download a new Docker-Image - - travis_wait build/pull_apim_docker_image.sh - # Now it's time to safe the downloaded API-Management Docker-Image into the cache folder - - if [ ! -f $CACHE_FILE_APIM ]; then docker save $APIM_DOCKER_IMAGE | gzip > $CACHE_FILE_APIM; fi - # Pull Cassandra Image or use the cache - - travis_wait build/pull_cassandra_docker_image.sh - # Safe Cassandra image inc cache file - - if [ ! -f $CACHE_FILE_CASSANDRA ]; then docker save $CASSANDRA_DOCKER_IMAGE | gzip > $CACHE_FILE_CASSANDRA; fi - # Pull wait-for-dependencies or use the cache - - travis_wait build/pull_wait_for_dependencies.sh - # Wait dadarek/wait-for-dependencies to avoid docker pull limit - - if [ ! -f $CACHE_FILE_WAIT_FOR_DEPENDENCIES ]; then docker save dadarek/wait-for-dependencies | gzip > $CACHE_FILE_WAIT_FOR_DEPENDENCIES; fi - -install: - # Start Cassandra and wait that port 9042 is reachable - - docker-compose run --rm start_cassandra - # Start the API-Gateway + API-Manager - - docker-compose run --rm start_apimgmt - # Give API-Manager a moment to start - - docker-compose logs --tail 30 apimgmt diff --git a/CHANGELOG.md b/CHANGELOG.md index 2019ba61f..bfb83fd75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ 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.6] In progress +## 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)) +- -returnCodeMapping option does not work on apim-cli org import (See issue [#496](https://github.com/Axway-API-Management-Plus/apim-cli/issues/496)) +- The output of command 'apim api get' is not containing the complete list of client applications (array) of the api (See issue [#495](https://github.com/Axway-API-Management-Plus/apim-cli/issues/495)) +- Update API with Assigned Quota (See issue [#499](https://github.com/Axway-API-Management-Plus/apim-cli/issues/499)) + +### Added +- Force APIM-cli to download the latest Trusted Certificates in a Frontend API (See issue [#494](https://github.com/Axway-API-Management-Plus/apim-cli/issues/494)) + +### Changed +- Updated libs to fix security vulnerabilities + - com.graphql-java:graphql-java from 21.3 to 21.5 + - commons-io:commons-io from 2.11.0 to 2.14.0 + + # [1.14.5] 2024-07-12 ## Fixed diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index dfa8485bd..63b071eac 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -19,50 +19,11 @@ are ready for the next version. This means that the develop branch is actually s - GnuPG for Code-Signing (e.g. https://gnupg.org/) - Apache Maven 3.6.3 or higher -#### Maven settings.xml +### Maven pgp usage +- https://maven.apache.org/plugins/maven-gpg-plugin/usage.html -A server configuration for GitHub write access by Maven using your personal access token. -```xml - - github - cwiechmann@axway.com - YOUR_GITHUB_PAT - -``` -The Code must be signed to be published to Maven-Central. A Signing-Key must be created and published: -Learn more: https://central.sonatype.org/publish/requirements/gpg/ - -Confguration required for the Sonatype communication: -Learn more: https://github.com/chhh/sonatype-ossrh-parent/blob/master/publishing-to-maven-central.md - -A profile Sonatype servers used by Sonatype maven plugin. - -```xml - - ossrh - YOUR_OSSRH_USERNAME - YOUR_OSSRH_PASSWORD - -``` - -A profile for GPG which is used by the `maven-gpg-plugin` plugin. - -```xml - - ossrh - - true - - - gpg - axway - - -``` -Learn more: https://maven.apache.org/plugins/maven-gpg-plugin/usage.html - -### Create a new release +## Create a new release For the release, develop is merged into Master and the release is generated on Master with Maven. @@ -85,47 +46,12 @@ git commit git push ``` -### 4. Create Pre-Release with Maven +### 4. Create Release with Maven -```sh -mvn -Darguments=-DskipTests release:prepare -P release - -# Set the version number following [Semantic Versioning](https://semver.org/) -# Git-Label version should be for example: 1.11.0 -# Next SNAPSHOT Version: 1.12.0-SNAPSHOT -``` - -### 5. Validate the Pre-Release - -- Use the Pre-Release to manually perform some smoke tests -`apim-cli\distribution\target` - - If you are not happy with the actual build for any reason, you need to rollback the actual release prepare: - ```sh - mvn release:rollback - # Sometimes the created tag isn't removed automatically. You need to delete it to re-execute release:prepare: - git tag -d 1.11.0 - git push origin :refs/tags/1.11.0 - ``` - -### 6. Create the release - -```sh -# This uploads the release artifacts to Maven-Central automatically -mvn -Darguments=-DskipTests release:perform -P release -``` - -### 7. Create a release on GitHub +- Run Github action Release API CLI on github and Maven repository -- Select the tag created by Maven -- Use the description from the previous release and modify it -- It also pushes the Chocolately package -- upload the created release files to GitHub: - ``` - target/checkout/distribution/target/axway-apimcli-1.11.0.zip - target/checkout/distribution/target/axway-apimcli-1.11.0.tar.gz - ``` -### 8. Commit all changes and merge master into develop +### 5. Commit all changes and merge master into develop ``` git checkout develop git merge master diff --git a/ROTATE_PGP_KEY.md b/ROTATE_PGP_KEY.md new file mode 100644 index 000000000..5448c3e60 --- /dev/null +++ b/ROTATE_PGP_KEY.md @@ -0,0 +1,43 @@ +# Rotate PGP Keys. + +PGP key comes with expiry date. + + +## Create new key + +```bash +➜ apim-cli git:(master) gpg --gen-key +gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + +Note: Use "gpg --full-generate-key" for a full featured key generation dialog. + +GnuPG needs to construct a user ID to identify your key. + +Real name: Rathna +Email address: rathnapandi.n@gmail.com +You selected this USER-ID: + "Rathna " + +Change (N)ame, (E)mail, or (O)kay/(Q)uit? O +``` + +## Push the key to Key server + +Use the pgp id to upload it key server + +```bash + gpg --keyserver keyserver.ubuntu.com --send-keys 5D8F776E941F2D1D91EB2875212961A21019826F +``` + +## Store the key password and private key to Github action secrets and variables. + +- Secret names + - GPG_PASSPHRASE + - GPG_PRIVATE_KEY + +### Export private key +```bash +gpg --output private.pgp --armor --export-secret-key 5D8F776E941F2D1D91EB2875212961A21019826F +``` diff --git a/build/base_apim_setup.sh b/build/base_apim_setup.sh deleted file mode 100755 index 2f2382bb7..000000000 --- a/build/base_apim_setup.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -# Create an API-Development Organisation! -curl --insecure -u apiadmin:changeme -X POST \ - https://localhost:8075/api/portal/v1.3/organizations \ - -H 'Content-Type: application/json' \ - -d '{ - "name": "API Development", - "description": "Test Org", - "enabled": true, - "development": true -}' -echo "Created organization: 'API Development'" \ No newline at end of file diff --git a/build/pull_apim_docker_image.sh b/build/pull_apim_docker_image.sh deleted file mode 100755 index 224549ca5..000000000 --- a/build/pull_apim_docker_image.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -echo "CACHE_FILE_APIM: $CACHE_FILE_APIM" -echo "SKIP_CACHE: $SKIP_CACHE" - -echo "Listing $CACHE_DIR" -ls -l $CACHE_DIR - -if [ -f $CACHE_FILE_APIM -a "$SKIP_CACHE" != "true" ] -then - echo "Using cached API-Manager docker image: $APIM_DOCKER_IMAGE from $CACHE_FILE_APIM" - gunzip -c $CACHE_FILE_APIM | docker load -else - echo "Pulling APIM docker from registry, this will take a while" - docker login --username $AXWAY_DOCKER_REG_USER --password $AXWAY_DOCKER_REG_PASS docker-registry.demo.axway.com - docker pull $APIM_DOCKER_IMAGE -fi diff --git a/build/pull_cassandra_docker_image.sh b/build/pull_cassandra_docker_image.sh deleted file mode 100755 index 72bbba9c2..000000000 --- a/build/pull_cassandra_docker_image.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -if [ -f $CACHE_FILE_CASSANDRA ] -then - echo "Loading docker image: $CASSANDRA_DOCKER_IMAGE from $CACHE_FILE_CASSANDRA" - gunzip -c $CACHE_FILE_CASSANDRA | docker load -else - echo "Pulling CASSANDRA docker from registry, this will take a while" - docker login -u $DOCKER_HUB_USER -p $DOCKER_HUB_PASS - docker pull $CASSANDRA_DOCKER_IMAGE -fi - - diff --git a/build/pull_wait_for_dependencies.sh b/build/pull_wait_for_dependencies.sh deleted file mode 100755 index cf932c62d..000000000 --- a/build/pull_wait_for_dependencies.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -if [ -f $CACHE_FILE_WAIT_FOR_DEPENDENCIES ] -then - echo "Loading docker image: dadarek/wait-for-dependencies from $CACHE_FILE_WAIT_FOR_DEPENDENCIES" - gunzip -c $CACHE_FILE_WAIT_FOR_DEPENDENCIES | docker load -else - echo "Pulling dadarek/wait-for-dependencies docker from Docker-Hub" - docker login -u $DOCKER_HUB_USER -p $DOCKER_HUB_PASS - docker pull dadarek/wait-for-dependencies -fi - - diff --git a/distribution/pom.xml b/distribution/pom.xml index b2efa7cd3..985476191 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -12,7 +12,6 @@ distribution pom Distribution - com.github.axway-api-management-plus.apim-cli @@ -52,6 +51,7 @@ + axway-apimcli-1.14.5.1-SNAPSHOT maven-assembly-plugin diff --git a/docker-compose.yml b/docker-compose.yml index 9b8efab20..c09c214c8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,13 +2,14 @@ version: "2" services: cassandra: + # image: cassandra:4.0.13 image: ${CASSANDRA_DOCKER_IMAGE} ports: - 9042:9042 # Cassandra listen socket hostname: cassandra apimgmt: - # image: docker-registry.demo.axway.com/swagger-promote/api-mgr-with-policies:7.7 + # image: docker.repository.axway.com/apigateway-docker-prod/7.7/gateway:7.7.0.20240530-2-BN0004-ubi9 image: ${APIM_DOCKER_IMAGE} volumes: - ${GITHUB_WORKSPACE}/licenses:/opt/Axway/apigateway/conf/licenses diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIFilter.java b/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIFilter.java index 931ceca63..dabc79e0b 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIFilter.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIFilter.java @@ -200,12 +200,9 @@ public void setApiPath(String apiPath) { op = "like"; apiPath = apiPath.replace("*", ""); } - // Only from version 7.7 on we can query for the path directly. - if (APIManagerAdapter.hasAPIManagerVersion("7.7")) { - filters.add(new BasicNameValuePair(FIELD, "path")); - filters.add(new BasicNameValuePair(OP, op)); - filters.add(new BasicNameValuePair(VALUE, apiPath)); - } + filters.add(new BasicNameValuePair(FIELD, "path")); + filters.add(new BasicNameValuePair(OP, op)); + filters.add(new BasicNameValuePair(VALUE, apiPath)); } public String getQueryStringVersion() { diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIAdapter.java b/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIAdapter.java index 23ae4eb81..05cd7b57b 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIAdapter.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIAdapter.java @@ -417,7 +417,7 @@ public void translateMethodIdsToName(APIQuota apiQuota, String apiId) throws App APIManagerAPIMethodAdapter methodAdapter = APIManagerAdapter.getInstance().getMethodAdapter(); List quotaRestrictions = apiQuota.getRestrictions(); for (QuotaRestriction quotaRestriction : quotaRestrictions) { - APIMethod apiMethod = methodAdapter.getMethodForId(apiId, quotaRestriction.getApiId()); + APIMethod apiMethod = methodAdapter.getMethodForId(apiId, quotaRestriction.getMethod()); if (apiMethod != null) quotaRestriction.setMethod(apiMethod.getName()); } @@ -605,7 +605,7 @@ public API updateAPIProxy(API api) throws AppException { } } - private String[] getSerializeAllExcept() throws AppException { + public String[] getSerializeAllExcept() throws AppException { String[] serializeAllExcept; // queryStringPassThrough added in inboundProfiles on API manager version 7.7.20220530 if (queryStringPassThroughBreakingVersion.contains(APIManagerAdapter.getInstance().getApiManagerVersion())) { diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIMethodAdapter.java b/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIMethodAdapter.java index 69a8dce7a..4c9b300b9 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIMethodAdapter.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIMethodAdapter.java @@ -83,6 +83,8 @@ public APIMethod getMethodForName(String apiId, String methodName) throws AppExc } public APIMethod getMethodForId(String apiId, String methodId) throws AppException { + if(methodId.equals("*")) + return null; List apiMethods = getAllMethodsForAPI(apiId); if (apiMethods.isEmpty()) { LOG.warn("No operations found for API with id: {}", apiId); diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/adapter/jackson/QuotaRestrictionSerializer.java b/modules/apim-adapter/src/main/java/com/axway/apim/adapter/jackson/QuotaRestrictionSerializer.java index 6c7a19697..8697db642 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/adapter/jackson/QuotaRestrictionSerializer.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/adapter/jackson/QuotaRestrictionSerializer.java @@ -15,42 +15,42 @@ public class QuotaRestrictionSerializer extends StdSerializer public static final String METHOD = "method"; public QuotaRestrictionSerializer() { - this(null); - } - - public QuotaRestrictionSerializer(Class t) { - super(t); - } - - @Override - public void serialize(QuotaRestriction quotaRestriction, JsonGenerator jgen, SerializerProvider provider) throws IOException { - jgen.writeStartObject(); - if(quotaRestriction.getRestrictedAPI()==null) { - jgen.writeObjectField("api", "*"); - jgen.writeObjectField(METHOD, "*"); - } else { // API-Specific quota - // Don't write the API-Name as it's confusing it is ignored during import when the API-Path is given. - jgen.writeObjectField("apiPath", quotaRestriction.getRestrictedAPI().getPath()); - if(quotaRestriction.getRestrictedAPI().getVhost()!=null) { - jgen.writeObjectField("vhost", quotaRestriction.getRestrictedAPI().getVhost()); - } - if(quotaRestriction.getRestrictedAPI().getApiRoutingKey()!=null) { - jgen.writeObjectField("apiRoutingKey", quotaRestriction.getRestrictedAPI().getApiRoutingKey()); - } - if(quotaRestriction.getMethod()==null || "*".equals(quotaRestriction.getMethod())) { - jgen.writeObjectField(METHOD, "*"); - } else { - APIMethod method = APIManagerAdapter.getInstance().getMethodAdapter().getMethodForId(quotaRestriction.getApiId(), quotaRestriction.getMethod()); - jgen.writeObjectField(METHOD, method.getName()); - } - } - jgen.writePOJOField("type",quotaRestriction.getType()); - jgen.writePOJOField("config",quotaRestriction.getConfig()); - jgen.writeEndObject(); - } - - @Override - public Class handledType() { - return QuotaRestriction.class; - } + this(null); + } + + public QuotaRestrictionSerializer(Class t) { + super(t); + } + + @Override + public void serialize(QuotaRestriction quotaRestriction, JsonGenerator jgen, SerializerProvider provider) throws IOException { + jgen.writeStartObject(); + if (quotaRestriction.getRestrictedAPI() == null) { + jgen.writeObjectField("api", "*"); + jgen.writeObjectField(METHOD, "*"); + } else { // API-Specific quota + // Don't write the API-Name as it's confusing it is ignored during import when the API-Path is given. + jgen.writeObjectField("apiPath", quotaRestriction.getRestrictedAPI().getPath()); + if (quotaRestriction.getRestrictedAPI().getVhost() != null) { + jgen.writeObjectField("vhost", quotaRestriction.getRestrictedAPI().getVhost()); + } + if (quotaRestriction.getRestrictedAPI().getApiRoutingKey() != null) { + jgen.writeObjectField("apiRoutingKey", quotaRestriction.getRestrictedAPI().getApiRoutingKey()); + } + if (quotaRestriction.getMethod() == null || "*".equals(quotaRestriction.getMethod())) { + jgen.writeObjectField(METHOD, "*"); + } else { + APIMethod method = APIManagerAdapter.getInstance().getMethodAdapter().getMethodForId(quotaRestriction.getApiId(), quotaRestriction.getMethod()); + jgen.writeObjectField(METHOD, method.getName()); + } + } + jgen.writePOJOField("type", quotaRestriction.getType()); + jgen.writePOJOField("config", quotaRestriction.getConfig()); + jgen.writeEndObject(); + } + + @Override + public Class handledType() { + return QuotaRestriction.class; + } } diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/WADLSpecification.java b/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/WADLSpecification.java index fc1505a5e..7940462f9 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/WADLSpecification.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/WADLSpecification.java @@ -1,6 +1,7 @@ package com.axway.apim.api.specification; import com.axway.apim.api.API; +import com.axway.apim.lib.CoreParameters; import com.axway.apim.lib.error.AppException; import com.axway.apim.lib.error.ErrorCode; import com.axway.apim.lib.utils.Utils; @@ -33,6 +34,7 @@ public void updateBasePath(String basePath, String host) { @Override public void configureBasePath(String backendBasePath, API api) throws AppException { try { + CoreParameters.getInstance().setOverrideSpecBasePath(false); // Not allowing override base path for WADL, hence changing it to false. if (backendBasePath != null) { URL url = new URL(backendBasePath); // Parse it to make sure it is valid if (url.getPath() != null && !url.getPath().isEmpty() && !backendBasePath.endsWith("/")) { // See issue #178 diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/WSDLSpecification.java b/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/WSDLSpecification.java index 3bdab49e9..faa55b40f 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/WSDLSpecification.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/WSDLSpecification.java @@ -2,6 +2,7 @@ import com.axway.apim.api.API; import com.axway.apim.api.model.ServiceProfile; +import com.axway.apim.lib.CoreParameters; import com.axway.apim.lib.error.AppException; import com.axway.apim.lib.utils.Utils; import org.slf4j.Logger; @@ -61,6 +62,7 @@ public boolean parse(byte[] apiSpecificationContent) throws AppException { return true; } try { + CoreParameters.getInstance().setOverrideSpecBasePath(false); // Not allowing override base path for WSDL, hence changing it to false. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); // to be compliant, completely disable DOCTYPE declaration: diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/lib/EnvironmentProperties.java b/modules/apim-adapter/src/main/java/com/axway/apim/lib/EnvironmentProperties.java index e7a649260..ac34495cf 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/lib/EnvironmentProperties.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/lib/EnvironmentProperties.java @@ -22,6 +22,7 @@ public class EnvironmentProperties implements Map { public static final String FALSE = "false"; public static final boolean RETAIN_BACKEND_URL = Boolean.parseBoolean(System.getenv().getOrDefault("retain.backend.url", FALSE)); public static final boolean PRINT_CONFIG_CONSOLE = Boolean.parseBoolean(System.getenv().getOrDefault("print_console", FALSE)); + public static final boolean OVERRIDE_CERTIFICATES = Boolean.parseBoolean(System.getenv().getOrDefault("override_certificates", FALSE)); public static final boolean CHECK_CATALOG = Boolean.parseBoolean(System.getenv().getOrDefault("check_catalog", FALSE)); private static final Logger LOG = LoggerFactory.getLogger(EnvironmentProperties.class); diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/lib/error/ErrorCode.java b/modules/apim-adapter/src/main/java/com/axway/apim/lib/error/ErrorCode.java index af3d8f1ba..6c51cb875 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/lib/error/ErrorCode.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/lib/error/ErrorCode.java @@ -11,7 +11,7 @@ public enum ErrorCode { MISSING_PARAMETER(5, "There is a missing parameter.", false), INVALID_PARAMETER(6, "There is an invalid parameter.", false), API_ALREADY_EXISTS(7, "The API already exists for another organization.", false), - BACKEND_API_DEF_NA(8, "The API already exists for another organization.", false), + BACKEND_API_DEF_NA(8, "Backend API definition is not available.", false), NO_CHANGE(10, "No change between desired and actual API has been detected.", false, LogLevel.WARN), EXPORT_FOLDER_EXISTS(12, "Export failed Export-Folder already exists.", false), UPDATE_ONLY_IS_SET(13, "Creating of a new API fails, when flag updateOnly is set.", false), diff --git a/modules/apim-adapter/src/test/java/com/axway/apim/adapter/apis/APIManagerAPIAdapterTest.java b/modules/apim-adapter/src/test/java/com/axway/apim/adapter/apis/APIManagerAPIAdapterTest.java index 72531374b..7f7d454e3 100644 --- a/modules/apim-adapter/src/test/java/com/axway/apim/adapter/apis/APIManagerAPIAdapterTest.java +++ b/modules/apim-adapter/src/test/java/com/axway/apim/adapter/apis/APIManagerAPIAdapterTest.java @@ -3,6 +3,7 @@ import com.axway.apim.WiremockWrapper; import com.axway.apim.adapter.APIManagerAdapter; import com.axway.apim.adapter.client.apps.ClientAppFilter; +import com.axway.apim.adapter.jackson.QuotaRestrictionDeserializer; import com.axway.apim.api.API; import com.axway.apim.api.model.*; import com.axway.apim.api.model.apps.ClientApplication; @@ -11,7 +12,15 @@ import com.axway.apim.lib.CoreParameters; import com.axway.apim.lib.error.AppException; import com.axway.apim.lib.utils.Utils; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.FilterProvider; +import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -786,4 +795,28 @@ public boolean parse(byte[] apiSpecificationContent) throws AppException { } + @Test + public void updateAPIProxyWithBasicAuthEmptyPassword() throws IOException { + String testConfig = this.getClass().getResource("/com/axway/apim/adapter/conf/outbound_basic_auth_empty_password.json").getPath(); + File file = new File(testConfig); + ObjectMapper mapper = Utils.createObjectMapper(new File(testConfig)); + SimpleModule module = new SimpleModule(); + module.addDeserializer(QuotaRestriction.class, new QuotaRestrictionDeserializer(QuotaRestrictionDeserializer.DeserializeMode.configFile, false)); + // We would like to get back the original AppExcepption instead of a JsonMappingException + mapper.disable(DeserializationFeature.WRAP_EXCEPTIONS); + mapper.registerModule(module); + ObjectReader reader = mapper.reader(); + API baseConfig = reader.forType(API.class).readValue(file); + System.out.println(baseConfig.getAuthenticationProfiles()); + + ObjectMapper objectMapper = new ObjectMapper(); + String[] serializeAllExcept = apiManagerAPIAdapter.getSerializeAllExcept(); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + FilterProvider filter = new SimpleFilterProvider().setDefaultFilter( + SimpleBeanPropertyFilter.serializeAllExcept(serializeAllExcept)); + objectMapper.setFilterProvider(filter); + + System.out.println(objectMapper.writeValueAsString(baseConfig)); + } + } diff --git a/modules/apim-adapter/src/test/java/com/axway/apim/api/model/AuthenticationProfileTest.java b/modules/apim-adapter/src/test/java/com/axway/apim/api/model/AuthenticationProfileTest.java index e4cf2fcf5..ce2e4f6df 100644 --- a/modules/apim-adapter/src/test/java/com/axway/apim/api/model/AuthenticationProfileTest.java +++ b/modules/apim-adapter/src/test/java/com/axway/apim/api/model/AuthenticationProfileTest.java @@ -1,6 +1,9 @@ package com.axway.apim.api.model; import com.axway.apim.lib.utils.Utils; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.testng.Assert; import org.testng.annotations.Test; @@ -173,6 +176,24 @@ public void compareBasicAuthProfilesWithDifferentPassword(){ Assert.assertNotEquals(authenticationProfileFromGateway, authenticationProfile); } + @Test + public void checkBasicAuthProfilesWithEmptyPassword() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + String authProfile = "{\n" + + " \"name\":\"HTTP Basic Auth\",\n" + + " \"parameters\":{\n" + + " \"username\":\"usernameabc\",\n" + + " \"password\":\"\"\n" + + " },\n" + + " \"type\":\"http_basic\"\n" + + " }"; + AuthenticationProfile authenticationProfile = mapper.readValue(authProfile, AuthenticationProfile.class); + Assert.assertTrue(authenticationProfile.getParameters().get("password").equals("")); + } + + @Test public void compareBasicAuthProfilesWithSamePassword(){ AuthenticationProfile authenticationProfile = new AuthenticationProfile(); diff --git a/modules/apim-adapter/src/test/resources/apimanager/README.md b/modules/apim-adapter/src/test/resources/apimanager/README.md index 01692efc0..c3a5b4336 100644 --- a/modules/apim-adapter/src/test/resources/apimanager/README.md +++ b/modules/apim-adapter/src/test/resources/apimanager/README.md @@ -1,45 +1,62 @@ # Not used - Migrated to official docker image # Purpose The project is using Integration-Tests to simulate tasks the API-Developer is doing. That means, creating the API for the first time, doing frequent changes, subscribe with applications, etc. -For that TravisCI is using, which is starting an API-Manager V7.x Docker-Container to perform these integration tests. This document describes the steps needed to build the Docker-Image. +For that Github Action is using, which is starting an API-Manager V7.x Docker-Container to perform these integration tests. This document describes the steps needed to build the Docker-Image. ## Steps -Download the API-Gateway/API-Manager release from support.axway.com you want to test with and have the following ready: -- APIGateway_x.x.x_xxx_Install_linux-x86-64_BNxxxxxx.run -- APIGateway_x.x.x-x_ScriptsPackageDocker_linux-x86-64_BNxxxxxxx.tar.gz -- a license without hostname binding -Copy everything to a system having docker installed. -Perform the following steps: -``` - cd $HOME - git clone https://github.com/Axway-API-Management-Plus/apim-cli.git - mkdir apim-cli-dockerimage - cp APIGateway_x.x.x_xxx_Install_linux-x86-64_BNxxxxxx.run apim-cli-dockerimage - cp APIGateway_7.7.20200130-1_DockerScripts.tar.gz apim-cli-dockerimage - cp multiple.lic apim-cli-dockerimage - $HOME/apim-cli/modules/apim-adapter/src/test/resources/apimanager/buildDockerImage.sh 7.7-20200930 +Integration test Github action uses APIM V7 docker image to run the integration tests. +- Update latest docker image with tag +- Update supported Cassandra version +- Update the docker cahes + +Github workflow file integration-test.yaml + +```yaml + name: APIM CLI Integration Tests + + on: [push] + + env: + CASSANDRA_DOCKER_IMAGE: cassandra:4.0.13 + APIM_DOCKER_IMAGE: docker.repository.axway.com/apigateway-docker-prod/7.7/gateway:7.7.0.20240530-2-BN0004-ubi9 + CACHE_FILE_APIM: api-manager_7_7_20240530.cache.tar + CACHE_FILE_CASSANDRA: cassandra_4_0_13.cache.tar + FED_FILE: swagger-promote-7.7-20240530.fed + LOG_LEVEL: info ``` -### Added Untrusted Docker-Registry + +## Update fed file to newer version. + +### Upgrade fed file + +- Run upgradeconfig CLI command to update fed file to newer version + +```bash +docker run -it -v /home/axway/apim-cli/modules/apim-adapter/src/test/resources/apimanager:/opt/Axway/apiprojects docker.repository.axway.com/apigateway-docker-prod/7.7/gateway:7.7.0.20240530-1-BN0092-ubi9 /bin/sh /opt/Axway/apigateway/posix/bin/upgradeconfig -f /opt/Axway/apiprojects/swagger-promote-7.7-20240228.fed -o /opt/Axway/apiprojects/new ``` -vi /etc/docker/daemon.json + +Above command creates new folder named **new** under modules/apim-adapter/src/test/resources/apimanager and files (suffix with .fed, .pol, .env) + +- Rename fed folder +```bash +mv e4b134f7-905b-4c56-ab40-221db6c931c9.fed swagger-promote-7.7-20240530.fed ``` -Add the following -```json -{ - "insecure-registries" : ["docker-registry.demo.axway.com"] -} -systemctl restart dockerd + +- Update fed file name in workflow file integration-test.yaml +```yaml +env: + FED_FILE: swagger-promote-7.7-20240530.fed ``` -Please note, that you need Write-Permissions to the Docker-Repository to push the image! +## Update APIM license -To enable the image, please adjust the image referred in the Travis-CI configuration file: +- Create base64 encoded version of license. +```bash +base64 -i ~/Downloads/API-7.7-Docker-Temp.lic ``` -edit .github/workflows/integration-test.yml -and change: -Add/register your new Docker-Image and reference it in the following environment variables: -- DOCKER_IMAGE_TO_USE=docker-registry.demo.axway.com/swagger-promote/api-mgr-with-policies:7.7-20221130 -- CACHE_FILE_APIM=api-manager_7_7_20221130.cache.tar -``` -After checkin & commit a Github Action build is started using the provided Docker-Image. +- Copy the base64 content and update Github Secrets and Variables + +Secret name - APIM_LIC + +## Push all changes to git, it will trigger the integration test. diff --git a/modules/apim-adapter/src/test/resources/com/axway/apim/adapter/conf/outbound_basic_auth_empty_password.json b/modules/apim-adapter/src/test/resources/com/axway/apim/adapter/conf/outbound_basic_auth_empty_password.json new file mode 100644 index 000000000..2071e6536 --- /dev/null +++ b/modules/apim-adapter/src/test/resources/com/axway/apim/adapter/conf/outbound_basic_auth_empty_password.json @@ -0,0 +1,18 @@ +{ + "name": "test", + "path": "/test", + "state": "Published", + "version": "1.0.0", + "organization": "orga", + "authenticationProfiles": [ + { + "name": "_default", + "isDefault": true, + "parameters": { + "username": "daskdjaskldjaskljdklasjdl", + "password": "" + }, + "type": "http_basic" + } + ] +} diff --git a/modules/apis/src/main/java/com/axway/apim/api/export/ExportAPI.java b/modules/apis/src/main/java/com/axway/apim/api/export/ExportAPI.java index fa776d86b..1dd3bd0e7 100644 --- a/modules/apis/src/main/java/com/axway/apim/api/export/ExportAPI.java +++ b/modules/apis/src/main/java/com/axway/apim/api/export/ExportAPI.java @@ -292,10 +292,11 @@ public List getClientOrganizations() throws AppException { public List> getApplications() { if (actualAPIProxy.getApplications().isEmpty()) return Collections.emptyList(); List> exportApps = new ArrayList<>(); - Map applications = new HashMap<>(); - exportApps.add(applications); for (ClientApplication app : actualAPIProxy.getApplications()) { + Map applications = new HashMap<>(); applications.put("name", app.getName()); + applications.put("organization", app.getOrganization().getName()); + exportApps.add(applications); } return exportApps; } diff --git a/modules/apis/src/main/java/com/axway/apim/api/export/impl/ExportHelper.java b/modules/apis/src/main/java/com/axway/apim/api/export/impl/ExportHelper.java index 4f643e6f9..3d9a27b45 100644 --- a/modules/apis/src/main/java/com/axway/apim/api/export/impl/ExportHelper.java +++ b/modules/apis/src/main/java/com/axway/apim/api/export/impl/ExportHelper.java @@ -92,7 +92,6 @@ public void saveAPILocally(ExportAPI exportAPI, APIResultHandler apiResultHandle mapper.registerModule(new SimpleModule().setSerializerModifier(new APIExportSerializerModifier())); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); FilterProvider filters = new SimpleFilterProvider() .addFilter("CaCertFilter", SimpleBeanPropertyFilter.filterOutAllExcept("inbound", "outbound", "certFile")) diff --git a/modules/apis/src/main/java/com/axway/apim/apiimport/APIImportConfigAdapter.java b/modules/apis/src/main/java/com/axway/apim/apiimport/APIImportConfigAdapter.java index b341bbeb2..05a947c6f 100644 --- a/modules/apis/src/main/java/com/axway/apim/apiimport/APIImportConfigAdapter.java +++ b/modules/apis/src/main/java/com/axway/apim/apiimport/APIImportConfigAdapter.java @@ -19,7 +19,6 @@ import com.axway.apim.lib.error.AppException; import com.axway.apim.lib.error.ErrorCode; import com.axway.apim.lib.utils.Utils; -import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; @@ -96,7 +95,6 @@ public APIImportConfigAdapter(String apiConfigFileName, String stage, String pat // We would like to get back the original AppExcepption instead of a JsonMappingException mapper.disable(DeserializationFeature.WRAP_EXCEPTIONS); mapper.registerModule(module); - mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); ObjectReader reader = mapper.reader(); API baseConfig = reader.withAttribute(VALIDATE_ORGANIZATION, validateOrganization).forType(DesiredAPI.class).readValue(Utils.substituteVariables(this.apiConfigFile)); if (stageConfigFile != null) { @@ -391,7 +389,10 @@ private void completeClientApplications(API apiConfig) throws AppException { while (it.hasNext()) { app = it.next(); if (app.getName() != null) { - ClientAppFilter filter = new ClientAppFilter.Builder().hasName(app.getName()).build(); + ClientAppFilter.Builder builder = new ClientAppFilter.Builder().hasName(app.getName()); + if (app.getOrganization() != null) + builder.hasOrganizationName(app.getOrganization().getName()); + ClientAppFilter filter = builder.build(); loadedApp = APIManagerAdapter.getInstance().getAppAdapter().getApplication(filter); if (loadedApp == null) { LOG.warn("Unknown application with name: {} configured. Ignoring this application.", filter.getApplicationName()); @@ -400,7 +401,7 @@ private void completeClientApplications(API apiConfig) throws AppException { it.remove(); continue; } - LOG.info("Found existing application: {} ({}) based on given name {}", app.getName(), app.getId(), app.getName()); + LOG.info("Application exists : {} ({})]", app.getName(), app.getId()); } else if (app.getApiKey() != null) { loadedApp = getAppForCredential(app.getApiKey(), APIManagerAdapter.CREDENTIAL_TYPE_API_KEY); if (loadedApp == null) { diff --git a/modules/apis/src/main/java/com/axway/apim/apiimport/actions/APIQuotaManager.java b/modules/apis/src/main/java/com/axway/apim/apiimport/actions/APIQuotaManager.java index fd58fe95e..0e8ee2b42 100644 --- a/modules/apis/src/main/java/com/axway/apim/apiimport/actions/APIQuotaManager.java +++ b/modules/apis/src/main/java/com/axway/apim/apiimport/actions/APIQuotaManager.java @@ -43,6 +43,7 @@ public void execute(API createdAPI) throws AppException { // Handle the system quota List actualRestrictions = actualState != null ? getRestrictions(actualState.getSystemQuota()) : null; List desiredRestrictions = getRestrictions(desiredState.getSystemQuota()); + updateRestrictions(actualRestrictions, desiredRestrictions, createdAPI, Quota.SYSTEM_DEFAULT, sameAPI); // Handle the application quota actualRestrictions = actualState != null ? getRestrictions(actualState.getApplicationQuota()) : null; @@ -57,22 +58,18 @@ public void updateRestrictions(List actualRestrictions, List mergedRestrictions = addOrMergeRestriction(actualRestrictions, desiredRestrictions); + List mergedRestrictions = mergeRestriction(actualRestrictions, desiredRestrictions); + LOG.debug("Merged Quota : {}", mergedRestrictions); populateMethodId(createdAPI, mergedRestrictions); // If there is an actual API, remove the restrictions for the current actual API if (actualState != null) { @@ -83,22 +80,22 @@ public void updateRestrictions(List actualRestrictions, List addOrMergeRestriction(List existingRestrictions, List desiredRestrictions) { + public List mergeRestriction(List existingRestrictions, List desiredRestrictions) { List mergedRestrictions = new ArrayList<>(); if (existingRestrictions == null) existingRestrictions = new ArrayList<>(); - boolean existingRestrictionFound = false; if (CoreParameters.getInstance().getQuotaMode().equals(CoreParameters.Mode.replace)) { LOG.info("Removing existing Quotas for API: {} as quotaMode is set to replace.", this.actualState.getName()); } else { // Otherwise initially take over all existing restrictions for that API. mergedRestrictions.addAll(existingRestrictions); } + if (desiredRestrictions != null) { - // Iterate over the given desired restrictions + // Iterate over the given desired restrictions and copy quota for (QuotaRestriction desiredRestriction : desiredRestrictions) { desiredRestriction.setApiId(null); // And compare each desired restriction, if it is already included in the existing restrictions - for (QuotaRestriction existingRestriction : mergedRestrictions) { + for (QuotaRestriction existingRestriction : existingRestrictions) { // It's considered as the same restriction when type, method, period & per are equal if (desiredRestriction.isSameRestriction(existingRestriction, true)) { // If it is the same restriction, we need to update the restriction configuration @@ -107,17 +104,37 @@ public List addOrMergeRestriction(List exist } else { existingRestriction.getConfig().put("mb", desiredRestriction.getConfig().get("mb")); } - existingRestrictionFound = true; break; } } - // If we haven't found any existing restriction add a new desired restriction - if (!existingRestrictionFound) mergedRestrictions.add(desiredRestriction); + } + // Add missing desired restrictions to actual restriction + for (QuotaRestriction desiredRestriction : desiredRestrictions) { + if (!quotaApiMethodExists(existingRestrictions, desiredRestriction)) { + mergedRestrictions.add(desiredRestriction); + } + } + + // Remove actual restrictions are not found in desired restriction. + for (QuotaRestriction existingRestriction : existingRestrictions) { + if (!quotaApiMethodExists(desiredRestrictions, existingRestriction)) { + mergedRestrictions.remove(existingRestriction); + } } } return mergedRestrictions; } + public boolean quotaApiMethodExists(List desiredRestrictions, QuotaRestriction existingRestriction) { + for (QuotaRestriction desiredRestriction : desiredRestrictions) { + if (desiredRestriction.getMethod().equals(existingRestriction.getMethod())) { + return true; + } + } + return false; + } + + public void populateMethodId(API createdAPI, List mergedRestrictions) throws AppException { APIManagerAPIMethodAdapter methodAdapter = APIManagerAdapter.getInstance().getMethodAdapter(); for (QuotaRestriction restriction : mergedRestrictions) { @@ -127,10 +144,18 @@ public void populateMethodId(API createdAPI, List mergedRestri // Additionally, we have to change the methodId // Load the method for actualAPI to get the name of the method to which the existing quota is applied to if (actualState != null) { - APIMethod actualMethod = methodAdapter.getMethodForId(actualState.getId(), restriction.getMethod()); - // Now load the new method based on the name for the createdAPI - APIMethod newMethod = methodAdapter.getMethodForName(createdAPI.getId(), actualMethod.getName()); - // Finally modify the restriction + APIMethod actualMethod = methodAdapter.getMethodForName(actualState.getId(), restriction.getMethod()); + if (actualMethod != null) { + // Now load the new method based on the name for the createdAPI + APIMethod newMethod = methodAdapter.getMethodForName(createdAPI.getId(), actualMethod.getName()); + // Finally modify the restriction + restriction.setMethod(newMethod.getId()); + } else { + LOG.warn("API Method Name : {} not found in specification", restriction.getMethod()); + } + } else { + // For new api creation + APIMethod newMethod = methodAdapter.getMethodForName(createdAPI.getId(), restriction.getMethod()); restriction.setMethod(newMethod.getId()); } } diff --git a/modules/apis/src/main/java/com/axway/apim/apiimport/actions/CreateNewAPI.java b/modules/apis/src/main/java/com/axway/apim/apiimport/actions/CreateNewAPI.java index 220a6348e..dd137228a 100644 --- a/modules/apis/src/main/java/com/axway/apim/apiimport/actions/CreateNewAPI.java +++ b/modules/apis/src/main/java/com/axway/apim/apiimport/actions/CreateNewAPI.java @@ -20,6 +20,7 @@ import com.axway.apim.lib.APIPropertiesExport; import com.axway.apim.lib.error.AppException; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -64,6 +65,10 @@ public void execute(APIChangeState changes, boolean reCreation) throws AppExcept rollback.addRollbackAction(new RollbackAPIProxy(createdAPI)); // In any case, register the API just created for a potential rollback try { + if(EnvironmentProperties.OVERRIDE_CERTIFICATES){ + //Ignore certificates downloaded from backend. + createdAPI.setCaCerts(new ArrayList<>()); + } // ... here we basically need to add all props to initially bring the API in sync! APIChangeState.initCreatedAPI(desiredAPI, createdAPI); //handle backend base path update diff --git a/modules/apis/src/test/java/com/axway/apim/api/export/ExportAPITest.java b/modules/apis/src/test/java/com/axway/apim/api/export/ExportAPITest.java index 386ad0b83..7181d92e0 100644 --- a/modules/apis/src/test/java/com/axway/apim/api/export/ExportAPITest.java +++ b/modules/apis/src/test/java/com/axway/apim/api/export/ExportAPITest.java @@ -2,13 +2,11 @@ import com.axway.apim.api.API; import com.axway.apim.api.model.*; +import com.axway.apim.api.model.apps.ClientApplication; import org.testng.Assert; import org.testng.annotations.Test; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class ExportAPITest { @@ -144,14 +142,14 @@ public void getSecurityProfilesPassThrough() { } @Test - public void getRemoteHostNull(){ + public void getRemoteHostNull() { API api = new API(); ExportAPI exportAPI = new ExportAPI(api); Assert.assertNull(exportAPI.getRemoteHost()); } @Test - public void getRemoteHostStandard(){ + public void getRemoteHostStandard() { API api = new API(); RemoteHost remoteHost = new RemoteHost(); remoteHost.setPort(443); @@ -162,7 +160,7 @@ public void getRemoteHostStandard(){ } @Test - public void getRemoteHostCustomPort(){ + public void getRemoteHostCustomPort() { API api = new API(); RemoteHost remoteHost = new RemoteHost(); remoteHost.setPort(8065); @@ -173,14 +171,14 @@ public void getRemoteHostCustomPort(){ } @Test - public void getCorsProfilesEmpty(){ + public void getCorsProfilesEmpty() { API api = new API(); ExportAPI exportAPI = new ExportAPI(api); Assert.assertTrue(exportAPI.getCorsProfiles().isEmpty()); } @Test - public void getCorsProfilesDefault(){ + public void getCorsProfilesDefault() { API api = new API(); CorsProfile corsProfile = CorsProfile.getDefaultCorsProfile(); List corsProfiles = new ArrayList<>(); @@ -191,7 +189,7 @@ public void getCorsProfilesDefault(){ } @Test - public void getCorsProfiles(){ + public void getCorsProfiles() { API api = new API(); CorsProfile corsProfile = CorsProfile.getDefaultCorsProfile(); corsProfile.setName("custom"); @@ -203,21 +201,21 @@ public void getCorsProfiles(){ } @Test - public void getInboundProfilesEmpty(){ + public void getInboundProfilesEmpty() { API api = new API(); ExportAPI exportAPI = new ExportAPI(api); Assert.assertTrue(exportAPI.getInboundProfiles().isEmpty()); } @Test - public void getTagsEmpty(){ + public void getTagsEmpty() { API api = new API(); ExportAPI exportAPI = new ExportAPI(api); Assert.assertTrue(exportAPI.getTags().isEmpty()); } @Test - public void getTags(){ + public void getTags() { API api = new API(); TagMap apiManagerTags = new TagMap(); String[] tagValue = {"dev"}; @@ -226,4 +224,38 @@ public void getTags(){ ExportAPI exportAPI = new ExportAPI(api); Assert.assertFalse(exportAPI.getTags().isEmpty()); } + + + @Test + public void getMultipleApplicationTest() { + API api = new API(); + APIMethod apiMethod = new APIMethod(); + TagMap apiManagerTags = new TagMap(); + String[] tagValue = {"dev"}; + Organization organization = new Organization(); + organization.setName("test"); + api.setOrganization(organization); + + Organization consumerOrganization = new Organization(); + consumerOrganization.setName("test2"); + + List exportApps = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + ClientApplication clientApplication = new ClientApplication(); + clientApplication.setName("app" + i); + clientApplication.setOrganization(consumerOrganization); + exportApps.add(clientApplication); + } + api.setApplications(exportApps); + + + + apiManagerTags.put("stage", tagValue); + apiMethod.setTags(apiManagerTags); + apiMethod.setDescriptionType("manual"); + apiMethod.setDescriptionManual("manual desc"); + + ExportAPI exportAPI = new ExportAPI(api); + Assert.assertEquals(2, exportAPI.getApplications().size()); + } } diff --git a/modules/apis/src/test/java/com/axway/apim/apiimport/APIImportConfigAdapterTest.java b/modules/apis/src/test/java/com/axway/apim/apiimport/APIImportConfigAdapterTest.java index 0c702435e..8b1cae7da 100644 --- a/modules/apis/src/test/java/com/axway/apim/apiimport/APIImportConfigAdapterTest.java +++ b/modules/apis/src/test/java/com/axway/apim/apiimport/APIImportConfigAdapterTest.java @@ -27,6 +27,7 @@ public class APIImportConfigAdapterTest extends WiremockWrapper { private static final Logger LOG = LoggerFactory.getLogger(APIImportConfigAdapterTest.class); private String apimCliHome; + @BeforeClass public void initWiremock() { super.initWiremock(); @@ -42,6 +43,7 @@ public void initWiremock() { } } + @AfterClass public void close() { super.close(); @@ -272,8 +274,8 @@ public void testMarkdownLocalList() throws AppException { DesiredAPI apiConfig = (DesiredAPI) adapter.getApiConfig(); Assert.assertEquals(apiConfig.getName(), "API with classic markdown local list"); Assert.assertEquals(apiConfig.getDescriptionManual(), "THIS IS THE API-DESCRIPTION FROM A LOCAL MARKDOWN!\n" - + "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.\n" - + "THIS IS THE SECOND API-DESCRIPTION FROM A LOCAL MARKDOWN!"); + + "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.\n" + + "THIS IS THE SECOND API-DESCRIPTION FROM A LOCAL MARKDOWN!"); } @Test @@ -306,7 +308,7 @@ public void completeCaCertsWithCertChain() throws AppException { APIImportConfigAdapter adapter = new APIImportConfigAdapter(testConfig, null, "petstore.json", null); API api = new API(); CaCert caCert = new CaCert(); - // caCert.setAlias("CN=test"); + // caCert.setAlias("CN=test"); caCert.setInbound("true"); caCert.setOutbound("false"); caCert.setCertFile("certchain.pem"); @@ -317,4 +319,19 @@ public void completeCaCertsWithCertChain() throws AppException { Assert.assertEquals(api.getCaCerts().size(), 3); } + @Test + public void testOutboundBasicAuthEmptyPassword() throws AppException { + // Create Environment properties without any stage (basically loads env.properties) + EnvironmentProperties props = new EnvironmentProperties(null, apimCliHome); + APIImportParams params = new APIImportParams(); + params.setProperties(props); + params.setHostname("localhost"); + params.setUsername("test"); + params.setPassword(Utils.getEncryptedPassword()); + String testConfig = this.getClass().getResource("/com/axway/apim/test/files/basic/outbound_basic_auth_empty_password.json").getFile(); + APIImportConfigAdapter adapter = new APIImportConfigAdapter(testConfig, null, "notRelavantForThis Test", null); + API apiConfig = adapter.getApiConfig(); + Assert.assertEquals("", apiConfig.getAuthenticationProfiles().get(0).getParameters().get("password")); + } + } diff --git a/modules/apis/src/test/java/com/axway/apim/apiimport/actions/APIQuotaManagerTest.java b/modules/apis/src/test/java/com/axway/apim/apiimport/actions/APIQuotaManagerTest.java index 076947cd9..67e3c96e5 100644 --- a/modules/apis/src/test/java/com/axway/apim/apiimport/actions/APIQuotaManagerTest.java +++ b/modules/apis/src/test/java/com/axway/apim/apiimport/actions/APIQuotaManagerTest.java @@ -12,7 +12,7 @@ public class APIQuotaManagerTest { @Test - public void addOrMergeRestriction() throws IOException { + public void mergeRestriction() throws IOException { ObjectMapper objectMapper = new ObjectMapper(); String actualQuota = "[\n" + " {\n" + @@ -69,11 +69,186 @@ public void addOrMergeRestriction() throws IOException { " }\n" + " }\n" + " ]"; - TypeReference> quotaRestrictionTypeRef = new TypeReference>() {}; - List actualQuotaRestriction = objectMapper.readValue(actualQuota, quotaRestrictionTypeRef); - List desiredQuotaRestriction = objectMapper.readValue(desiredQuota, quotaRestrictionTypeRef); + TypeReference> quotaRestrictionTypeRef = new TypeReference>() { + }; + List actualQuotaRestriction = objectMapper.readValue(actualQuota, quotaRestrictionTypeRef); + List desiredQuotaRestriction = objectMapper.readValue(desiredQuota, quotaRestrictionTypeRef); APIQuotaManager apiQuotaManager = new APIQuotaManager(null, null); - List result = apiQuotaManager.addOrMergeRestriction(actualQuotaRestriction, desiredQuotaRestriction); - Assert.assertEquals(5, result.size()); + List result = apiQuotaManager.mergeRestriction(actualQuotaRestriction, desiredQuotaRestriction); + Assert.assertEquals(3, result.size()); + } + + + @Test + public void mergeRestrictionActual() throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + String actualQuota = "[\n" + + " {\n" + + " \"api\": \"4f52e8a2-cba1-4645-8088-2ed98f5ea57e\",\n" + + " \"method\": \"method1\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"8\",\n" + + " \"messages\": \"1000\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"api\": \"*\",\n" + + " \"method\": \"method2\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"5\",\n" + + " \"messages\": \"1000\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"api\": \"4f52e8a2-cba1-4645-8088-2ed98f5ea57e\",\n" + + " \"method\": \"*\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"messages\": \"1000\",\n" + + " \"period\": \"second\",\n" + + " \"per\": \"2\"\n" + + " }\n" + + " }\n" + + "]"; + + String desiredQuota = "[\n" + + " {\n" + + " \"api\": \"4f52e8a2-cba1-4645-8088-2ed98f5ea57e\",\n" + + " \"method\": \"method1\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"8\",\n" + + " \"messages\": \"1000\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"api\": \"method2\",\n" + + " \"method\": \"*\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"5\",\n" + + " \"messages\": \"1000\"\n" + + " }\n" + + " }\n" + + " ]"; + TypeReference> quotaRestrictionTypeRef = new TypeReference>() { + }; + List actualQuotaRestriction = objectMapper.readValue(actualQuota, quotaRestrictionTypeRef); + List desiredQuotaRestriction = objectMapper.readValue(desiredQuota, quotaRestrictionTypeRef); + APIQuotaManager apiQuotaManager = new APIQuotaManager(null, null); + List result = apiQuotaManager.mergeRestriction(actualQuotaRestriction, desiredQuotaRestriction); + Assert.assertEquals(2, result.size()); + } + + @Test + public void mergeRestrictionDesired() throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + String actualQuota = "[\n" + + " {\n" + + " \"method\": \"PATCH /{txid}\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"1\",\n" + + " \"messages\": \"656\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"method\": \"OPTIONS /{txid}\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"1\",\n" + + " \"messages\": \"750\"\n" + + " }\n" + + " }\n" + + " ]"; + + String desiredQuota = "[\n" + + " {\n" + + " \"method\": \"PATCH /{txid}\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"1\",\n" + + " \"messages\": \"656\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"method\": \"OPTIONS /{txid}\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"1\",\n" + + " \"messages\": \"750\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"method\": \"POST /{txid}\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"1\",\n" + + " \"messages\": \"887\"\n" + + " }\n" + + " }\n" + + " ]"; + TypeReference> quotaRestrictionTypeRef = new TypeReference>() { + }; + List actualQuotaRestriction = objectMapper.readValue(actualQuota, quotaRestrictionTypeRef); + List desiredQuotaRestriction = objectMapper.readValue(desiredQuota, quotaRestrictionTypeRef); + APIQuotaManager apiQuotaManager = new APIQuotaManager(null, null); + List result = apiQuotaManager.mergeRestriction(actualQuotaRestriction, desiredQuotaRestriction); + Assert.assertEquals(3, result.size()); + } + + + @Test + public void mergeRestrictionDesiredWithNoActual() throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + String actualQuota = "[]"; + + String desiredQuota = "[\n" + + " {\n" + + " \"method\": \"PATCH /{txid}\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"1\",\n" + + " \"messages\": \"656\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"method\": \"OPTIONS /{txid}\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"1\",\n" + + " \"messages\": \"750\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"method\": \"POST /{txid}\",\n" + + " \"type\": \"throttle\",\n" + + " \"config\": {\n" + + " \"period\": \"second\",\n" + + " \"per\": \"1\",\n" + + " \"messages\": \"887\"\n" + + " }\n" + + " }\n" + + " ]"; + TypeReference> quotaRestrictionTypeRef = new TypeReference>() { + }; + List actualQuotaRestriction = objectMapper.readValue(actualQuota, quotaRestrictionTypeRef); + List desiredQuotaRestriction = objectMapper.readValue(desiredQuota, quotaRestrictionTypeRef); + APIQuotaManager apiQuotaManager = new APIQuotaManager(null, null); + List result = apiQuotaManager.mergeRestriction(actualQuotaRestriction, desiredQuotaRestriction); + Assert.assertEquals(3, result.size()); } } diff --git a/modules/apis/src/test/java/com/axway/apim/export/test/applications/ApplicationExportTestIT.java b/modules/apis/src/test/java/com/axway/apim/export/test/applications/ApplicationExportTestIT.java index e3e9f9acf..320802965 100644 --- a/modules/apis/src/test/java/com/axway/apim/export/test/applications/ApplicationExportTestIT.java +++ b/modules/apis/src/test/java/com/axway/apim/export/test/applications/ApplicationExportTestIT.java @@ -60,7 +60,7 @@ public void run(@Optional @CitrusResource TestContext context) throws IOExceptio // ############## Creating Test-Application 1 ################# variable("app1Name", "Consuming Test App ${apiNumber} ${orgNumber}"); $(http().client(apiManager).send().post("/applications").message().header("Content-Type", "application/json") - .body("{\"name\":\"${app1Name}\",\"apis\":[],\"organizationId\":\"${orgId}\"}")); + .body("{\"name\":\"${app1Name}\",\"apis\":[],\"organizationId\":\"${orgId3}\"}")); $(http().client(apiManager).receive().response(HttpStatus.CREATED).message().type(MessageType.JSON).extract(fromBody() .expression("$.id", "consumingTestApp1Id") @@ -83,7 +83,6 @@ public void run(@Optional @CitrusResource TestContext context) throws IOExceptio JsonNode exportedAPIConfig = mapper.readTree(Files.newInputStream(new File(exportedAPIConfigFile).toPath())); assertEquals(exportedAPIConfig.get("version").asText(), "1.0.1"); assertEquals(exportedAPIConfig.get("organization").asText(), "API Development " + context.getVariable("orgNumber")); - //assertEquals(exportedAPIConfig.get("backendBasepath").asText(), "https://petstore.swagger.io"); assertEquals(exportedAPIConfig.get("state").asText(), "published"); assertEquals(exportedAPIConfig.get("path").asText(), context.getVariable("apiPath")); assertEquals(exportedAPIConfig.get("name").asText(), context.getVariable("apiName")); @@ -99,12 +98,10 @@ public void run(@Optional @CitrusResource TestContext context) throws IOExceptio ClientApplication app = exportedApps.get(0); assertTrue(app.getApiAccess() == null || app.getApiAccess().isEmpty(), "Exported Apps should not contains API-Access"); assertNull(app.getId(), "The ID of an application shouldn't be exported."); - assertNull(app.getOrganization(), "The Org-ID of an application shouldn't be exported."); assertNull(app.getAppQuota(), "The application quota should not be exported. It's not supported by the export!"); assertTrue(new File(context.getVariable("exportLocation") + "/" + context.getVariable("exportFolder") + "/swagger.io.crt").exists(), "Certificate swagger.io.crt is missing"); assertTrue(new File(context.getVariable("exportLocation") + "/" + context.getVariable("exportFolder") + "/StarfieldServicesRootCertificateAuthority-G2.crt").exists(), "Certificate StarfieldServicesRootCertificateAuthority-G2.crt is missing"); assertTrue(new File(context.getVariable("exportLocation") + "/" + context.getVariable("exportFolder") + "/AmazonRootCA1.crt").exists(), "Certificate AmazonRootCA1.crt is missing"); - // assertTrue(new File(context.getVariable("exportLocation") + "/" + context.getVariable("exportFolder") + "/Amazon.crt").exists(), "Certificate Amazon.crt is missing"); assertTrue(new File(context.getVariable("exportLocation") + "/" + context.getVariable("exportFolder") + "/" + context.getVariable("exportAPIName")).exists(), "Exported Swagger-File is missing"); } } diff --git a/modules/apis/src/test/java/com/axway/apim/test/ImportTestAction.java b/modules/apis/src/test/java/com/axway/apim/test/ImportTestAction.java index 0740c4dc8..457ec7a37 100644 --- a/modules/apis/src/test/java/com/axway/apim/test/ImportTestAction.java +++ b/modules/apis/src/test/java/com/axway/apim/test/ImportTestAction.java @@ -49,8 +49,8 @@ public void doExecute(TestContext context) { apiDefinition = origApiDefinition; } String configFile = replaceDynamicContentInFile(origConfigFile, context, createTempFilename(origConfigFile)); - LOG.info("Using Replaced Swagger-File: " + apiDefinition); - LOG.info("Using Replaced configFile-File: " + configFile); + LOG.info("Using Replaced Swagger-File: {}", apiDefinition); + LOG.info("Using Replaced configFile-File: {}", configFile); int expectedReturnCode = 0; try { expectedReturnCode = Integer.parseInt(context.getVariable("expectedReturnCode")); @@ -119,7 +119,7 @@ public void doExecute(TestContext context) { // This creates the dynamic staging config file! (For testing, we also support reading out of a file directly) replaceDynamicContentInFile(stageConfigFile, context, replacedStagedConfig); } - copyImagesAndCertificates(origConfigFile, context); + copyImagesAndCertificates(origConfigFile); List args = new ArrayList<>(); if (useEnvironmentOnly) { @@ -138,8 +138,7 @@ public void doExecute(TestContext context) { if (useApiAdmin) { LOG.info("API-Manager import is using user: '" + context.replaceDynamicContentInString("${apiManagerUser}") + "'"); args.add(context.replaceDynamicContentInString("${apiManagerUser}")); - } - else { + } else { LOG.info("API-Manager import is using user: '" + context.replaceDynamicContentInString("${oadminUsername1}") + "'"); args.add(context.replaceDynamicContentInString("${oadminUsername1}")); } @@ -262,7 +261,7 @@ private File createTestDirectory(TestContext context) { return testDir; } - private void copyImagesAndCertificates(String origConfigFile, TestContext context) { + private void copyImagesAndCertificates(String origConfigFile) { File sourceDir = new File(origConfigFile).getParentFile(); if (!sourceDir.exists()) { sourceDir = new File(ImportTestAction.class.getResource(origConfigFile).getFile()).getParentFile(); @@ -272,7 +271,7 @@ private void copyImagesAndCertificates(String origConfigFile, TestContext contex } FileFilter filter = new WildcardFileFilter("*.crt", "*.jpg", "*.png", "*.pem", "*.md"); try { - LOG.info("Copy certificates and images from source: " + sourceDir + " into test-dir: '" + testDir + "' (Filter: \"*.crt\", \"*.jpg\", \"*.png\", \"*.pem\", \"*.md\")"); + LOG.info("Copy certificates and images from source: {} into test-dir: {} (Filter: \"*.crt\", \"*.jpg\", \"*.png\", \"*.pem\", \"*.md\")", sourceDir, testDir); FileUtils.copyDirectory(sourceDir, testDir, filter); } catch (IOException e) { e.printStackTrace(); diff --git a/modules/apis/src/test/java/com/axway/apim/test/quota/ValidateAppQuotaStaysTestIT.java b/modules/apis/src/test/java/com/axway/apim/test/quota/ValidateAppQuotaStaysTestIT.java index eab71776c..c0d732b80 100644 --- a/modules/apis/src/test/java/com/axway/apim/test/quota/ValidateAppQuotaStaysTestIT.java +++ b/modules/apis/src/test/java/com/axway/apim/test/quota/ValidateAppQuotaStaysTestIT.java @@ -76,7 +76,7 @@ public void run() throws IOException, InterruptedException { + "{\"api\":\"${apiId}\",\"method\":\"${testMethodId}\",\"type\":\"throttle\",\"config\":{\"period\":\"day\",\"per\":2,\"messages\":100000}} " + "]," + "\"system\":false}")); - $(http().client(apiManager).receive().response(HttpStatus.OK)); + $(http().client(apiManager).receive().response(HttpStatus.CREATED)); $(echo("####### Enforce Re-Creation of API - Application quotas must stay #######")); variable(ImportTestAction.API_DEFINITION, "/com/axway/apim/test/files/basic/petstore2.json"); variable(ImportTestAction.API_CONFIG, "/com/axway/apim/test/files/quota/2_api-with-quota-app-subscription.json"); diff --git a/modules/apis/src/test/resources/com/axway/apim/test/files/basic/outbound_basic_auth_empty_password.json b/modules/apis/src/test/resources/com/axway/apim/test/files/basic/outbound_basic_auth_empty_password.json new file mode 100644 index 000000000..2071e6536 --- /dev/null +++ b/modules/apis/src/test/resources/com/axway/apim/test/files/basic/outbound_basic_auth_empty_password.json @@ -0,0 +1,18 @@ +{ + "name": "test", + "path": "/test", + "state": "Published", + "version": "1.0.0", + "organization": "orga", + "authenticationProfiles": [ + { + "name": "_default", + "isDefault": true, + "parameters": { + "username": "daskdjaskldjaskljdklasjdl", + "password": "" + }, + "type": "http_basic" + } + ] +} diff --git a/modules/apis/src/test/resources/test/export/files/applications/1_api-with-0-org-1-app.json b/modules/apis/src/test/resources/test/export/files/applications/1_api-with-0-org-1-app.json index b50d33006..6a7216e81 100644 --- a/modules/apis/src/test/resources/test/export/files/applications/1_api-with-0-org-1-app.json +++ b/modules/apis/src/test/resources/test/export/files/applications/1_api-with-0-org-1-app.json @@ -4,7 +4,8 @@ "state":"${state}", "version":"1.0.1", "organization":"API Development ${orgNumber}", + "clientOrganizations" : [ "API Development 5172" ], "applications":[ { "name":"${consumingTestAppName}" } ] -} \ No newline at end of file +} diff --git a/modules/apps/src/test/java/com/axway/apim/appimport/it/basic/ImportApplicationWithAPIAccessTestIT.java b/modules/apps/src/test/java/com/axway/apim/appimport/it/basic/ImportApplicationWithAPIAccessTestIT.java index 57a5c8edc..597623ee1 100644 --- a/modules/apps/src/test/java/com/axway/apim/appimport/it/basic/ImportApplicationWithAPIAccessTestIT.java +++ b/modules/apps/src/test/java/com/axway/apim/appimport/it/basic/ImportApplicationWithAPIAccessTestIT.java @@ -47,7 +47,7 @@ public void importApplicationBasicTest(@Optional @CitrusResource TestContext con context, "apps", false); $(testContext -> { String[] args = {"api", "import", "-c", updatedConfigFile, "-a", specFile, "-h", testContext.getVariable("apiManagerHost"), - "-u", testContext.getVariable("apiManagerUser"), "-p", testContext.getVariable("apiManagerPass")}; + "-u", testContext.getVariable("apiManagerUser"), "-p", testContext.getVariable("apiManagerPass"), "-force"}; int returnCode = APIImportApp.importAPI(args); if (returnCode != 0) throw new ValidationException("Expected RC was: 0 but got: " + returnCode); diff --git a/modules/organizations/src/main/java/com/axway/apim/organization/OrganizationApp.java b/modules/organizations/src/main/java/com/axway/apim/organization/OrganizationApp.java index 87bfbcf83..23ae436bb 100644 --- a/modules/organizations/src/main/java/com/axway/apim/organization/OrganizationApp.java +++ b/modules/organizations/src/main/java/com/axway/apim/organization/OrganizationApp.java @@ -24,7 +24,6 @@ public class OrganizationApp implements APIMCLIServiceProvider { private static final Logger LOG = LoggerFactory.getLogger(OrganizationApp.class); - static ErrorCodeMapper errorCodeMapper = new ErrorCodeMapper(); @Override public String getName() { @@ -115,16 +114,18 @@ private static ExportResult exportOrgs(OrgExportParams params, ResultHandler exp @CLIServiceMethod(name = "import", description = "Import organization(s) into the API-Manager") public static int importOrganization(String[] args) { OrgImportParams params; + ErrorCodeMapper errorCodeMapper = new ErrorCodeMapper(); try { params = (OrgImportParams) OrgImportCLIOptions.create(args).getParams(); } catch (AppException e) { - LOG.error("Error {}", e.getMessage()); - return e.getError().getCode(); + LOG.error("Error importing org {}", e.getMessage()); + return errorCodeMapper.getMapedErrorCode(e.getError()).getCode(); } - return importOrganization(params); + return errorCodeMapper.getMapedErrorCode(importOrganization(params)).getCode(); + } - public static int importOrganization(OrgImportParams params) { + public static ErrorCode importOrganization(OrgImportParams params) { APIManagerAdapter apiManagerAdapter = null; try { params.validateRequiredParameters(); @@ -141,13 +142,13 @@ public static int importOrganization(OrgImportParams params) { importManager.replicate(desiredOrg, actualOrg); } LOG.info("Successfully replicated organization(s) into API-Manager"); - return ErrorCode.SUCCESS.getCode(); + return ErrorCode.SUCCESS; } catch (AppException ap) { ap.logException(LOG); - return errorCodeMapper.getMapedErrorCode(ap.getError()).getCode(); + return ap.getError(); } catch (Exception e) { LOG.error(e.getMessage(), e); - return ErrorCode.UNXPECTED_ERROR.getCode(); + return ErrorCode.UNXPECTED_ERROR; } finally { Utils.deleteInstance(apiManagerAdapter); } @@ -159,7 +160,7 @@ public static int delete(String[] args) { OrgExportParams params = (OrgExportParams) OrgDeleteCLIOptions.create(args).getParams(); return delete(params).getRc(); } catch (AppException e) { - LOG.error("Error : {}", e.getMessage()); + LOG.error("Error deleting org : {}", e.getMessage()); return e.getError().getCode(); } } diff --git a/pom.xml b/pom.xml index bce76321d..1a8793591 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 4.1.1 2.15.3 3.3.2 - 21.3 + 21.5 4.10.0 2.0.13 2.9.0 @@ -117,7 +117,7 @@ commons-io commons-io - 2.11.0 + 2.14.0 org.apache.commons