diff --git a/.env b/.env index acfd4e47..d9f1fad8 100755 --- a/.env +++ b/.env @@ -1,9 +1,42 @@ +# ---------------------------------------------------------------------------------------------- # Filebeat will mount that folder into the Filebeat Docker-Container to have access to the files APIGATEWAY_LOGS_FOLDER=/home/localuser/Axway-x.y.z/apigateway/logs/opentraffic APIGATEWAY_TRACES_FOLDER=/home/localuser/Axway-x.y.z/apigateway/groups/group-2/instance-1/trace -# This variable is used by the API-Builder project to locate the Elasticsearch instance -# Using the default docker-compose.yaml this setting is sufficient -# When running the API-Builder on a different host, this variable needs to be made available to the -# container. -ELASTIC_NODE=http://elasticsearch1:9200 \ No newline at end of file +# ---------------------------------------------------------------------------------------------- +# This variable is used by the API-Builder to locate the Elasticsearch instance +# When using the default docker-compose.yaml this setting is optional. +# But, when running the ElasticSearch on a difference host (e.g. existing Elastic-Search cluster) +# this environment variable is used by the API-Builder to locate the ElasticSearch cluster. +# ELASTIC_NODE=http://elasticsearch1:9200 + +# ---------------------------------------------------------------------------------------------- +# This variable is used by Logstash to communicate with the Lookup-API, which is used to +# enrich documents before sending it to ElasticSearch. +# When using the default docker-compose.yml the default setting will work. +# But, if the API-Builder process is running somewhere else (e.g. externally), you have to make +# this environment variable available to the Logstash Docker-Container. +API_BUILDER_URL=http://elk-traffic-monitor-api:8080 + + +# ---------------------------------------------------------------------------------------------- +# The following three variables are used by the API-Builder project to communicate with the +# API-Management platform (Admin-Node-Manager & API-Manager) + +# The Connection/URL to the Admin-Node-Manager. +# IMPORTANT NOTE: +# This URL must be reachable/resolveable from within the API-Builder Docker-Container! +ADMIN_NODE_MANAGER=https://api-env:8090 + +# ---------------------------------------------------------------------------------------------- +# The Connection/URL to the API-Manager. If not given, the same as Admin-Node-Manager URL with +# port 8075 is used. +# IMPORTANT NOTE: +# This URL must be reachable/resolveable from within the API-Builder Docker-Container! +# API_MANAGER=https://api-env:8075 + +# ---------------------------------------------------------------------------------------------- +# This user is used by API-Builder to lookup APIs & User-Information in API-Manager. +# Therefore it must be a user having "admin" role. +API_MANAGER_USERNAME=apiadmin +API_MANAGER_PASSWORD=changeme \ No newline at end of file diff --git a/.github/workflows/api-utils-flow-node.yml b/.github/workflows/api-utils-flow-node.yml new file mode 100644 index 00000000..8e34125e --- /dev/null +++ b/.github/workflows/api-utils-flow-node.yml @@ -0,0 +1,44 @@ +# This workflow is validating the API-Builder exposed Traffic-Monitor API. +# For that an Elasticsearch instance is started, test-data inserted and the +# API-Builder Traffic-Monitor API is executed with all possible parameters. + +name: API-Builder API-Utils Flow-Node + + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + release: + types: [ published ] + +jobs: + build: + if: "!contains(github.event.head_commit.message, 'skip ci')" + env: + workingDirectory: 'elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management' + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [12.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Run npm ci, npm test + working-directory: ${{env.workingDirectory}} + env: + LOG_LEVEL: DEBUG + CI: true + run: | + npm ci + npm run build --if-present + npm test + + diff --git a/.github/workflows/traffic-monitor-api.yml b/.github/workflows/traffic-monitor-api.yml index 909930d2..80586500 100644 --- a/.github/workflows/traffic-monitor-api.yml +++ b/.github/workflows/traffic-monitor-api.yml @@ -34,7 +34,7 @@ jobs: - name: Starting Elasticsearch instance uses: nyaruka/elasticsearch-action@v1 with: - elastic version: '7.6.1' + elastic version: '7.8.1' - name: Sleep 15 seconds to make sure ES is ready uses: jakejarvis/wait-action@master with: diff --git a/README.md b/README.md index 24a35e7f..dbae0559 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,22 @@ # API-Management Traffic-Monitor based ELK stack +This project has 3 main objectives in relation to the Axway API management solution. + +__Performance__ + When having many API-Gateway instances with millions of requests the API-Gateway Traffic Monitor can become slow and the observation period quite short. The purpose of this project is to solve that performance issue, make it possible to observe a long time-frame and get other benefits by using a standard external datastore: [Elasticsearch](https://www.elastic.co/elasticsearch). +__Visibility__ + +This solution allows API service providers to give access to the Standard Traffic Monitor so that they only see the API traffic of their own organization. This allows API service providers to analyze their own traffic using the extensive information in the traffic monitor. + +__Analytics__ + +With the help of Kibana, the goal of the project is to deliver standard dashboards that provide analysis capabilities across multiple perspectives. +It should still be possible to add your own dashboards as you wish. + +## Architecture + The overall architecture this project provides looks like this: ![Architecture][img1] @@ -11,20 +26,35 @@ It also helps, when running the Axway API-Gateway in Docker-Orchestration-Enviro Watch this video to see a side by side compare betwen the classical and ElasticSearch based Traffic-Monitor: [![API-Management CLI](https://img.youtube.com/vi/MUbx4m9EtpY/0.jpg)](https://youtu.be/MUbx4m9EtpY) -### How it works +## How it works Each API-Gateway instance is writing, [if configured](#enable-open-traffic-event-log), Open-Traffic Event-Log-Files, which are streamed by [Filebeat](https://www.elastic.co/beats/filebeat) into a Logstash-Instance. [Logstash](https://www.elastic.co/logstash) performs data pre-processing, combines different events and finally forwards these so called documents into an Elasticsearch cluster. Once the data is indexed by Elasticsearch it can be used by different clients. This process allows almost realtime monitoring of incoming requests. It takes around 5 seconds until a request is available in Elasticsearch. -## Using the existing Traffic-Monitor -Use the existing API-Gateway Traffic-Monitor. That means, you use the same tooling as of today, but the underlying implementation of the Traffic-Monitor API is now pointing to Elasticsearch instead of the internal OPSDB hosted by each API-Gateway instance. This improves performance damatically, as Elasticsearch can scale across multiple machines if required and other dashboards can be created for instance with Kibana. +## The Traffic-Monitor + +The standard API-Gateway Traffic-Monitor which is shipped with the solution is based on a REST-API that is provided by the Admin-Node-Manager. By default the Traffic-Information is loaded from the OBSDB running on each API-Gateway instance. This project is partly re-implementing this REST-API, which makes it possible, that the Traffic-Monitor is using data from ElasticSearch instead of the internal OBSDB. +That means, you can use the same tooling as of today, but the underlying implementation of the Traffic-Monitor is now pointing to Elasticsearch instead of the internal OPSDB hosted by each API-Gateway instance. This improves performance damatically, as Elasticsearch can scale across multiple machines if required and other dashboards can be created for instance with Kibana. The glue between Elasticsearch and the API-Gateway Traffic-Monitor is an [API-Builder project](./elk-traffic-monitor-api), that is exposing the same Traffic-Monitor API, but it is implemented using Elasticsearch instead of the OPSDB. The API-Builder is available as a ready to use Docker-Image and preconfigured in the docker-compose file. Optionally you can import the API-Builder API into your API-Management system to apply additional security and by that secure access to your Elasticsearch instance. -Finally, the Admin-Node-Manager has to be [configured](#configure-the-admin-node-manager) to use the API-Builder API instead of the internal implementation. +## Restrict the Traffic-Monitor -API-Builder exposing Traffic-Monitor API: -[![Traffic-Monitor API](https://github.com/Axway-API-Management-Plus/apigateway-openlogging-elk/workflows/Traffic-Monitor%20API/badge.svg)](https://github.com/Axway-API-Management-Plus/apigateway-openlogging-elk/actions) +In larger companies hundreds of API service providers are using the API Manager to register their own services/APIs and want or should be able to monitor their own API independently. During registration, the corresponding APIs are assigned to API Manager organizations. However, the standard traffic monitor does not know the organization concept and therefore cannot restrict the view for a user based on the organization of an API. +This project solves the problem by storing the API transactions in Elasticsearch with the appropriate organization. This API organization is used when reading the traffic data from Elasticsearch according to the following rules. + +| API-Gateway Manager | API-Manager | Restriction | Comment | +| :--- | :--- | :--- | :--- | +| **Administrator** | N/A | Unrestricted access | A GW-Manager user is considered as an Admin, when is owns the permission: `adminusers_modify` | +| **Operator** | API-Admin | All APIs having a Service-Context | By default each API processed by the API-Manager has a Service-Context. Pure Gateway APIs (e.g. /healthcheck) will not be visible.| +| **Operator** | Org-Admin | APIs of its own organization | Such a user will only see the APIs that belong to the same organization as himself. | +| **Operator** | User | APIs of its own organization | The same rules apply as for the Org-Admin | + +### Setup Restricted user + +To give a user limited access to the API Traffic Monitor, the user must use the same login name in the API Manager and API Gateway Manager. Here, for example, an LDAP connection can be a simplification. +In order to give the user a restricted view in the API Gateway Manager, none of his roles must contain the permission: `adminusers_modify`. A suitable standard role is the `API Gateway Operator role`. +You can, of course, create additional roles in the API Gateway Manager to adjust the user's rights according to your needs. ## Prerequisites For a simple deployment the prerequisites are very simple as all services can be started as a Docker-Container. In order to start all components in PoC-Like-Mode you just need: @@ -81,31 +111,54 @@ You may add a custom success message (e.g. `Used ElasticSearch API`) if you like :point_right: Please remember to copy the changed Admin-Node-Manager configuration from the Policy-Studio project folder (path on Linux: `/home//apiprojects/\`) back to the ANM folder (`\/apigateway/conf/fed`). Afterwards the ANM must be restarted. +## Setup + +Before you start the environment based on the `docker-compose.yml` file, please adjust the `.env` file accordingly. The configuration is already used by the different modules as described below. + ### Setup filebeat :exclamation: __This is an important step, as otherwise Filebeat will not see and send any Open-Traffic Event data!__ -Before starting the container using docker-compose, make sure to setup the paths in the project `*.env` file. The variables must point to your running API-Gateway instance. These parameters are used to mount the Open-Traffic-Folder into the Filebeat container. For a typical Linux installation it looks like this (APIM beeing a symlink to current software version): +Setup the paths in the project `*.env` file. The variables must point to your running API-Gateway instance. These parameters are used to mount the Open-Traffic-Folder into the Filebeat container. For a typical Linux installation it looks like this (APIM being a symlink to current software version): ``` APIGATEWAY_LOGS_FOLDER=/opt/Axway/APIM/apigateway/logs/opentraffic APIGATEWAY_TRACES_FOLDER=/opt/Axway/APIM/apigateway/groups/group-2/instance-1/trace ``` +### Setup Logstash + +Logstash receives the open traffic and open trace events from Filebeat and processes them. Among other things, an HTTP lookup is performed on an API detail lookup REST-API to enrich the API information. Therefore Logstash must know under which URL the API builder can be reached. +This parameter is optional if you use the default docker-compose.yml file. +``` +API_BUILDER_URL=http://my-api-builder:8080 +``` + ### Setup API-Builder -As the API-Builder container needs to communicate with Elasticsearch it needs to know where Elasticsearch is running. Again, this environment variable must be configured within `.env`: +As the API-Builder container needs to communicate with Elasticsearch it needs to know where Elasticsearch is running: +Please note, when using the default docker-compose.yaml the default setting is sufficient, as it's using the internal Docker-Network `elastic`. ``` ELASTIC_NODE=http://elasticsearch1:9200 ``` -Please note, when using the default docker-compose.yaml the default setting is sufficient, as it's using the internal Docker-Network `elastic`. - -### Update vm.max_map_count kernel setting to at least 262144 +Furthermore, the API Builder communicates with the Admin Node Manager and API Manager. Therefore the following parameters must be configured in the `.env` file. +``` +ADMIN_NODE_MANAGER=https://api-env:8090 +API_MANAGER_USERNAME= +API_MANAGER_PASSWORD= +``` -See https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-prod-prerequisites +Build status API-Builder Traffic-Monitor API: +[![Traffic-Monitor API](https://github.com/Axway-API-Management-Plus/apigateway-openlogging-elk/workflows/Traffic-Monitor%20API/badge.svg)](https://github.com/Axway-API-Management-Plus/apigateway-openlogging-elk/actions) -### Start local Elasticsearch cluster -Bring the cluster up using docker-compose: +## Start the environment +To bring up the entire environment using docker-compose: ```` docker-compose up -d ```` -Of course, the components can also run on different machines or on a Docker-Orchestration framework such as Kubernetes. +You can also run the individual components on different environments. To do this, you can check out the project on the appropriate machines, adjust the docker-compose.yml and .env file and start the desired services. +To start a single service (e.g. the API-Builder project): +``` +docker-compose up -d elk-traffic-monitor-api +``` + +Of course it is also possible to run the containers in a docker orchestration framework, like Kubernetes or OpenShift. ### Stop local Elasticsearch cluster ```` @@ -179,7 +232,10 @@ When Logstash is successfully started you should see the following: [INFO ][logstash.agent ] Pipelines running {:count=>2, :running_pipelines=>[:main, :".monitoring-logstash"], :non_running_pipelines=>[]} [INFO ][logstash.agent ] Successfully started Logstash API endpoint {:port=>9600} ``` - +If you see the following or similar error message during processing of events the API-Builder Lookup-API cannot be reached. In case, please make sure the environment variable: `API_BUILDER_URL`is set correctly. +``` +[2020-08-19T10:51:05,671][ERROR][logstash.filters.http ][main][......] error during HTTP request {:url=>"/api/elk/v1/api/lookup/api", :body=>nil, :client_error=>"Target host is not specified"} +``` ### Check Elasticsearch processing It takes a while until Elasticsearch is finally started and reports it with the following line: diff --git a/docker-compose.yml b/docker-compose.yml index c0699220..a20df269 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -76,6 +76,7 @@ services: environment: - PIPELINE_WORKERS=1 - XPACK_MONITORING_ELASTICSEARCH_HOSTS=["elasticsearch1:9200"] + - API_BUILDER_URL=${API_BUILDER_URL} ports: - 5044:5044 volumes: @@ -84,6 +85,7 @@ services: command: logstash --path.config /usr/share/logstash/pipeline/pipeline.conf --pipeline.batch.size 400 --log.level info depends_on: - elasticsearch1 + - elk-traffic-monitor-api networks: - elastic @@ -93,7 +95,10 @@ services: links: - elasticsearch1 environment: - - ELASTIC_NODE=http://elasticsearch1:9200 + - ELASTIC_NODE=${ELASTIC_NODE} + - ADMIN_NODE_MANAGER=${ADMIN_NODE_MANAGER} + - API_MANAGER_USERNAME=${API_MANAGER_USERNAME} + - API_MANAGER_PASSWORD=${API_MANAGER_PASSWORD} #- LOG_LEVEL=debug ports: - 8889:8080 diff --git a/elk-traffic-monitor-api/conf/axway-api-utils.default.js b/elk-traffic-monitor-api/conf/axway-api-utils.default.js new file mode 100644 index 00000000..92489d12 --- /dev/null +++ b/elk-traffic-monitor-api/conf/axway-api-utils.default.js @@ -0,0 +1,16 @@ +module.exports = { + pluginConfig: { + 'api-builder-plugin-axway-api-management': { + 'apigateway': { + url: process.env.ADMIN_NODE_MANAGER, + //username: process.env.ANM_USERNAME, // For future use + //password: process.env.ANM_PASSWORD // For future use + }, + 'apimanager': { + url: process.env.API_MANAGER, // If not set, the Admin-Node-Manager hostname is used + username: process.env.API_MANAGER_USERNAME, // User with Admin-Privileges required + password: process.env.API_MANAGER_PASSWORD + } + } + } +}; diff --git a/elk-traffic-monitor-api/conf/elasticsearch.default.js b/elk-traffic-monitor-api/conf/elasticsearch.default.js index f2fcfb37..1a478631 100644 --- a/elk-traffic-monitor-api/conf/elasticsearch.default.js +++ b/elk-traffic-monitor-api/conf/elasticsearch.default.js @@ -2,7 +2,7 @@ module.exports = { pluginConfig: { '@axway-api-builder-ext/api-builder-plugin-fn-elasticsearch': { 'elastic': { - node: process.env.ELASTIC_NODE, + node: (process.env.ELASTIC_NODE) ? process.env.ELASTIC_NODE : 'http://elasticsearch1:9200', auth: { /* Use an API-Key apiKey: process.env.ELASTIC_API_KEY @@ -12,7 +12,7 @@ module.exports = { */ }, // The name to identify the client instance in the events. - name: 'api-builder' + name: 'elk-traffic-monitor-api' // You can use all configuration options documented here: // https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/7.x/client-configuration.html } diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/.gitignore b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/README.md b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/README.md new file mode 100644 index 00000000..11136a4a --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/README.md @@ -0,0 +1,24 @@ +# api-builder-plugin-axway-api-management + +## About flow-nodes + +Flow-nodes are used within [Axway API Builder's](https://www.axway.com/en/datasheet/axway-api-builder) +flow editor that is a low-code / no-code solution to designing and developing services +that integrate to many different connected components, such as databases and APIs. + +## Getting started + +1. Follow the [Getting Started Guide](https://docs.axway.com/bundle/API_Builder_4x_allOS_en/page/api_builder_getting_started_guide.html) to create an API Builder service +1. Follow the [API Builder SDK](https://docs.axway.com/bundle/API_Builder_4x_allOS_en/page/api_builder_sdk.html) guide to get started creating flow-node plugins. + +## Publish + +After developing this plugin you can publish it to [npm](https://www.npmjs.com) to make it public. + +## Install + +After creating your API Builder service (`api-builder init`), you can install this plugin using npm: + +``` +npm install api-builder-plugin-axway-api-management +``` diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/config/axway-api-utils.default.js b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/config/axway-api-utils.default.js new file mode 100644 index 00000000..c7afee63 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/config/axway-api-utils.default.js @@ -0,0 +1,16 @@ +module.exports = { + pluginConfig: { + 'api-builder-plugin-axway-api-management': { + 'apigateway': { + url: process.env.ADMIN_NODE_MANAGER, + //username: process.env.API_GATEWAY_USERNAME, // For future use + //password: process.env.API_GATEWAY_PASSWORD // For future use + }, + 'apimanager': { + url: process.env.API_MANAGER, // If not set, the API-Gateway hostname is used + username: process.env.API_MANAGER_USERNAME, // User with Admin-Privileges required + password: process.env.API_MANAGER_PASSWORD + } + } + } +}; diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/package-lock.json b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/package-lock.json new file mode 100644 index 00000000..b072e083 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/package-lock.json @@ -0,0 +1,1119 @@ +{ + "name": "api-builder-plugin-axway-api-management", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@axway/api-builder-sdk": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@axway/api-builder-sdk/-/api-builder-sdk-1.0.4.tgz", + "integrity": "sha512-iRaxGZg9NhyY319atpA4KBRdT5F2Gc6UxmldTKqU+5Exudj0EaqIqcLvk2tbqqhAO/aK6zQpuNvny9QXRRlwfg==", + "requires": { + "ajv": "^5.3.0", + "js-yaml": "^3.13.1" + } + }, + "@axway/api-builder-test-utils": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@axway/api-builder-test-utils/-/api-builder-test-utils-1.1.1.tgz", + "integrity": "sha512-Hgj0jAf7LYW2tP51OYIgQl4ZQ6aIunsrBzv+p0PKxpzzDjOE74aYQw7x3oybhco7R7xpWm/yglgaZFi/1KITYw==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "axway-flow-schema": "5.4.1" + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, + "axway-flow-schema": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/axway-flow-schema/-/axway-flow-schema-5.4.1.tgz", + "integrity": "sha512-+xMZSXADmeXmBDgfsVUJXq2dpYb9wz4QjuXuxCc1EcfwcDyrpzwR/19rlmRvSgN3ZoWcIFzXsxahelWAPdU2dw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", + "dev": true + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "nock": { + "version": "13.0.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.0.4.tgz", + "integrity": "sha512-alqTV8Qt7TUbc74x1pKRLSENzfjp4nywovcJgi/1aXDiUxXdt7TkruSTF5MDWPP7UoPVgea4F9ghVdmX0xxnSA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash.set": "^4.3.2", + "propagate": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "requires": { + "clone": "2.x" + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } +} diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/package.json b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/package.json new file mode 100644 index 00000000..37309e5f --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/package.json @@ -0,0 +1,37 @@ +{ + "name": "api-builder-plugin-axway-api-management", + "version": "1.0.0", + "description": "A plugin for Axway API Builder", + "author": "", + "license": "ISC", + "keywords": [ + "amplify", + "api-builder" + ], + "engines": { + "node": ">= 12.15" + }, + "main": "src/index.js", + "files": [ + "src", + "README.md" + ], + "dependencies": { + "@axway/api-builder-sdk": "^1.0.0", + "node-cache": "^5.1.2" + }, + "peerDependencies": { + "@axway/api-builder-runtime": "^4.5.0" + }, + "devDependencies": { + "@axway/api-builder-test-utils": "^1.1.0", + "chai": "^4.1.2", + "dotenv": "^8.2.0", + "mocha": "^7.1.1", + "nock": "^13.0.4" + }, + "scripts": { + "test": "mocha ./test --recursive -R spec", + "postinstall": "node scripts/copyconf.js" + } +} diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/scripts/copyconf.js b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/scripts/copyconf.js new file mode 100644 index 00000000..75ad5fed --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/scripts/copyconf.js @@ -0,0 +1,62 @@ +#!/usr/bin/env node + +const path = require('path'); +const fs = require('fs'); +const chalk = require('chalk'); +const packageName = require('../package.json').name; +const { COPYFILE_EXCL } = fs.constants; +const projectDir = process.mainModule.paths[0].split('node_modules')[0].slice(0, -1); +const config = 'axway-api-utils.default.js'; +const srcConf = path.resolve(__dirname, '..', 'config', config); +const projConfDir = path.resolve(projectDir, 'conf'); +const projConf = path.resolve(projConfDir, config); + +// this makes sure it doesn't run on a dev npm install +if (process.env.NODE_ENV === 'production') { + process.exit(0); +} + +const banner = (titleColor, textColor, status, msg) => { + const width = process.stdout.columns, + border = '='.repeat(width), + title = `[${status.toUpperCase()}] ${packageName}:\n`; + + msg = msg || ''; + // eslint-disable-next-line no-console + console.log(chalk[titleColor](`\n${border}`)); + // eslint-disable-next-line no-console + console.log(chalk[titleColor].bold(title)); + // eslint-disable-next-line no-console + console.log(chalk[textColor](msg)); + // eslint-disable-next-line no-console + console.log(chalk[titleColor](`${border}\n`)); +}; + +const warn = (msg) => { + banner('yellow', 'yellow', 'warning', msg); +}; + +const info = (msg) => { + banner('green', 'white', 'info', msg); +}; + +const copyFile = (source, dest) => { + try { + fs.copyFileSync(source, dest, COPYFILE_EXCL); + } catch (e) { + throw new Error(`Unable to copy config file ${source} to ${dest}.\n\n${e.message || e}`); + } +}; + +try { + if (!fs.existsSync(projConfDir)) { + info(`conf directory not found in ${projectDir}. Are you in an API Builder project?`); + } else if (fs.existsSync(projConf)) { + info(`Connector configuration file already exists at ${projConf}.\nYou can find a copy of the default config at ${srcConf}`); + } else { + copyFile(srcConf, projConf); + info(`${config} has been copied to your API Builder conf directory. You must configure the file located in ${projConfDir}`); + } +} catch (e) { + warn(e.message); +} diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/actions.js b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/actions.js new file mode 100644 index 00000000..705bd341 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/actions.js @@ -0,0 +1,277 @@ +const https = require('https'); + +var pluginConfig = {}; +var cache = {}; +var logger; + +//process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; +/** + * Action method. + * + * @param {object} params - A map of all the parameters passed from the flow. + * @param {object} options - The additional options provided from the flow + * engine. + * @param {object} options.pluginConfig - The service configuration for this + * plugin from API Builder config.pluginConfig['api-builder-plugin-pluginName'] + * @param {object} options.logger - The API Builder logger which can be used + * to log messages to the console. When run in unit-tests, the messages are + * not logged. If you wish to test logging, you will need to create a + * mocked logger (e.g. using `simple-mock`) and override in + * `MockRuntime.loadPlugin`. For more information about the logger, see: + * https://docs.axway.com/bundle/API_Builder_4x_allOS_en/page/logging.html + * @param {*} [options.pluginContext] - The data provided by passing the + * context to `sdk.load(file, actions, { pluginContext })` in `getPlugin` + * in `index.js`. + * @return {*} The response value (resolves to "next" output, or if the method + * does not define "next", the first defined output). + */ +async function lookupCurrentUser(params, options) { + const { requestHeaders, apiManagerUserRequired } = params; + logger = options.logger; + cache = options.pluginContext.userCache; + pluginConfig = options.pluginConfig; + if (!requestHeaders) { + throw new Error('You must provide the requestHeaders originally sent to the ANM to this method.'); + } + if(!requestHeaders.cookie) { + throw new Error('The requestHeaders do not contain the cookie header.'); + } + const VIDUSR = _getCookie(requestHeaders.cookie, "VIDUSR"); + if(!VIDUSR) { + logger.trace(`Received cookies: ${requestHeaders.cookie}`); + throw new Error('The requestHeaders do not contain the required cookie VIDUSR'); + } + if(!requestHeaders['csrf-token']) { + logger.trace(`Received headers: ${requestHeaders}`); + throw new Error('The requestHeaders do not contain the required header csrf-token'); + } + if(cache.has(VIDUSR)) { + return cache.get(VIDUSR); + } + const user = {}; + logger.trace(`Trying to get current user based on VIDUSR: ${VIDUSR}`); + user.loginName = await _getCurrentGWUser(VIDUSR); + logger.trace(`Current user is: ${user.loginName}`); + user.gatewayManager = {isAdmin : false}; + var permissions = await _getCurrentGWPermissions(VIDUSR, requestHeaders['csrf-token'], loginName); + if(permissions.includes("adminusers_modify")) { + user.gatewayManager.isAdmin = true; + logger.debug(`Current user is: '${user.loginName}' Is Gateway admin: ${user.gatewayManager.isAdmin}`); + return user; + } + logger.trace(`Trying to load API-Manager user using Login-Name: '${user.loginName}'`); + const users = await _getManagerUser(user); + if(!users || users.length == 0) { + throw new Error(`User: '${user.loginName}' not found in API-Manager.`); + } + user.apiManager = users[0]; + var org = await _getOrganization(user.apiManager.organizationId); + user.apiManager.organizationName = org.name; + logger.debug(`User: '${user.loginName}' (Role: ${user.apiManager.role}) found in API-Manager. Organization: '${user.apiManager.organizationName}'`); + cache.set( VIDUSR, user); + return user; +} + +async function lookupAPIDetails(params, options) { + const { apiName, apiPath } = params; + cache = options.pluginContext.userCache; + pluginConfig = options.pluginConfig; + if (!apiName) { + throw new Error('You must provide the apiName that should be used to lookup the API.'); + } + if (!apiPath) { + throw new Error('You must provide the apiPath that should be used to lookup the API.'); + } + if(cache.has(apiPath)) { + return cache.get(apiPath); + } + const proxies = await _getAPIProxy(apiName); + if(!proxies || proxies.length == 0) { + throw new Error(`No APIs found with name: '${apiName}'`); + } + apiProxy = undefined; + for (i = 0; i < proxies.length; i++) { + api = proxies[i]; + if(apiPath.startsWith(api.path)) { + apiProxy = api; + } + } + if(!apiProxy) { + throw new Error(`No APIs found with name: '${apiName}' and apiPath: '${apiPath}'`); + } + var org = await _getOrganization(apiProxy.organizationId); + apiProxy.organizationName = org.name; + // Remove a few properties we really don't need + delete apiProxy.corsProfiles; + delete apiProxy.securityProfiles; + delete apiProxy.authenticationProfiles; + delete apiProxy.inboundProfiles; + delete apiProxy.outboundProfiles; + delete apiProxy.serviceProfiles; + delete apiProxy.caCerts; + if(cache.set(apiPath, apiProxy)); + return apiProxy; +} + +async function _getCurrentGWUser(VIDUSR) { + var options = { + path: '/api/rbac/currentuser', + headers: { + 'Cookie': `VIDUSR=${VIDUSR}` + }, + agent: new https.Agent({ rejectUnauthorized: false }) + }; + loginName = await sendRequest(pluginConfig.apigateway.url, options) + .then(response => { + return response.result; + }) + .catch(err => { + throw new Error(`Error getting current user Request sent to: '${pluginConfig.apigateway.hostname}'. ${err}`); + }); + return loginName; +} + +async function _getCurrentGWPermissions(VIDUSR, csrfToken, loginName) { + var options = { + path: '/api/rbac/permissions/currentuser', + headers: { + 'Cookie': `VIDUSR=${VIDUSR}`, + 'csrf-token': csrfToken + }, + agent: new https.Agent({ rejectUnauthorized: false }) + }; + result = await sendRequest(pluginConfig.apigateway.url, options) + .then(response => { + return response.result; + }) + .catch(err => { + throw new Error(err); + }); + if(result.user!=loginName) { + throw new Error(`Error reading current permissions from API-Gateway Manager. Loginname: ${loginName} does not match to retrieved user: ${result.user}.`); + } + return result.permissions; +} + +async function _getManagerUser(user) { + var options = { + path: `/api/portal/v1.3/users?field=loginName&op=eq&value=${user.loginName}&field=enabled&op=eq&value=enabled`, + headers: { + 'Authorization': 'Basic ' + Buffer.from(pluginConfig.apimanager.username + ':' + pluginConfig.apimanager.password).toString('base64') + }, + agent: new https.Agent({ rejectUnauthorized: false }) + }; + managerUser = await sendRequest(pluginConfig.apimanager.url, options) + .then(response => { + return response; + }) + .catch(err => { + throw new Error(err); + }); + return managerUser; +} + +async function _getAPIProxy(apiName) { + var options = { + path: `/api/portal/v1.3/proxies?field=name&op=eq&value=${apiName}`, + headers: { + 'Authorization': 'Basic ' + Buffer.from(pluginConfig.apimanager.username + ':' + pluginConfig.apimanager.password).toString('base64') + }, + agent: new https.Agent({ rejectUnauthorized: false }) + }; + apiProxy = await sendRequest(pluginConfig.apimanager.url, options) + .then(response => { + return response; + }) + .catch(err => { + throw new Error(`Error getting APIs with API-Name: ${apiName}. Request sent to: '${pluginConfig.apimanager.url}'. ${err}`); + }); + return apiProxy; +} + +async function sendRequest(url, options) { + return new Promise((resolve, reject) => { + try { + options.path = encodeURI(options.path); + var req = https.request(url, options, function (response) { + var chunks = []; + var statusCode = response.statusCode; + response.on("data", function (chunk) { + chunks.push(chunk); + }); + + response.on("end", function () { + var body = Buffer.concat(chunks); + if (statusCode < 200 || statusCode > 299) { + reject(`Unexpected response for HTTP-Request. Response-Code: ${statusCode}`); + return; + } + const userResponse = body.toString(); + if (!userResponse) { + resolve(userResponse); + return; + } + resolve(JSON.parse(userResponse)); + return; + }); + }); + req.on("error", function (error) { + reject(error); + return; + }); + req.end(); + } catch (ex) { + reject(ex); + } + }); +} + +function _getCookie(cookies, cookieName) { + const fields = cookies.split(";"); + for (var i = 0; i < fields.length; ++i) { + var cookie = fields[i].trim(); + const foundCookie = cookie.substring(0, cookie.indexOf("=")); + if(cookieName == foundCookie) { + return cookie.substring(cookie.indexOf("=")+1); + } + } + return; +} + +async function _getOrganization(orgId) { + if(cache.has(`ORG-${orgId}`)) { + var org = cache.get(`ORG-${orgId}`); + logger.debug(`Organization: '${org.name}' (ID: ${orgId}) found in cache.`); + return org; + } + var options = { + path: `/api/portal/v1.3/organizations/${orgId}`, + headers: { + 'Authorization': 'Basic ' + Buffer.from(pluginConfig.apimanager.username + ':' + pluginConfig.apimanager.password).toString('base64') + }, + agent: new https.Agent({ rejectUnauthorized: false }) + }; + org = await sendRequest(pluginConfig.apimanager.url, options) + .then(response => { + if(!response) { + throw new Error(`Organization with : '${orgId}' not found in API-Manager.`); + } + return response; + }) + .catch(err => { + throw new Error(err); + }); + if(!org.enabled) { + throw new Error(`Organization: '${org.name}' is disabled.`); + } + if(!org.development) { + throw new Error(`Organization: '${org.name}' is not a development organization.`); + } + cache.set(`ORG-${orgId}`, org) + return org; +} + +module.exports = { + lookupCurrentUser, + lookupAPIDetails +}; diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/axway-logo.png b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/axway-logo.png new file mode 100644 index 00000000..e4190821 Binary files /dev/null and b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/axway-logo.png differ diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/flow-nodes.yml b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/flow-nodes.yml new file mode 100644 index 00000000..448fc2e8 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/flow-nodes.yml @@ -0,0 +1,62 @@ +flow-nodes: + axway-api-management: + name: Axway API-Management Utils + icon: axway-logo.png + description: Flow providing utility functions related to the Axway-API-Management solution. As of today it can be used to lookup a user in API-Gateway Manager and API-Manager to get a union view. + category: general + methods: + lookupCurrentUser: + name: Lookup current user + description: Looks up the current user in Axway API-Gateway Manager and API-Manager based on the provided Request-Header that contains the session-cookie and CSRF-Token. + parameters: + requestHeaders: + name: Request Headers + description: The request headers are used to lookup the current users based on the current session cookie (VIDUSR). + required: true + initialType: string + schema: + type: string + outputs: + next: + name: Next + description: The user was found in API-Gateway and API-Manager. + context: $.user + schema: + type: object + error: + name: Error + description: An unexpected error happened + context: $.error + schema: + type: object + lookupAPIDetails: + name: Lookup API + description: Looks up the details of an API based on the given API-Name and API-Path + parameters: + apiName: + name: API-Name + description: Name of the API is primary used to lookup the API + required: true + initialType: string + schema: + type: string + apiPath: + name: Path of the API + description: This request path is used to double check that the API found is correct. + required: true + initialType: string + schema: + type: string + outputs: + next: + name: Next + description: The API-Proxy + context: $.api + schema: + type: object + error: + name: Error + description: An unexpected error happened + context: $.error + schema: + type: object \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/index.js b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/index.js new file mode 100644 index 00000000..2fd000b2 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/index.js @@ -0,0 +1,43 @@ +const path = require('path'); +const { SDK } = require('@axway/api-builder-sdk'); +const actions = require('./actions'); +const NodeCache = require( "node-cache" ); + +/** + * Resolves the API Builder plugin. + * @param {object} pluginConfig - The service configuration for this plugin + * from API Builder config.pluginConfig['api-builder-plugin-pluginName'] + * @param {string} pluginConfig.proxy - The configured API-builder proxy server + * @param {object} options - Additional options and configuration provided by API Builder + * @param {string} options.appDir - The current directory of the service using the plugin + * @param {string} options.logger - An API Builder logger scoped for this plugin + * @returns {object} An API Builder plugin. + */ +async function getPlugin(pluginConfig, options) { + const userCache = new NodeCache({ stdTTL: 3600, useClones: false }); + const sdk = new SDK({ pluginConfig }); + if(!pluginConfig.apigateway) { + throw new Error(`API-Gateway (apigateway) paramater section is missing in configuration`); + } + if(!pluginConfig.apimanager) { + throw new Error(`API-Manager (apimanager) paramater section is missing in configuration`); + } + if(!pluginConfig.apigateway.url) { + throw new Error(`Required parameter: apigateway.url is not set.`); + } + if(!pluginConfig.apimanager.url) { + const managerURL = new URL(pluginConfig.apigateway.url); + managerURL.port = 8075; + pluginConfig.apimanager.url = managerURL.toString(); + } + if(!pluginConfig.apimanager.username) { + throw new Error(`Required parameter: apimanager.username is not set.`) + } + if(!pluginConfig.apimanager.password) { + throw new Error(`Required parameter: apimanager.password is not set.`) + } + sdk.load(path.resolve(__dirname, 'flow-nodes.yml'), actions, { pluginContext: { userCache: userCache }, pluginConfig}); + return sdk.getPlugin(); +} + +module.exports = getPlugin; \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/.env b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/.env new file mode 100644 index 00000000..077c86f5 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/.env @@ -0,0 +1,8 @@ +# When using hostname mocked-api-gateway all requested are mocked when running tests. +API_MANAGER=https://mocked-api-gateway:8175 +API_MANAGER_USERNAME=apiadmin +API_MANAGER_PASSWORD=changeme + +ADMIN_NODE_MANAGER=https://mocked-api-gateway:8190 +API_GATEWAY_USERNAME=apiadmin +API_GATEWAY_PASSWORD=changeme \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/test-apilookup.js b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/test-apilookup.js new file mode 100644 index 00000000..474b4ad3 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/test-apilookup.js @@ -0,0 +1,121 @@ +const { expect } = require('chai'); +const { MockRuntime } = require('@axway/api-builder-test-utils'); +const getPlugin = require('../src'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); + +describe('Test API Lookup', () => { + let plugin; + let flowNode; + + // Loads environment variables from .env if the file exists + const envFilePath = path.join(__dirname, '.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } + var pluginConfig = require('../config/axway-api-utils.default.js').pluginConfig['api-builder-plugin-axway-api-management']; + + beforeEach(async () => { + plugin = await MockRuntime.loadPlugin(getPlugin,pluginConfig); + plugin.setOptions({ validateOutputs: true }); + flowNode = plugin.getFlowNode('axway-api-management'); + }); + + describe('#constructor apilookup', () => { + it('should define flow-nodes', () => { + expect(plugin).to.be.a('object'); + expect(plugin.getFlowNodeIds()).to.deep.equal([ + 'axway-api-management' + ]); + expect(flowNode).to.be.a('object'); + + // Ensure the flow-node matches the spec + expect(flowNode.name).to.equal('Axway API-Management Utils'); + expect(flowNode.icon).to.be.a('string'); + expect(flowNode.getMethods()).to.deep.equal([ + 'lookupAPIDetails', + 'lookupCurrentUser' + ]); + }); + + it('should define valid flow-nodes', () => { + plugin.validate(); + }); + }); + + describe('#lookupAPIDetails', () => { + it('should error when API-Name is not set', async () => { + const { value, output } = await flowNode.lookupAPIDetails({ + apiName: null + }); + + expect(value).to.be.instanceOf(Error) + .and.to.have.property('message', 'You must provide the apiName that should be used to lookup the API.'); + expect(output).to.equal('error'); + }); + + it('should error when API-Path is not set', async () => { + const { value, output } = await flowNode.lookupAPIDetails({ + apiName: 'My great API', apiPath: null + }); + + expect(value).to.be.instanceOf(Error) + .and.to.have.property('message', 'You must provide the apiPath that should be used to lookup the API.'); + expect(output).to.equal('error'); + }); + + it('should follow the Error path if the API-Manager host cannot be reached/communicated', async () => { + // We just have NO mock to make this test + const { value, output } = await flowNode.lookupAPIDetails({ + apiName: 'Unknown API', apiPath: '/v1/unkownAPI' + }); + + expect(value).to.be.instanceOf(Error); + expect(value.message).to.have.string(`Error getting APIs with API-Name: Unknown API. Request sent to: 'https://mocked-api-gateway:8175'. Error: getaddrinfo`); + expect(output).to.equal('error'); + }); + + it('should error with an unknown API', async () => { + nock('https://mocked-api-gateway:8175').get('/api/portal/v1.3/proxies?field=name&op=eq&value=Unknown API').reply(200, '[]'); + const { value, output } = await flowNode.lookupAPIDetails({ + apiName: 'Unknown API', apiPath: '/v1/unkownAPI' + }); + + expect(value).to.be.instanceOf(Error); + expect(value.message).to.equal(`No APIs found with name: 'Unknown API'`); + expect(output).to.equal('error'); + }); + + it('should error if the API-Name is found, but the API-Path doesnt match', async () => { + nock('https://mocked-api-gateway:8175').get('/api/portal/v1.3/proxies?field=name&op=eq&value=Petstore HTTPS').replyWithFile(200, './test/testReplies/apimanager/apiProxyFound.json'); + const { value, output } = await flowNode.lookupAPIDetails({ + apiName: 'Petstore HTTPS', apiPath: '/v1/wrong' + }); + + expect(value).to.be.instanceOf(Error); + expect(value.message).to.have.string(`No APIs found with name: 'Petstore HTTPS' and apiPath: '/v1/wrong'`); + expect(output).to.equal('error'); + }); + + it('should return the resolved API proxy details (cache is tested as well)', async () => { + nock('https://mocked-api-gateway:8175').get('/api/portal/v1.3/proxies?field=name&op=eq&value=Petstore HTTPS').replyWithFile(200, './test/testReplies/apimanager/apiProxyFound.json'); + nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/organizations/439ec2bd-0350-459c-8df3-bb6d14da6bc8`).replyWithFile(200, './test/testReplies/apimanager/organizationAPIDevelopment.json'); + + const { value, output } = await flowNode.lookupAPIDetails({ + apiName: 'Petstore HTTPS', apiPath: '/v1/petstore' + }); + expect(value.organizationName).to.equal(`API Development`); + expect(value.name).to.equal(`Petstore HTTPS`); + expect(value.path).to.equal(`/v1/petstore`); + expect(output).to.equal('next'); + // Make sure the result is cached + nock.cleanAll(); + // This re-run should be delivered out of the cache + await flowNode.lookupAPIDetails({ + apiPath: '/v1/petstore' + }); + }); + }); +}); diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/test-userlookup.js b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/test-userlookup.js new file mode 100644 index 00000000..c3c287a0 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/test-userlookup.js @@ -0,0 +1,305 @@ +const { expect } = require('chai'); +const { MockRuntime } = require('@axway/api-builder-test-utils'); +const getPlugin = require('../src'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); + +describe('Configuration parameter tests', () => { + + var pluginConfig = {}; + + describe('#Missing config parameter tests', () => { + it('should error when API-Gateway parameters are missing at all', async () => { + try { + const plugin = await MockRuntime.loadPlugin(getPlugin,pluginConfig); + } catch(e) { + expect(e).to.be.an('Error') + .and.to.have.property('message', 'API-Gateway (apigateway) paramater section is missing in configuration'); + } + }); + it('should error when API-Manager parameters are missing at all', async () => { + try { + pluginConfig.apigateway = {}; + expect(await MockRuntime.loadPlugin(getPlugin,pluginConfig)).to.throw('API-Manager (apimanager) paramater section is missing in configuration'); + } catch(e) { + expect(e).to.be.an('Error') + .and.to.have.property('message', 'API-Manager (apimanager) paramater section is missing in configuration'); + } + }); + it('should error when API-Gateway URL is missing', async () => { + try { + pluginConfig.apimanager = {}; + pluginConfig.apigateway = {}; + const plugin = await MockRuntime.loadPlugin(getPlugin,pluginConfig); + } catch(e) { + expect(e).to.be.an('Error') + .and.to.have.property('message', 'Required parameter: apigateway.url is not set.'); + } + }); + it('should error when API-Manager username is not set', async () => { + try { + pluginConfig.apimanager = {}; + pluginConfig.apigateway = {}; + pluginConfig.apigateway.url = "https://api-gateway-host:8090"; + const plugin = await MockRuntime.loadPlugin(getPlugin,pluginConfig); + } catch(e) { + expect(e).to.be.an('Error') + .and.to.have.property('message', 'Required parameter: apimanager.username is not set.'); + } + }); + it('should error when API-Manager password is not set', async () => { + try { + pluginConfig.apimanager = {}; + pluginConfig.apigateway = {}; + pluginConfig.apigateway.url = "https://api-gateway-host:8090"; + pluginConfig.apimanager.username = "apiadmin"; + const plugin = await MockRuntime.loadPlugin(getPlugin,pluginConfig); + } catch(e) { + expect(e).to.be.an('Error') + .and.to.have.property('message', 'Required parameter: apimanager.password is not set.'); + } + }); + it('should NOT FAIL when API-Manager URL is not set', async () => { + pluginConfig.apimanager = {}; + pluginConfig.apigateway = {}; + pluginConfig.apigateway.url = "https://any-gateway-host:8090"; + pluginConfig.apimanager.username = "apiadmin"; + pluginConfig.apimanager.password = "changeme"; + plugin = await MockRuntime.loadPlugin(getPlugin,pluginConfig); + plugin.setOptions({ validateOutputs: true }); + flowNode = plugin.getFlowNode('axway-api-management'); + expect(pluginConfig.apimanager.hostname).to.equal(pluginConfig.apigateway.hostname); + }); + }); +}); + +describe('Tests with complete configuration parameters', () => { + let plugin; + let flowNode; + + const enabledField = "&field=enabled&op=eq&value=enabled"; + + // Loads environment variables from .env if the file exists + const envFilePath = path.join(__dirname, '.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } + var pluginConfig = require('../config/axway-api-utils.default.js').pluginConfig['api-builder-plugin-axway-api-management']; + + beforeEach(async () => { + plugin = await MockRuntime.loadPlugin(getPlugin,pluginConfig); + plugin.setOptions({ validateOutputs: true }); + flowNode = plugin.getFlowNode('axway-api-management'); + }); + + describe('#constructor lookupCurrentUser', () => { + it('should define flow-nodes', () => { + expect(plugin).to.be.a('object'); + expect(plugin.getFlowNodeIds()).to.deep.equal([ + 'axway-api-management' + ]); + expect(flowNode).to.be.a('object'); + + // Ensure the flow-node matches the spec + expect(flowNode.name).to.equal('Axway API-Management Utils'); + expect(flowNode.icon).to.be.a('string'); + expect(flowNode.getMethods()).to.deep.equal([ + 'lookupAPIDetails', + 'lookupCurrentUser' + ]); + }); + + it('should define valid flow-nodes', () => { + plugin.validate(); + }); + }); + + describe('#lookupCurrentUser', () => { + it('should error when requestHeaders are not set', async () => { + const { value, output } = await flowNode.lookupCurrentUser({ + requestHeaders: null + }); + + expect(value).to.be.instanceOf(Error) + .and.to.have.property('message', 'You must provide the requestHeaders originally sent to the ANM to this method.'); + expect(output).to.equal('error'); + }); + + it('should error when requestHeaders are set, but contain no cookie header', async () => { + const { value, output } = await flowNode.lookupCurrentUser({ + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20"} + }); + + expect(value).to.be.instanceOf(Error) + .and.to.have.property('message', 'The requestHeaders do not contain the cookie header.'); + expect(output).to.equal('error'); + }); + + it('should error when requestHeaders are set, but the VIDUSR cookie is missing', async () => { + const { value, output } = await flowNode.lookupCurrentUser({ + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"XXX-VIDUSR=1597381095-XTawGDtJhBA7Zw%3d%3d;"} + }); + + expect(value).to.be.instanceOf(Error) + .and.to.have.property('message', 'The requestHeaders do not contain the required cookie VIDUSR'); + expect(output).to.equal('error'); + }); + + it('should error when requestHeaders are set, but the CSRF-Token is missing', async () => { + const { value, output } = await flowNode.lookupCurrentUser({ + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"VIDUSR=1597381095-XTawGDtJhBA7Zw%3d%3d;"} + }); + + expect(value).to.be.instanceOf(Error) + .and.to.have.property('message', 'The requestHeaders do not contain the required header csrf-token'); + expect(output).to.equal('error'); + }); + + it('should error with an invalid Cookie', async () => { + nock('https://mocked-api-gateway:8190').get('/api/rbac/currentuser').replyWithFile(403, './test/testReplies/gateway/unknownSessionCookie.txt', { + 'Content-Type': 'text/html', + }); + const { value, output } = await flowNode.lookupCurrentUser({ + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"VIDUSR=has-expired-cookie;", "csrf-token": "436386FFE9196A8A4A8211992240639DBF65A4BC13549BC7777F2D2DB9BE7F0B"} + }); + + expect(value).to.be.instanceOf(Error); + expect(value.message).to.have.string('Unexpected response for HTTP-Request. Response-Code: 403'); + expect(output).to.equal('error'); + }); + + it('should error with if user does not exists in the API-Manager', async () => { + nock('https://mocked-api-gateway:8190').get('/api/rbac/currentuser').reply(200, {"result": "chris"}); + nock('https://mocked-api-gateway:8190').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/testReplies/gateway/operatorRoleOnlyPermissions.json'); + nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=chris${enabledField}`).reply(200, [] ); + const { value, output } = await flowNode.lookupCurrentUser({ + // Let's assume this cookie resolves to username admin - which is unknown in the API-Manager + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"VIDUSR=1597404606-ZQr/l9c2HvlhtA==;", "csrf-token": "CF2796B3BD18C1B0B5AB1C8E95B75662E92FBC04BD799DEB97838FC5B9C39348"} + }); + + expect(value).to.be.instanceOf(Error) + .and.to.have.property('message', 'User: \'chris\' not found in API-Manager.'); + expect(output).to.equal('error'); + }); + + it('should result into an API-Gateway Admin-User (based on permission: adminusers_modify), which requires no lookup to the API-Manager', async () => { + nock('https://mocked-api-gateway:8190').get('/api/rbac/currentuser').reply(200, { "result": "gwadmin" }); + nock('https://mocked-api-gateway:8190').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/testReplies/gateway/gatewayAdminOnlyPermissions.json'); + + const { value, output } = await flowNode.lookupCurrentUser({ + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"VIDUSR=1597381095-XTawGDtJhBA7Zw==;", "csrf-token": "CF2796B3BD18C1B0B5AB1C8E95B75662E92FBC04BD799DEB97838FC5B9C39348"} + }); + + expect(value).to.deep.equal({ + "loginName": "gwadmin", + "gatewayManager": { + "isAdmin": true + } + }); + expect(output).to.equal('next'); + }); + + it('should result into a standard API-Gateway User (NOT HAVING permission: adminusers_modify), which requires user lookup to the API-Manager', async () => { + nock('https://mocked-api-gateway:8190').get('/api/rbac/currentuser').reply(200, { "result": "chris" }); + nock('https://mocked-api-gateway:8190').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/testReplies/gateway/operatorRoleOnlyPermissions.json'); + nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=chris${enabledField}`).replyWithFile(200, './test/testReplies/apimanager/apiManagerUserChris.json'); + nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-f833ca1c0a74`).replyWithFile(200, './test/testReplies/apimanager/organizationAPIDevelopment.json'); + + const { value, output } = await flowNode.lookupCurrentUser({ + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"VIDUSR=1597381095-XTawGDtJhBA7Zw==;", "csrf-token": "CF2796B3BD18C1B0B5AB1C8E95B75662E92FBC04BD799DEB97838FC5B9C39348"} + }); + + expect(value).to.deep.equal({ + "loginName": "chris", + "gatewayManager": { + "isAdmin": false + }, + "apiManager": { + "id": "d66a42d6-b9c7-4efd-b33a-de8b88545861", + "organizationId": "2bfaa1c2-49ab-4059-832d-f833ca1c0a74", + "organizationName": "API Development", + "name": "Chris", + "loginName": "chris", + "email": "chris@axway.com", + "role": "oadmin", + "enabled": true, + "createdOn": 1597338071490, + "state": "approved", + "type": "internal", + "dn": "cn=chris,o=API Development,ou=organizations,ou=APIPortal" + } + }); + expect(output).to.equal('next'); + }); + + it('should should cache the result', async () => { + nock('https://mocked-api-gateway:8190').get('/api/rbac/currentuser').reply(200, { "result": "chris" }); + nock('https://mocked-api-gateway:8190').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/testReplies/gateway/operatorRoleOnlyPermissions.json'); + nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=chris${enabledField}`).replyWithFile(200, './test/testReplies/apimanager/apiManagerUserChris.json'); + nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-f833ca1c0a74`).replyWithFile(200, './test/testReplies/apimanager/organizationAPIDevelopment.json'); + + const { value, output } = await flowNode.lookupCurrentUser({ + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"VIDUSR=1597381095-XTawGDtJhBA7Zw==;", "csrf-token": "CF2796B3BD18C1B0B5AB1C8E95B75662E92FBC04BD799DEB97838FC5B9C39348"} + }); + + expect(value).to.deep.equal({ + "loginName": "chris", + "gatewayManager": { + "isAdmin": false + }, + "apiManager": { + "id": "d66a42d6-b9c7-4efd-b33a-de8b88545861", + "organizationId": "2bfaa1c2-49ab-4059-832d-f833ca1c0a74", + "organizationName": "API Development", + "name": "Chris", + "loginName": "chris", + "email": "chris@axway.com", + "role": "oadmin", + "enabled": true, + "createdOn": 1597338071490, + "state": "approved", + "type": "internal", + "dn": "cn=chris,o=API Development,ou=organizations,ou=APIPortal" + } + }); + expect(output).to.equal('next'); + + nock.cleanAll(); + await flowNode.lookupCurrentUser({ + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"VIDUSR=1597381095-XTawGDtJhBA7Zw==;", "csrf-token": "CF2796B3BD18C1B0B5AB1C8E95B75662E92FBC04BD799DEB97838FC5B9C39348"} + }); + }); + + it('should error if belonging organization is disabled', async () => { + nock('https://mocked-api-gateway:8190').get('/api/rbac/currentuser').reply(200, { "result": "chris" }); + nock('https://mocked-api-gateway:8190').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/testReplies/gateway/operatorRoleOnlyPermissions.json'); + nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=chris${enabledField}`).replyWithFile(200, './test/testReplies/apimanager/apiManagerUserChris.json'); + nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-f833ca1c0a74`).replyWithFile(200, './test/testReplies/apimanager/disabledOrganization.json'); + + const { value, output } = await flowNode.lookupCurrentUser({ + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"VIDUSR=1597381095-XTawGDtJhBA7Zw==;", "csrf-token": "CF2796B3BD18C1B0B5AB1C8E95B75662E92FBC04BD799DEB97838FC5B9C39348"} + }); + + expect(value).to.be.instanceOf(Error) + .and.to.have.property('message', 'Organization: \'API Development\' is disabled.'); + expect(output).to.equal('error'); + }); + + it('should error if belonging organization has no development flag', async () => { + nock('https://mocked-api-gateway:8190').get('/api/rbac/currentuser').reply(200, { "result": "chris" }); + nock('https://mocked-api-gateway:8190').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/testReplies/gateway/operatorRoleOnlyPermissions.json'); + nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=chris${enabledField}`).replyWithFile(200, './test/testReplies/apimanager/apiManagerUserChris.json'); + nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-f833ca1c0a74`).replyWithFile(200, './test/testReplies/apimanager/noDevelopmentOrg.json'); + + const { value, output } = await flowNode.lookupCurrentUser({ + requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"VIDUSR=1597381095-XTawGDtJhBA7Zw==;", "csrf-token": "CF2796B3BD18C1B0B5AB1C8E95B75662E92FBC04BD799DEB97838FC5B9C39348"} + }); + + expect(value).to.be.instanceOf(Error) + .and.to.have.property('message', 'Organization: \'API Development\' is not a development organization.'); + expect(output).to.equal('error'); + }); + }); +}); diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/apiManagerUserChris.json b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/apiManagerUserChris.json new file mode 100644 index 00000000..67df941c --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/apiManagerUserChris.json @@ -0,0 +1,15 @@ +[ + { + "id": "d66a42d6-b9c7-4efd-b33a-de8b88545861", + "organizationId": "2bfaa1c2-49ab-4059-832d-f833ca1c0a74", + "name": "Chris", + "loginName": "chris", + "email": "chris@axway.com", + "role": "oadmin", + "enabled": true, + "createdOn": 1597338071490, + "state": "approved", + "type": "internal", + "dn": "cn=chris,o=API Development,ou=organizations,ou=APIPortal" + } +] \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/apiProxyFound.json b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/apiProxyFound.json new file mode 100644 index 00000000..9c50de3f --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/apiProxyFound.json @@ -0,0 +1,166 @@ +[ + { + "id": "55a27047-a9dc-4d43-ad11-2cbf7a239f8a", + "organizationId": "439ec2bd-0350-459c-8df3-bb6d14da6bc8", + "apiId": "06c58f1c-3f43-40e0-b752-63b6dd2f7d1c", + "name": "Petstore HTTPS", + "version": "1.0.5", + "apiRoutingKey": null, + "vhost": null, + "path": "/v1/petstore", + "descriptionType": "original", + "descriptionManual": null, + "descriptionMarkdown": null, + "descriptionUrl": null, + "summary": null, + "retired": false, + "expired": false, + "image": null, + "retirementDate": 0, + "deprecated": false, + "state": "published", + "createdOn": 1597676259637, + "createdBy": "f60e3e05-cdf3-4b70-affc-4cb61a10f4bb", + "corsProfiles": [ + { + "name": "_default", + "isDefault": true, + "origins": [ + "*" + ], + "allowedHeaders": [], + "exposedHeaders": [ + "X-CorrelationID" + ], + "supportCredentials": false, + "maxAgeSeconds": 0 + } + ], + "securityProfiles": [ + { + "name": "_default", + "isDefault": true, + "devices": [ + { + "name": "API Key", + "type": "apiKey", + "order": 1, + "properties": { + "apiKeyFieldName": "KeyId", + "takeFrom": "HEADER", + "removeCredentialsOnSuccess": "true" + } + } + ] + } + ], + "authenticationProfiles": [ + { + "name": "_default", + "isDefault": true, + "parameters": { + "_id_": 0 + }, + "type": "none" + } + ], + "inboundProfiles": { + "_default": { + "securityProfile": "_default", + "corsProfile": "_default", + "monitorAPI": true, + "monitorSubject": "authentication.subject.id" + } + }, + "outboundProfiles": { + "_default": { + "authenticationProfile": "_default", + "routeType": "proxy", + "requestPolicy": null, + "responsePolicy": null, + "routePolicy": null, + "faultHandlerPolicy": null, + "apiId": null, + "apiMethodId": null, + "parameters": [] + } + }, + "serviceProfiles": { + "_default": { + "apiId": "06c58f1c-3f43-40e0-b752-63b6dd2f7d1c", + "basePath": "https://petstore.swagger.io" + } + }, + "caCerts": [ + { + "certBlob": "MIIFYDCCBEigAwIBAgIQBHaGXD1xHK+7DIzsNpFHkjANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2ZXIgQ0EgMUIxDzANBgNVBAMTBkFtYXpvbjAeFw0yMDA0MTUwMDAwMDBaFw0yMTA1MTUxMjAwMDBaMBcxFTATBgNVBAMMDCouc3dhZ2dlci5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANASN8RW6mBBxfSnwbQOANV2MbRtXYFj+RcZTCeN2GrltOKfhfpI89KNXVmHkqhUjC9FyS9XVQC5XsUGuR2BiCwYDpd13pgFqp0jQDv95IosqPLILQJZVoKerB5xsetRAA/5HYh2EKptJnPkjvj0ZDeNOW32IVzNEG+KZEwnJ0DXp7PQqJrkEmsLfbB413ZJXFFlMgGTP98nfzLewuS3AwlF96Il0BMyFa3UGAvB6LVEauqy7nxxMNmv/vKfA9fi+j7Q9heQCzihal9xUzgh1xSeu5V8M862wHNNkyDDzCYJ3aqGfUF22nnDju4U/+UhLQdshpb4qgb/skfrA3wFKvkCAwEAAaOCAncwggJzMB8GA1UdIwQYMBaAFFmkZgZSoHuVkjyjlAcnlnRb+T3QMB0GA1UdDgQWBBS8ra9FacL0+YDHMzSNEA0IhrYZzDAXBgNVHREEEDAOggwqLnN3YWdnZXIuaW8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3JsLnNjYTFiLmFtYXpvbnRydXN0LmNvbS9zY2ExYi5jcmwwIAYDVR0gBBkwFzALBglghkgBhv1sAQIwCAYGZ4EMAQIBMHUGCCsGAQUFBwEBBGkwZzAtBggrBgEFBQcwAYYhaHR0cDovL29jc3Auc2NhMWIuYW1hem9udHJ1c3QuY29tMDYGCCsGAQUFBzAChipodHRwOi8vY3J0LnNjYTFiLmFtYXpvbnRydXN0LmNvbS9zY2ExYi5jcnQwDAYDVR0TAQH/BAIwADCCAQMGCisGAQQB1nkCBAIEgfQEgfEA7wB2APZclC/RdzAiFFQYCDCUVo7jTRMZM7/fDC8gC8xO8WTjAAABcXtMbIsAAAQDAEcwRQIgaRRwZ/FIuyRHVCa3nK8Ype9EIQNgvFsSnSiYmU3RE6wCIQCQ7ZZkTIW845VmjBJbj46tiGSkG0MzuCiSCPTws6GILQB1AFzcQ5L+5qtFRLFemtRW5hA3+9X6R9yhc5SyXub2xw7KAAABcXtMbLgAAAQDAEYwRAIgfuJGxXn/P2jCCcQS/Z3R2M8u1CV69urvEVQmlnILZJMCIAbd8o82SzcZnzKVYF653+CVH+N6GX2DmwMJ3b81H+MPMA0GCSqGSIb3DQEBCwUAA4IBAQABHMtwCTgDX/RfNwFgCg1Gveq1ut1jVg7jvagglF5keEhDWOVNrRbEuODPf3YmiFsXwngxn5ng7fZdi/xRSRqN4uQqc8KykGgFe7LX+SgcHGkjqfUJ5JbiW0D9Jtw5MDZpBvevBr31gW253V0mL4yAlwBy8F0X0Ny4NJJSkovwLYprM4aglEOpSQvW45pOWccGAvkgayW8zBBIrj7B2jSjBtCdjO1SeMQNLmkErz7/aCnsRSC+Kaw2kfiIrRtwDEuKCa2IgemmlUA1xvIR1GrRwz05QZlCuae6/uvvaqotFWCxdnNtnbUu13Hb7KPCcy742yODpso0R7RAGzFA6Kgo", + "name": "CN=*.swagger.io", + "alias": "CN=*.swagger.io", + "subject": "CN=*.swagger.io", + "issuer": "CN=Amazon, OU=Server CA 1B, O=Amazon, C=US", + "version": 3, + "notValidBefore": 1586908800000, + "notValidAfter": 1621080000000, + "signatureAlgorithm": "RSA (2048 bits)", + "sha1Fingerprint": "2E:40:92:83:A6:F5:FC:C1:1D:F3:18:3B:7A:08:0E:CA:04:72:53:B6", + "md5Fingerprint": "81:AD:AF:05:B1:39:ED:FF:BE:EE:79:94:28:B3:F2:10", + "expired": false, + "notYetValid": false, + "inbound": false, + "outbound": true + }, + { + "certBlob": "MIIESTCCAzGgAwIBAgITBn+UV4WH6Kx33rJTMlu8mYtWDTANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENBIDFCMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCThZn3c68asg3Wuw6MLAd5tES6BIoSMzoKcG5blPVo+sDORrMd4f2AbnZcMzPa43j4wNxhplty6aUKk4T1qe9BOwKFjwK6zmxxLVYo7bHViXsPlJ6qOMpFge5blDP+18x+B26A0piiQOuPkfyDyeR4xQghfj66Yo19V+emU3nazfvpFA+ROz6WoVmB5x+F2pV8xeKNR7u6azDdU5YVX1TawprmxRC1+WsAYmz6qP+z8ArDITC2FMVy2fw0IjKOtEXc/VfmtTFch5+AfGYMGMqqvJ6LcXiAhqG5TI+Dr0RtM88k+8XUBCeQ8IGKuANaL7TiItKZYxK1MMuTJtV9IblAgMBAAGjggE7MIIBNzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUWaRmBlKge5WSPKOUByeWdFv5PdAwHwYDVR0jBBgwFoAUhBjMhTTsvAyUlC4IWZzHshBOCggwewYIKwYBBQUHAQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5yb290Y2ExLmFtYXpvbnRydXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NydC5yb290Y2ExLmFtYXpvbnRydXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY3JsMBMGA1UdIAQMMAowCAYGZ4EMAQIBMA0GCSqGSIb3DQEBCwUAA4IBAQCFkr41u3nPo4FCHOTjY3NTOVI159Gt/a6ZiqyJEi+752+a1U5y6iAwYfmXss2lJwJFqMp2PphKg5625kXg8kP2CN5t6G7bMQcT8C8xDZNtYTd7WPD8UZiRKAJPBXa30/AbwuZe0GaFEQ8ugcYQgSn+IGBI8/LwhBNTZTUVEWuCUUBVV18YtbAiPq3yXqMB48Oz+ctBWuZSkbvkNodPLamkB2g1upRyzQ7qDn1X8nn8N8V7YJ6y68AtkHcNSRAnpTitxBKjtKPISLMVCx7i4hncxHZSyLyKQXhw2W2Xs0qLeC1etA+jTGDK4UfLeC0SF7FSi8o5LL21L8IzApar2pR/", + "name": "CN=Amazon, OU=Server CA 1B, O=Amazon, C=US", + "alias": "CN=Amazon, OU=Server CA 1B, O=Amazon, C=US", + "subject": "CN=Amazon, OU=Server CA 1B, O=Amazon, C=US", + "issuer": "CN=Amazon Root CA 1, O=Amazon, C=US", + "version": 3, + "notValidBefore": 1445472000000, + "notValidAfter": 1760832000000, + "signatureAlgorithm": "RSA (2048 bits)", + "sha1Fingerprint": "91:7E:73:2D:33:0F:9A:12:40:4F:73:D8:BE:A3:69:48:B9:29:DF:FC", + "md5Fingerprint": "EB:26:8E:55:D4:34:FE:BD:A3:6A:97:9A:44:65:4B:6D", + "expired": false, + "notYetValid": false, + "inbound": false, + "outbound": true + }, + { + "certBlob": "MIIEkjCCA3qgAwIBAgITBn+USionzfP6wq4rAfkI7rnExjANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTE1MDUyNTEyMDAwMFoXDTM3MTIzMTAxMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaOCATEwggEtMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSEGMyFNOy8DJSULghZnMeyEE4KCDAfBgNVHSMEGDAWgBScXwDfqgHXMCs4iKK4bUqc8hGRgzB4BggrBgEFBQcBAQRsMGowLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLnJvb3RnMi5hbWF6b250cnVzdC5jb20wOAYIKwYBBQUHMAKGLGh0dHA6Ly9jcnQucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY2VyMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQsFAAOCAQEAYjdCXLwQtT6LLOkMm2xF4gcAevnFWAu5CIw+7bMlPLVvUOTNNWqnkzSWMiGpSESrnO09tKpzbeR/FoCJbM8oAxiDR3mjEH4wW6w7sGDgd9QIpuEdfF7Au/maeyKdpwAJfqxGF4PcnCZXmTA5YpaP7dreqsXMGz7KQ2hsVxa81Q4gLv7/wmpdLqBKbRRYh5TmOTFffHPLkIhqhBGWJ6bt2YFGpn6jcgAKUj6DiAdjd4lpFw85hdKrCEVN0FE6/V1dN2RMfjCyVSRCnTawXZwXgWHxyvkQAiSr6w10kY17RSlQOYiypok1JR4UakcjMS9cmvqtmg5iUaQqqcT5NJ0hGA==", + "name": "CN=Amazon Root CA 1, O=Amazon, C=US", + "alias": "CN=Amazon Root CA 1, O=Amazon, C=US", + "subject": "CN=Amazon Root CA 1, O=Amazon, C=US", + "issuer": "CN=Starfield Services Root Certificate Authority - G2, O=\"Starfield Technologies, Inc.\", L=Scottsdale, ST=Arizona, C=US", + "version": 3, + "notValidBefore": 1432555200000, + "notValidAfter": 2145834000000, + "signatureAlgorithm": "RSA (2048 bits)", + "sha1Fingerprint": "06:B2:59:27:C4:2A:72:16:31:C1:EF:D9:43:1E:64:8F:A6:2E:1E:39", + "md5Fingerprint": "E8:65:A2:2A:AE:52:4D:26:86:9A:F0:44:8D:6F:D8:96", + "expired": false, + "notYetValid": false, + "inbound": false, + "outbound": true + }, + { + "certBlob": "MIIEdTCCA12gAwIBAgIJAKcOSkw0grd/MA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wOTA5MDIwMDAwMDBaFw0zNDA2MjgxNzM5MTZaMIGYMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZpZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVDDrEKvlO4vW+GZdfjohTsR8/y8+fIBNtKTrID30892t2OGPZNmCom15cAICyL1l/9of5JUOG52kbUpqQ4XHj2C0NTm/2yEnZtvMaVq4rtnQU68/7JuMauh2WLmo7WJSJR1b/JaCTcFOD2oR0FMNnngRoOt+OQFodSk7PQ5E751bWAHDLUu57fa4657wx+UX2wmDPE1kCK4DMNEffud6QZW0CzyyRpqbn3oUYSXxmTqM6bam17jQuug0DuDPfR+uxa40l2ZvOgdFFRjKWcIfeAg5JQ4W2bHO7ZOphQazJ1FTfhy/HIrImzJ9ZVGif/L4qL8RVHHVAYBeFAlU5i38FAgMBAAGjgfAwge0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMB8GA1UdIwQYMBaAFL9ft9HO3R+G9FtVrNzXEMIOqYjnME8GCCsGAQUFBwEBBEMwQTAcBggrBgEFBQcwAYYQaHR0cDovL28uc3MyLnVzLzAhBggrBgEFBQcwAoYVaHR0cDovL3guc3MyLnVzL3guY2VyMCYGA1UdHwQfMB0wG6AZoBeGFWh0dHA6Ly9zLnNzMi51cy9yLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBACMd44pXyn3pF3lM8R5V/cxTbj5HD9/GVfKyBDbtgB9TxF00KGu+x1X8Z+rLP3+QsjPNG1gQggL4+C/1E2DUBc7xgQjB3ad1l08YuW3e95ORCLp+QCztweq7dp4zBncdDQh/U90bZKuCJ/Fp1U1ervShw3WnWEQt8jxwmKy6abaVd38PMV4s/KCHOkdp8Hlf9BRUpJVeEXgSYCfOn8J3/yNTd126/+pZ59vPr5KW7ySaNRB6nJHGDn2Z9j8Z3/VyVOEVqQdZe4O/Ui5GjLIAZHYcSNPYeehuVsyuLAOQ1xk4meTKCRlb/weWsKh/NEnfVqn3sF/tM+2MR7cwA130A4w=", + "name": "CN=Starfield Services Root Certificate Authority - G2, O=\"Starfield Technologies, Inc.\", L=Scottsdale, ST=Arizona, C=US", + "alias": "CN=Starfield Services Root Certificate Authority - G2, O=\"Starfield Technologies, Inc.\", L=Scottsdale, ST=Arizona, C=US", + "subject": "CN=Starfield Services Root Certificate Authority - G2, O=\"Starfield Technologies, Inc.\", L=Scottsdale, ST=Arizona, C=US", + "issuer": "OU=Starfield Class 2 Certification Authority, O=\"Starfield Technologies, Inc.\", C=US", + "version": 3, + "notValidBefore": 1251849600000, + "notValidAfter": 2035129156000, + "signatureAlgorithm": "RSA (2048 bits)", + "sha1Fingerprint": "9E:99:A4:8A:99:60:B1:49:26:BB:7F:3B:02:E2:2D:A2:B0:AB:72:80", + "md5Fingerprint": "C6:15:09:25:CF:EA:59:41:DD:C7:FF:2A:0A:50:66:92", + "expired": false, + "notYetValid": false, + "inbound": false, + "outbound": true + } + ], + "tags": {} + } +] \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/disabledOrganization.json b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/disabledOrganization.json new file mode 100644 index 00000000..9bb6bc70 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/disabledOrganization.json @@ -0,0 +1,18 @@ +{ + "id": "2bfaa1c2-49ab-4059-832d-f833ca1c0a74", + "name": "API Development", + "description": null, + "email": null, + "image": null, + "restricted": false, + "virtualHost": null, + "phone": null, + "enabled": false, + "development": true, + "dn": "o=API Development,ou=organizations,ou=APIPortal", + "createdOn": 1597326913559, + "startTrialDate": null, + "endTrialDate": null, + "trialDuration": null, + "isTrial": null +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/noDevelopmentOrg.json b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/noDevelopmentOrg.json new file mode 100644 index 00000000..00716e1e --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/noDevelopmentOrg.json @@ -0,0 +1,18 @@ +{ + "id": "2bfaa1c2-49ab-4059-832d-f833ca1c0a74", + "name": "API Development", + "description": null, + "email": null, + "image": null, + "restricted": false, + "virtualHost": null, + "phone": null, + "enabled": true, + "development": false, + "dn": "o=API Development,ou=organizations,ou=APIPortal", + "createdOn": 1597326913559, + "startTrialDate": null, + "endTrialDate": null, + "trialDuration": null, + "isTrial": null +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/organizationAPIDevelopment.json b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/organizationAPIDevelopment.json new file mode 100644 index 00000000..66039ed5 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/apimanager/organizationAPIDevelopment.json @@ -0,0 +1,18 @@ +{ + "id": "2bfaa1c2-49ab-4059-832d-f833ca1c0a74", + "name": "API Development", + "description": null, + "email": null, + "image": null, + "restricted": false, + "virtualHost": null, + "phone": null, + "enabled": true, + "development": true, + "dn": "o=API Development,ou=organizations,ou=APIPortal", + "createdOn": 1597326913559, + "startTrialDate": null, + "endTrialDate": null, + "trialDuration": null, + "isTrial": null +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/gatewayAdminOnlyPermissions.json b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/gatewayAdminOnlyPermissions.json new file mode 100644 index 00000000..91f326bf --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/gatewayAdminOnlyPermissions.json @@ -0,0 +1,33 @@ +{ + "result": { + "user": "gwadmin", + "permissions": [ + "ama_modify", + "fips_modify", + "group_force_unlock", + "traffic_monitor", + "deploy", + "domain_audit", + "domain_audit_modify", + "logs", + "dashboard", + "events", + "adminusers_passwordpolicy_modify", + "settings_modify", + "adminusers", + "settings", + "dashboard_modify", + "fips_read", + "mgmt_modify", + "adminusers_modify", + "monitoring", + "adminusers_reset", + "mgmt", + "ama", + "discovery", + "adminusers_advisorybanner_modify", + "emc", + "config" + ] + } +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/gatewayAdminUserPermissions.json b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/gatewayAdminUserPermissions.json new file mode 100644 index 00000000..d58ef4d3 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/gatewayAdminUserPermissions.json @@ -0,0 +1,36 @@ +{ + "result": { + "user": "admin", + "permissions": [ + "ama_modify", + "fips_modify", + "group_lock", + "group_force_unlock", + "traffic_monitor", + "deploy", + "group_unlock", + "domain_audit", + "domain_audit_modify", + "logs", + "dashboard", + "events", + "adminusers_passwordpolicy_modify", + "settings_modify", + "adminusers", + "settings", + "dashboard_modify", + "fips_read", + "mgmt_modify", + "adminusers_modify", + "monitoring", + "adminusers_reset", + "kps", + "mgmt", + "ama", + "discovery", + "adminusers_advisorybanner_modify", + "emc", + "config" + ] + } +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/operatorRoleOnlyPermissions.json b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/operatorRoleOnlyPermissions.json new file mode 100644 index 00000000..b6ddc699 --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/operatorRoleOnlyPermissions.json @@ -0,0 +1,19 @@ +{ + "result": { + "user": "chris", + "permissions": [ + "adminusers", + "settings", + "mgmt", + "ama", + "fips_read", + "emc", + "traffic_monitor", + "monitoring", + "logs", + "adminusers_reset", + "dashboard", + "events" + ] + } +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/unknownSessionCookie.txt b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/unknownSessionCookie.txt new file mode 100644 index 00000000..ba3b083e --- /dev/null +++ b/elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/testReplies/gateway/unknownSessionCookie.txt @@ -0,0 +1,17 @@ + + + + Access Denied + + + Access Denied, please login. + +           +           +           +           +           +           +           + + \ No newline at end of file diff --git a/elk-traffic-monitor-api/endpoints/lookupAPI.json b/elk-traffic-monitor-api/endpoints/lookupAPI.json new file mode 100644 index 00000000..964ebca5 --- /dev/null +++ b/elk-traffic-monitor-api/endpoints/lookupAPI.json @@ -0,0 +1,52 @@ +{ + "swagger": "2.0", + "info": { + "title": "API-Management Lookup API", + "version": "1.0", + "description": "This API is some kind of helper API to allow Logstash to enrich the data inserted into ElasticSearch. Initially this API was required to lookup the API being called to get the organization of this API", + "license": { + "name": "Apache 2.0" + }, + "contact": { + "name": "Chris Wiechmann", + "email": "cwiechmann@axway.com" + } + }, + "host": "example.com", + "paths": { + "/lookup/api": { + "get": { + "responses": { + "200": { + "description": "Returned if the API has been found" + }, + "404": { + "description": "Returned if the API can't be found." + } + }, + "parameters": [ + { + "type": "string", + "in": "query", + "name": "apiPath", + "description": "The exposed path of the API to be looked up", + "required": true + }, + { + "type": "string", + "in": "query", + "name": "apiName", + "required": true, + "description": "The name of the API to look up" + } + ], + "summary": "Looks up an API based on the API-Path", + "description": "This endpoint is taking in the API-Path (e.g. /v1/my/api) and tries to find this API in the Axway API-Management system. If successful it returns the API-Details.", + "operationId": "search", + "x-flow": "lookupAPI-search" + }, + "parameters": [] + } + }, + "basePath": "/elk/v1/api" +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/flows/lookupAPI-search.json b/elk-traffic-monitor-api/flows/lookupAPI-search.json new file mode 100644 index 00000000..4b1f0a68 --- /dev/null +++ b/elk-traffic-monitor-api/flows/lookupAPI-search.json @@ -0,0 +1,133 @@ +{ + "schemaVersion": "4", + "info": { + "name": "API Lookup", + "description": "Looks up an API - Used by Logstash to enrich documents." + }, + "parameter": { + "properties": { + "params": { + "type": "object", + "description": "The parameters from the endpoint." + }, + "request": { + "type": "object", + "description": "The HTTP request." + }, + "config": { + "type": "object", + "description": "The service's configuration" + }, + "env": { + "type": "object", + "description": "The host OS environment" + } + }, + "additionalProperties": false, + "required": [ + "params", + "request", + "config", + "env" + ] + }, + "start": "axway-api-management.1", + "nodes": { + "axway-api-management.1": { + "type": "nodehandler://api-builder-plugin-axway-api-management/axway-api-management", + "name": "Lookup API", + "method": "lookupAPIDetails", + "parameters": [ + { + "name": "apiName", + "type": "jsonpath", + "value": "$.params.apiName", + "metaName": "API-Name", + "metaDescription": "Name of the API is primary used to lookup the API" + }, + { + "name": "apiPath", + "type": "jsonpath", + "value": "$.params.apiPath", + "metaName": "Path of the API", + "metaDescription": "This request path is used to double check that the API found is correct." + } + ], + "outputs": { + "next": { + "routes": [ + "http.1" + ], + "context": "$.api", + "metaName": "Next" + }, + "error": { + "routes": [ + "http.2" + ], + "context": "$.error", + "metaName": "Error" + } + }, + "metaMethod": "Lookup API" + }, + "http.1": { + "type": "nodehandler://axway-flow/http", + "name": "Return API", + "method": "setresponse", + "parameters": [ + { + "name": "status", + "type": "number", + "value": "200", + "metaName": "Status", + "metaDescription": "The HTTP status code" + }, + { + "name": "body", + "type": "jsonpath", + "value": "$.api", + "metaName": "Body", + "metaDescription": "The response payload" + } + ], + "outputs": { + "next": { + "context": "$.response", + "routes": [], + "metaName": "Next" + } + }, + "metaMethod": "Set HTTP Response" + }, + "http.2": { + "type": "nodehandler://axway-flow/http", + "name": "API not found", + "method": "setresponse", + "parameters": [ + { + "name": "status", + "type": "number", + "value": "404", + "metaName": "Status", + "metaDescription": "The HTTP status code" + }, + { + "name": "body", + "type": "jsonpath", + "value": "$.error", + "metaName": "Body", + "metaDescription": "The response payload" + } + ], + "outputs": { + "next": { + "context": "$.response", + "routes": [], + "metaName": "Next" + } + }, + "metaMethod": "Set HTTP Response" + } + } +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/flows/trafficMonitorApi-circuitpath.json b/elk-traffic-monitor-api/flows/trafficMonitorApi-circuitpath.json index d0d82a98..9d606b4b 100644 --- a/elk-traffic-monitor-api/flows/trafficMonitorApi-circuitpath.json +++ b/elk-traffic-monitor-api/flows/trafficMonitorApi-circuitpath.json @@ -1,7 +1,8 @@ { "schemaVersion": "4", "info": { - "name": "trafficMonitorApi - get /router/service/{serviceID}/ops/stream/{correlationID}/*/circuitpath" + "name": "Traffic-Monitor API - CircuitPath", + "description": "Used by Traffic monitor display the Policy-Execution path" }, "parameter": { "properties": { @@ -30,7 +31,7 @@ "env" ] }, - "start": "javascript.2", + "start": "axway-api-management.1", "nodes": { "elasticsearch.1": { "type": "nodehandler://@axway-api-builder-ext/api-builder-plugin-fn-elasticsearch/elasticsearch", @@ -190,7 +191,7 @@ { "name": "code", "type": "string", - "value": "\"let elasticQuery = ({\\n \\\"bool\\\": {\\n \\\"must\\\": {\\n \\\"term\\\": {\\n \\\"correlationId\\\": data.params.correlationID\\n }\\n },\\n \\\"filter\\\": {\\n \\t\\\"term\\\": {\\n \\t\\t\\\"processInfo.serviceId\\\": data.params.serviceID\\n \\t}\\n \\t}\\n }\\n});\\n\\n return elasticQuery;\"", + "value": "\"let elasticQuery = ({ \\n \\\"bool\\\": {\\n \\\"must\\\": [\\n {\\n \\\"term\\\": {\\n \\\"correlationId\\\": data.params.correlationID\\n }\\n },\\n {\\n \\\"term\\\": {\\n \\\"processInfo.serviceId\\\": data.params.serviceID\\n }\\n }\\n ]\\n }\\n});\\n \\nif(!data.user.gatewayManager.isAdmin) {\\n var orgFilter;\\n if(data.user.apiManager.role == \\\"admin\\\") {\\n orgFilter = {\\n exists: {\\n \\\"field\\\" : \\\"transactionSummary.serviceContext\\\"\\n }\\n };\\n } else {\\n orgFilter = {\\n term: {\\n \\\"transactionSummary.serviceContext.apiOrg\\\" : data.user.apiManager.organizationName\\n }\\n };\\n }\\n elasticQuery.bool.must.push(orgFilter);\\n}\\n\\n return elasticQuery;\"", "metaName": "code", "metaDescription": "A JavaScript function body. Supports `await` and returning promises." } @@ -241,6 +242,35 @@ } }, "metaMethod": "Set HTTP Response" + }, + "axway-api-management.1": { + "type": "nodehandler://api-builder-plugin-axway-api-management/axway-api-management", + "name": "Lookup current user", + "method": "lookupCurrentUser", + "parameters": [ + { + "name": "requestHeaders", + "type": "jsonpath", + "value": "$.request.headers", + "metaName": "Request Headers", + "metaDescription": "The request headers are used to lookup the current users based on the current session cookie (VIDUSR)." + } + ], + "outputs": { + "next": { + "routes": [ + "javascript.2" + ], + "context": "$.user", + "metaName": "Next" + }, + "error": { + "routes": [], + "context": "$.error", + "metaName": "Error" + } + }, + "metaMethod": "Lookup current user" } } } \ No newline at end of file diff --git a/elk-traffic-monitor-api/flows/trafficMonitorApi-getinfo.json b/elk-traffic-monitor-api/flows/trafficMonitorApi-getinfo.json index b9fbdc31..0ff37085 100644 --- a/elk-traffic-monitor-api/flows/trafficMonitorApi-getinfo.json +++ b/elk-traffic-monitor-api/flows/trafficMonitorApi-getinfo.json @@ -1,7 +1,8 @@ { "schemaVersion": "4", "info": { - "name": "trafficMonitorApi - get /router/service/{serviceID}/ops/{protocol}/{correlationID}/{legID}/getinfo" + "name": "Traffic-Monitor API - GetInfo", + "description": "Used by Traffic monitor to display Request/Responses" }, "parameter": { "properties": { @@ -30,7 +31,7 @@ "env" ] }, - "start": "javascript.1", + "start": "axway-api-management.1", "nodes": { "javascript.1": { "type": "nodehandler://@axway/api-builder-plugin-fn-javascript/javascript", @@ -123,7 +124,7 @@ { "name": "code", "type": "string", - "value": "\"let elasticQuery = ({\\n \\\"bool\\\": {\\n \\\"must\\\": [\\n {\\\"term\\\": {\\\"correlationId\\\": data.params.correlationID}},\\n {\\\"term\\\": {\\\"processInfo.serviceId\\\": data.params.serviceID}}\\n ]\\n }\\n });\\n \\n \\n return elasticQuery;\"", + "value": "\"let elasticQuery = ({\\n \\\"bool\\\": {\\n \\\"must\\\": [\\n {\\\"term\\\": {\\\"correlationId\\\": data.params.correlationID}},\\n {\\\"term\\\": {\\\"processInfo.serviceId\\\": data.params.serviceID}}\\n ]\\n }\\n });\\n \\n if(!data.user.gatewayManager.isAdmin) {\\n var orgFilter;\\n if(data.user.apiManager.role == \\\"admin\\\") {\\n orgFilter = {\\n exists: {\\n \\\"field\\\" : \\\"transactionSummary.serviceContext\\\"\\n }\\n };\\n } else {\\n orgFilter = {\\n term: {\\n \\\"transactionSummary.serviceContext.apiOrg\\\" : data.user.apiManager.organizationName\\n }\\n };\\n }\\n elasticQuery.bool.must.push(orgFilter);\\n }\\n \\n return elasticQuery;\"", "metaName": "code", "metaDescription": "A JavaScript function body. Supports `await` and returning promises." } @@ -229,7 +230,7 @@ { "name": "code", "type": "string", - "value": "\"//init variables\\n \\n let transactionInfo = {};\\n let sourceLegs = [];\\n let resultLegs = [];\\n let legParam = data.params.legID;\\n let detailsParam = data.params.details;\\n let sheadersParam = data.params.sheaders;\\n let rheadersParam = data.params.rheaders;\\n let elasticData = data.elasticsearch.result.body.hits;\\n \\n \\n transactionInfo = elasticData.hits[0]._source;\\n sourceLegs = transactionInfo.transactionElements;\\n \\n // Loop over legs\\n for (var item in sourceLegs) {\\n let sourceLeg = sourceLegs[item];\\n let resultLeg = {};\\n let details = {};\\n\\n\\tlet rheaders = [];\\n let sheaders = [];\\n \\n if (legParam == '*' || legParam == sourceLeg.leg)\\n {\\n \\n if (detailsParam == '1'){\\n details.uri = sourceLeg.protocolInfo.http.uri;\\n details.status = sourceLeg.protocolInfo.http.status;\\n details.statustext = sourceLeg.protocolInfo.http.statusText;\\n details.method = sourceLeg.protocolInfo.http.method;\\n details.vhost = (typeof sourceLeg.protocolInfo.http.vhost === 'undefined') ? null : sourceLeg.protocolInfo.http.vhost; // needs to be checked - not avail in test data\\n details.wafStatus = sourceLeg.protocolInfo.http.wafStatus;\\n details.bytesSent = sourceLeg.protocolInfo.http.bytesSent;\\n details.bytesReceived = sourceLeg.protocolInfo.http.bytesReceived;\\n details.remoteName = sourceLeg.protocolInfo.http.remoteName;\\n details.remoteAddr = sourceLeg.protocolInfo.http.remoteAddr;\\n details.localAddr = sourceLeg.protocolInfo.http.localAddr;\\n details.remotePort = sourceLeg.protocolInfo.http.remotePort;\\n details.localPort = sourceLeg.protocolInfo.http.localPort; \\n details.sslsubject = (typeof sourceLeg.protocolInfo.http.sslSubject === 'undefined') ? null : sourceLeg.protocolInfo.http.sslSubject; //need to be checked - not avail in test data \\n details.leg = sourceLeg.leg;\\n details.timestamp = Date.parse(transactionInfo['@timestamp']); //Needs to be formatted\\n details.duration = sourceLeg.duration;\\n details.correlationId = transactionInfo.correlationId;\\n details.serviceName = sourceLeg.serviceName;\\n details.subject = sourceLeg.protocolInfo.http.authSubjectId;\\n details.operation = sourceLeg.operation;\\n details.type = 'http'; //ToDo - currently hardcoded. Get it from path param in future\\n details.finalStatus = (typeof sourceLeg.finalStatus === 'undefined') ? null : sourceLeg.finalStatus; //need to be checked - not always avail in test data \\n resultLeg.details = details;\\n } else if (detailsParam == '0'){ \\n resultLeg.details = null;\\n } else{\\n // No details element at all\\n }\\n\\n \\n // Formatting the rHeaders \\n if (rheadersParam == '1'){\\n let rawRecvHeader = [];\\n rawRecvHeader = sourceLeg.protocolInfo.recvHeader.split(\\\"\\\\r\\\\n\\\")\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t;\\n let recvAttributes = []; \\n\\n rawRecvHeader.forEach(function (item,index){\\n if (index !=0){\\n let attribObj = {}; \\n let n = item.indexOf(\\\":\\\");\\n let attribName = item.substr(0,n).toString();\\n let atrribValue = (item.substr(n+1).trim());\\n if (attribName.length != 0) {\\n attribObj[attribName]= atrribValue; \\n recvAttributes.push(attribObj);\\n }\\n }\\n });\\n resultLeg.rheaders = recvAttributes;\\n } else if (rheadersParam == '0'){ \\n resultLeg.rheaders = null;\\n } else {\\n // No rheaders elemenmt at all\\n }\\n\\n\\n // Formatting the sHeaders\\n \\n\\t if (sheadersParam == '1') {\\n let rawSendHeader = [];\\n rawSendHeader = sourceLeg.protocolInfo.sentHeader.split(\\\"\\\\r\\\\n\\\")\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t;\\n let sendAttributes = []; \\n\\n rawSendHeader.forEach(function (item,index){\\n if (index !=0){\\n let attribObj = {}; \\n let n = item.indexOf(\\\":\\\");\\n let attribName = item.substr(0,n).toString();\\n let atrribValue = (item.substr(n+1).trim());\\n if (attribName.length != 0) {\\n attribObj[attribName]= atrribValue; \\n sendAttributes.push(attribObj);\\n }\\n }\\n });\\n\\n resultLeg.sheaders = sendAttributes;\\n } else if (sheadersParam == '0') {\\n resultLeg.sheaders = null;\\n } else {\\n // No sheaders element at all\\n }\\n\\n\\t // Only when all legs are requested create an Array with leg objects.\\n // Otherwise just return the leg object.\\n\\t if (legParam == '*') {\\n \\tresultLegs.push(resultLeg);\\n } else {\\n return resultLeg;\\n }\\n\\n }\\n }\\n\\n \\n return resultLegs;\"", + "value": "\"//init variables\\n \\n let transactionInfo = {};\\n let sourceLegs = [];\\n let resultLegs = [];\\n let legParam = data.params.legID;\\n let detailsParam = data.params.details;\\n let sheadersParam = data.params.sheaders;\\n let rheadersParam = data.params.rheaders;\\n let elasticData = data.elasticsearch.result.body.hits;\\n \\n \\n transactionInfo = elasticData.hits[0]._source;\\n sourceLegs = transactionInfo.transactionElements;\\n \\n // Loop over legs\\n for (var item in sourceLegs) {\\n let sourceLeg = sourceLegs[item];\\n let resultLeg = {};\\n let details = {};\\n\\n\\tlet rheaders = [];\\n let sheaders = [];\\n \\n if (legParam == '*' || legParam == sourceLeg.leg)\\n {\\n \\n if (detailsParam == '1'){\\n details.uri = sourceLeg.protocolInfo.http.uri;\\n details.status = sourceLeg.protocolInfo.http.status;\\n details.statustext = sourceLeg.protocolInfo.http.statusText;\\n details.method = sourceLeg.protocolInfo.http.method;\\n details.vhost = (typeof sourceLeg.protocolInfo.http.vhost === 'undefined') ? null : sourceLeg.protocolInfo.http.vhost; // needs to be checked - not avail in test data\\n details.wafStatus = sourceLeg.protocolInfo.http.wafStatus;\\n details.bytesSent = sourceLeg.protocolInfo.http.bytesSent;\\n details.bytesReceived = sourceLeg.protocolInfo.http.bytesReceived;\\n details.remoteName = sourceLeg.protocolInfo.http.remoteName;\\n details.remoteAddr = sourceLeg.protocolInfo.http.remoteAddr;\\n details.localAddr = sourceLeg.protocolInfo.http.localAddr;\\n details.remotePort = sourceLeg.protocolInfo.http.remotePort;\\n details.localPort = sourceLeg.protocolInfo.http.localPort; \\n details.sslsubject = (typeof sourceLeg.protocolInfo.http.sslSubject === 'undefined') ? null : sourceLeg.protocolInfo.http.sslSubject; //need to be checked - not avail in test data \\n details.leg = sourceLeg.leg;\\n details.timestamp = Date.parse(transactionInfo['@timestamp']); //Needs to be formatted\\n details.duration = sourceLeg.duration;\\n details.correlationId = transactionInfo.correlationId;\\n details.serviceName = sourceLeg.serviceName;\\n details.subject = sourceLeg.protocolInfo.http.authSubjectId;\\n details.operation = sourceLeg.operation;\\n details.type = 'http'; //ToDo - currently hardcoded. Get it from path param in future\\n details.finalStatus = (typeof sourceLeg.finalStatus === 'undefined') ? null : sourceLeg.finalStatus; //need to be checked - not always avail in test data \\n resultLeg.details = details;\\n } else if (detailsParam == '0'){ \\n resultLeg.details = null;\\n } else{\\n // No details element at all\\n }\\n\\n \\n // Formatting the rHeaders \\n if (rheadersParam == '1'){\\n let rawRecvHeader = [];\\n rawRecvHeader = sourceLeg.protocolInfo.recvHeader.split(\\\"\\\\r\\\\n\\\")\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t;\\n let recvAttributes = []; \\n\\n rawRecvHeader.forEach(function (item,index){\\n if (index !=0){\\n let attribObj = {}; \\n let n = item.indexOf(\\\":\\\");\\n let attribName = item.substr(0,n).toString();\\n let atrribValue = (item.substr(n+1).trim());\\n if (attribName.length != 0) {\\n attribObj[attribName]= atrribValue; \\n recvAttributes.push(attribObj);\\n }\\n }\\n });\\n resultLeg.rheaders = recvAttributes;\\n } else if (rheadersParam == '0'){ \\n resultLeg.rheaders = null;\\n } else {\\n // No rheaders elemenmt at all\\n }\\n\\n\\n // Formatting the sHeaders\\n \\n\\t if (sheadersParam == '1') {\\n let rawSendHeader = [];\\n rawSendHeader = sourceLeg.protocolInfo.sentHeader.split(\\\"\\\\r\\\\n\\\")\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t;\\n let sendAttributes = []; \\n\\n rawSendHeader.forEach(function (item,index){\\n if (index !=0){\\n let attribObj = {}; \\n let n = item.indexOf(\\\":\\\");\\n let attribName = item.substr(0,n).toString();\\n let atrribValue = (item.substr(n+1).trim());\\n if (attribName.length != 0) {\\n attribObj[attribName]= atrribValue; \\n sendAttributes.push(attribObj);\\n }\\n }\\n });\\n\\n resultLeg.sheaders = sendAttributes;\\n } else if (sheadersParam == '0') {\\n resultLeg.sheaders = null;\\n } else {\\n // No sheaders element at all\\n }\\n\\n\\t // Only when all legs are requested create an Array with leg objects.\\n // Otherwise just return the leg object.\\n\\t if (legParam == '*') {\\n \\tresultLegs.push(resultLeg);\\n } else {\\n return resultLeg;\\n }\\n\\n }\\n }\\n return resultLegs;\"", "metaName": "code", "metaDescription": "A JavaScript function body. Supports `await` and returning promises." } @@ -302,6 +303,35 @@ } }, "metaMethod": "Set HTTP Response" + }, + "axway-api-management.1": { + "type": "nodehandler://api-builder-plugin-axway-api-management/axway-api-management", + "name": "Lookup current user", + "method": "lookupCurrentUser", + "parameters": [ + { + "name": "requestHeaders", + "type": "jsonpath", + "value": "$.request.headers", + "metaName": "Request Headers", + "metaDescription": "The request headers are used to lookup the current users based on the current session cookie (VIDUSR)." + } + ], + "outputs": { + "next": { + "routes": [ + "javascript.1" + ], + "context": "$.user", + "metaName": "Next" + }, + "error": { + "routes": [], + "context": "$.error", + "metaName": "Error" + } + }, + "metaMethod": "Lookup current user" } } } \ No newline at end of file diff --git a/elk-traffic-monitor-api/flows/trafficMonitorApi-search.json b/elk-traffic-monitor-api/flows/trafficMonitorApi-search.json index 7bc7df75..44ef3930 100644 --- a/elk-traffic-monitor-api/flows/trafficMonitorApi-search.json +++ b/elk-traffic-monitor-api/flows/trafficMonitorApi-search.json @@ -1,7 +1,8 @@ { "schemaVersion": "4", "info": { - "name": "monitoringApiApi - get /router/service/{serviceID}/ops/search" + "name": "Traffic-Monitor API - Search", + "description": "Used by Traffic monitor to search for APIs (Table overview)" }, "parameter": { "properties": { @@ -30,7 +31,7 @@ "env" ] }, - "start": "javascript.8", + "start": "axway-api-management.1", "nodes": { "http.1": { "type": "nodehandler://axway-flow/http", @@ -410,7 +411,73 @@ "routes": [ "javascript.3", "javascript.6", - "javascript.7" + "javascript.7", + "javascript.4" + ], + "metaName": "Next" + }, + "error": { + "context": "$.error", + "routes": [], + "metaName": "Error" + } + }, + "metaMethod": "Execute" + }, + "axway-api-management.1": { + "type": "nodehandler://api-builder-plugin-axway-api-management/axway-api-management", + "name": "Lookup current user", + "method": "lookupCurrentUser", + "parameters": [ + { + "name": "requestHeaders", + "type": "jsonpath", + "value": "$.request.headers", + "metaName": "Request Headers", + "metaDescription": "The request headers are used to lookup the current users based on the current session cookie (VIDUSR)." + } + ], + "outputs": { + "next": { + "context": "$.user", + "routes": [ + "javascript.8" + ], + "metaName": "Next" + }, + "error": { + "context": "$.error", + "routes": [], + "metaName": "Error" + } + }, + "metaMethod": "Lookup current user" + }, + "javascript.4": { + "type": "nodehandler://@axway/api-builder-plugin-fn-javascript/javascript", + "name": "Org-Admin filter", + "method": "Execute", + "parameters": [ + { + "name": "data", + "type": "jsonpath", + "value": "$", + "metaName": "data", + "metaDescription": "The value to apply as the `data` argument to the JavaScript code. For objects and arrays, `data` is passed by reference." + }, + { + "name": "code", + "type": "string", + "value": "\"var queryFilters = data.queryFilters;\\n if(!data.user.gatewayManager.isAdmin) {\\n var filter;\\n if(data.user.apiManager.role == \\\"admin\\\") {\\n filter = {\\n exists: {\\n \\\"field\\\" : \\\"transactionSummary.serviceContext\\\"\\n }\\n };\\n } else {\\n filter = {\\n term: {\\n \\\"transactionSummary.serviceContext.apiOrg\\\" : data.user.apiManager.organizationName\\n }\\n };\\n }\\n queryFilters.push(filter);\\n }\\n return queryFilters;\"", + "metaName": "code", + "metaDescription": "A JavaScript function body. Supports `await` and returning promises." + } + ], + "outputs": { + "next": { + "context": "$.result", + "routes": [ + "javascript.2" ], "metaName": "Next" }, diff --git a/elk-traffic-monitor-api/flows/trafficMonitorApi-trace.json b/elk-traffic-monitor-api/flows/trafficMonitorApi-trace.json index a18abffa..fb1928d7 100644 --- a/elk-traffic-monitor-api/flows/trafficMonitorApi-trace.json +++ b/elk-traffic-monitor-api/flows/trafficMonitorApi-trace.json @@ -1,7 +1,8 @@ { "schemaVersion": "4", "info": { - "name": "trafficMonitorApi - get /router/service/{serviceID}/ops/trace/{correlationID}" + "name": "Traffic-Monitor API - Trace", + "description": "Used by Traffic monitor to show the trace details" }, "parameter": { "properties": { diff --git a/elk-traffic-monitor-api/package-lock.json b/elk-traffic-monitor-api/package-lock.json index a6db582e..01b1d3a1 100644 --- a/elk-traffic-monitor-api/package-lock.json +++ b/elk-traffic-monitor-api/package-lock.json @@ -19,13 +19,13 @@ } }, "@axway/api-builder-admin": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@axway/api-builder-admin/-/api-builder-admin-1.21.0.tgz", - "integrity": "sha512-kAT9O//wugXpwGa0XKHZGZZ/r5l45OgPVYIg6RtdHRTdWJYbOGw/q0EiPNHq0h8z/w/W4FEXOHYfS0jsgjYE+g==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@axway/api-builder-admin/-/api-builder-admin-1.22.0.tgz", + "integrity": "sha512-x3h9q9l1xGkZClF0xyBzVZRVHWBAciTmUI7jbJDSN8YR8Hp4nXntccdOtbER2l3I/IFqYJuV5+EKpICdQNz5WQ==", "dev": true, "requires": { - "arrow-admin-api": "6.13.0", - "arrow-admin-ui": "4.18.0", + "arrow-admin-api": "6.14.0", + "arrow-admin-ui": "4.19.0", "async": "^2.6.1", "chalk": "^2.4.1", "express": "^4.16.4", @@ -39,11 +39,12 @@ "integrity": "sha512-i1dkFjq2dw5AY6PCF/ZSaHO2gn288LZT2RBmAp0J2XNvIVg6ulJ9GTVHz23o13S8h/QgTZHtgur/YMxO+Rq6tA==" }, "@axway/api-builder-flow-invoke": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@axway/api-builder-flow-invoke/-/api-builder-flow-invoke-4.2.9.tgz", - "integrity": "sha512-d+zOX+vOES+lyIk3pzUA8xn+5vXgPfXN4unVFWewQqOpHmtSbGaoDXFER8oEhuxQ/KD+9bVRG4LHZn6SAhGEtA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@axway/api-builder-flow-invoke/-/api-builder-flow-invoke-4.3.1.tgz", + "integrity": "sha512-st/axYMj9w8TXCNjwceFHw7Z63wXaWoNrjPEWbAAdP/0hnYRSXG8P/XorZFTKvlmklIlYzVk0/BFCycnCkTxKw==", "requires": { - "@axway/flow": "6.5.4", + "@axway/api-builder-config": "3.1.2", + "@axway/flow": "6.6.0", "axway-schema": "4.2.2", "parse-json": "^4.0.0" } @@ -266,14 +267,14 @@ } }, "@axway/api-builder-runtime": { - "version": "4.32.2", - "resolved": "https://registry.npmjs.org/@axway/api-builder-runtime/-/api-builder-runtime-4.32.2.tgz", - "integrity": "sha512-3ttvCRVScmL6ypfVA0a4dcM/BA6irTo45epzggwo1y0h85fWCw3FItLKiPtVBk7/mIwKK+2cLPZQ9hzugAxH+g==", + "version": "4.33.2", + "resolved": "https://registry.npmjs.org/@axway/api-builder-runtime/-/api-builder-runtime-4.33.2.tgz", + "integrity": "sha512-TbfgRyzyMzIazQrPEt95jXhBl6gc7Jb79LjhnhP1qufyV7JRSRD0P0OhjQimJlfWjgId44bX5qKCxslPCHsSDw==", "requires": { "@axway/api-builder-config": "3.1.2", - "@axway/api-builder-flow-invoke": "4.2.9", - "@axway/axway-flow-authorization": "1.2.7", - "@axway/flow": "6.5.4", + "@axway/api-builder-flow-invoke": "4.3.1", + "@axway/axway-flow-authorization": "1.2.8", + "@axway/flow": "6.6.0", "ajv": "^5.3.0", "arrow-endpoint": "4.3.0", "arrow-orm": "2.9.7", @@ -382,23 +383,23 @@ } }, "@axway/axway-flow-authorization": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@axway/axway-flow-authorization/-/axway-flow-authorization-1.2.7.tgz", - "integrity": "sha512-lCulWfcnZin6CVlZx34QBVLQo/M2B2LYThrP+FXVvJD9M2PI4/QHTF1wr5b4kBmi0MWgoyhHCmr2k57Ncv1Tjg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@axway/axway-flow-authorization/-/axway-flow-authorization-1.2.8.tgz", + "integrity": "sha512-IGljkUBeBZnbdXcD9DB1myREz8CA0choYJov8PPvsu947AWuU6+GzQ6SimBBgTrCCRRp+/URbmE7m7vskmofvQ==", "requires": { - "@axway/flow": "6.5.4", + "@axway/flow": "6.6.0", "content-type": "^1.0.4", "qs": "^6.7.0", "request": "^2.88.0" } }, "@axway/flow": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/@axway/flow/-/flow-6.5.4.tgz", - "integrity": "sha512-c2IxTz6/P8A58juP3By++6H8hJb0uhUMPieOnRELvvYahx+vSPPhT3XnaLTy2MsunvRce13zi20OQY+wVenIGQ==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@axway/flow/-/flow-6.6.0.tgz", + "integrity": "sha512-YTRgiGEvXGrL8Hg/Zzfe6xthKIhmghaFf+QQYjgw+CUkqIplPeYVvFe2dQplkYJBE+9zT3reYGHPzZKmmgQEcw==", "requires": { "@livereach/jsonpath": "^1.0.0", - "axway-flow-graph": "3.1.4", + "axway-flow-graph": "3.2.0", "axway-flow-schema": "5.4.1", "axway-schema": "4.2.2", "chalk": "^2.4.1", @@ -480,9 +481,9 @@ } }, "@types/node": { - "version": "14.0.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz", - "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==" + "version": "14.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.0.tgz", + "integrity": "sha512-mikldZQitV94akrc4sCcSjtJfsTKt4p+e/s0AGscVA6XArQ9kFclP+ZiYUMnq987rc6QlYxXv/EivqlfSLxpKA==" }, "accepts": { "version": "1.3.7", @@ -534,6 +535,1007 @@ "picomatch": "^2.0.4" } }, + "api-builder-plugin-axway-api-management": { + "version": "file:custom_flow_nodes/api-builder-plugin-axway-api-management", + "requires": { + "@axway/api-builder-sdk": "^1.0.0", + "node-cache": "^5.1.2" + }, + "dependencies": { + "@axway/api-builder-sdk": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@axway/api-builder-sdk/-/api-builder-sdk-1.0.4.tgz", + "integrity": "sha512-iRaxGZg9NhyY319atpA4KBRdT5F2Gc6UxmldTKqU+5Exudj0EaqIqcLvk2tbqqhAO/aK6zQpuNvny9QXRRlwfg==", + "requires": { + "ajv": "^5.3.0", + "js-yaml": "^3.13.1" + } + }, + "@axway/api-builder-test-utils": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@axway/api-builder-test-utils/-/api-builder-test-utils-1.1.1.tgz", + "integrity": "sha512-Hgj0jAf7LYW2tP51OYIgQl4ZQ6aIunsrBzv+p0PKxpzzDjOE74aYQw7x3oybhco7R7xpWm/yglgaZFi/1KITYw==", + "requires": { + "ajv": "^5.3.0", + "axway-flow-schema": "5.4.1" + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==" + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, + "axway-flow-schema": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/axway-flow-schema/-/axway-flow-schema-5.4.1.tgz", + "integrity": "sha512-+xMZSXADmeXmBDgfsVUJXq2dpYb9wz4QjuXuxCc1EcfwcDyrpzwR/19rlmRvSgN3ZoWcIFzXsxahelWAPdU2dw==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "requires": { + "type-detect": "^4.0.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "requires": { + "is-buffer": "~2.0.3" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "requires": { + "chalk": "^2.4.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "nock": { + "version": "13.0.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.0.4.tgz", + "integrity": "sha512-alqTV8Qt7TUbc74x1pKRLSENzfjp4nywovcJgi/1aXDiUxXdt7TkruSTF5MDWPP7UoPVgea4F9ghVdmX0xxnSA==", + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash.set": "^4.3.2", + "propagate": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "requires": { + "clone": "2.x" + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + }, + "propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==" + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "requires": { + "picomatch": "^2.0.4" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } + }, "append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", @@ -553,13 +1555,13 @@ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "arrow-admin-api": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/arrow-admin-api/-/arrow-admin-api-6.13.0.tgz", - "integrity": "sha512-NHS4G1G98HaAWkyLs1hfCE4GYwfIniPm8EfQomLMhp4Z2g4ZNJ0cvbN3hYaZI/Ma4aI9532PygJL61m1U6Ktyg==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/arrow-admin-api/-/arrow-admin-api-6.14.0.tgz", + "integrity": "sha512-mxdWwFKUy4uRrCAi+5qkr0GZ1XyIU4CMBQF/cwWO/P6OvuFmsdHHMtLJyty9DujY/9e/a763eKPOO7Whm0Antw==", "dev": true, "requires": { "@axway/api-builder-config": "3.1.2", - "@axway/axway-flow-authorization": "1.2.7", + "@axway/axway-flow-authorization": "1.2.8", "async": "^2.6.1", "axway-schema": "4.2.2", "capitalize": "^1.0.0", @@ -576,9 +1578,9 @@ } }, "arrow-admin-ui": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/arrow-admin-ui/-/arrow-admin-ui-4.18.0.tgz", - "integrity": "sha512-btfY7V9a2Azi2cJE0S4WMmzbz12c28WLfxuVrr7J53E9zZLL5yDs4FkozLGn/9l9I3fgTaOmKhp/5RUVVpNv5g==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/arrow-admin-ui/-/arrow-admin-ui-4.19.0.tgz", + "integrity": "sha512-Epip4Q2fY1gL/WVUXJndw0n2ub5HKzr8J33LDaJRKHh4gNTGH0YxfXuaw4n24UIFRyI8vdVpXtAnycHD4lDrDw==", "dev": true, "requires": { "@axway/api-builder-config": "3.1.2" @@ -660,9 +1662,9 @@ "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==" }, "axway-flow-graph": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/axway-flow-graph/-/axway-flow-graph-3.1.4.tgz", - "integrity": "sha512-Llzehrb4ND3OQdD0iMI/uRL3h6hhNjdJwEWcLNHq6ZqsN0MWCmbhtzgIb0d8+xQpd80M3QYso7wbZWep161EFQ==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/axway-flow-graph/-/axway-flow-graph-3.2.0.tgz", + "integrity": "sha512-Ry5B0rpoOk2zH0yuJPjKaUuyd9WluOigpH8z0Kulfz/dlpqHrLGskPbvsGGZj2U+EBoDCzwksiUE2Y+eG453nA==" }, "axway-flow-schema": { "version": "5.4.0", @@ -2729,6 +3731,18 @@ "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==" }, + "nock": { + "version": "13.0.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.0.4.tgz", + "integrity": "sha512-alqTV8Qt7TUbc74x1pKRLSENzfjp4nywovcJgi/1aXDiUxXdt7TkruSTF5MDWPP7UoPVgea4F9ghVdmX0xxnSA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash.set": "^4.3.2", + "propagate": "^2.0.0" + } + }, "node-environment-flags": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", @@ -2964,6 +3978,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true + }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", diff --git a/elk-traffic-monitor-api/package.json b/elk-traffic-monitor-api/package.json index f163bd98..17c8e016 100644 --- a/elk-traffic-monitor-api/package.json +++ b/elk-traffic-monitor-api/package.json @@ -35,12 +35,15 @@ "@axway/api-builder-plugin-fn-mustache": "^1.0.6", "@axway/api-builder-plugin-fn-restclient": "^2.0.22", "@axway/api-builder-plugin-fn-swagger": "^2.7.8", - "@axway/api-builder-runtime": "^4.32.2" + "@axway/api-builder-runtime": "^4.33.2", + "api-builder-plugin-axway-api-management": "file:custom_flow_nodes/api-builder-plugin-axway-api-management" }, "devDependencies": { - "@axway/api-builder-admin": "^1.21.0", + "@axway/api-builder-admin": "^1.22.0", "chai": "^4.2.0", - "mocha": "^7.2.0" + "dotenv": "^8.2.0", + "mocha": "^7.2.0", + "nock": "^13.0.4" }, "scripts": { "start": "node .", diff --git a/elk-traffic-monitor-api/test/.env b/elk-traffic-monitor-api/test/.env new file mode 100644 index 00000000..33b40c74 --- /dev/null +++ b/elk-traffic-monitor-api/test/.env @@ -0,0 +1,3 @@ +ADMIN_NODE_MANAGER=https://mocked-api-gateway:8090 +API_MANAGER_USERNAME=apiadmin +API_MANAGER_PASSWORD=changeme \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/_base.js b/elk-traffic-monitor-api/test/_base.js index 7f741073..ab3b913c 100644 --- a/elk-traffic-monitor-api/test/_base.js +++ b/elk-traffic-monitor-api/test/_base.js @@ -71,7 +71,6 @@ async function sendToElasticsearch(elasticConfig, index, dataset) { const client = new Client({ node: elasticConfig.node }); - debugger; const mappingConfig = JSON.parse(fs.readFileSync('../logstash/config/traffic_details_index_template.json')).mappings; const createdIndexResponse = await client.indices.create({ index: index, diff --git a/elk-traffic-monitor-api/test/apiLookup/test_apiLookup.js b/elk-traffic-monitor-api/test/apiLookup/test_apiLookup.js new file mode 100644 index 00000000..2e89b6ee --- /dev/null +++ b/elk-traffic-monitor-api/test/apiLookup/test_apiLookup.js @@ -0,0 +1,75 @@ +const { expect } = require('chai'); +const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('../_base'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); + +describe('Test API-Lookup endpoint', function () { + this.timeout(30000); + let server; + let auth; + + afterEach(() => { + nock.cleanAll(); + }); + + /** + * Start API Builder. + */ + /** + * Start API Builder. + */ + before(() => { + const envFilePath = path.join(__dirname, '../.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } + server = startApiBuilder(); + auth = { + user: server.apibuilder.config.apikey || 'test', + password: '' + }; + return server.started; + }); + + /** + * Stop API Builder after the tests. + */ + after(() => stopApiBuilder(server)); + + describe('trace endpoint tests', () => { + + it('[apilookup-0001] Should return http 200 with API details for an existing API', () => { + nock('https://mocked-api-gateway:8075').get('/api/portal/v1.3/proxies?field=name&op=eq&value=Petstore%20HTTPS').replyWithFile(200, './test/mockedReplies/apimanager/oneApiProxyFound.json'); + nock('https://mocked-api-gateway:8075').get('/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-CHRIS').replyWithFile(200, './test/mockedReplies/apimanager/organizationChris.json'); + return requestAsync({ + method: 'GET', + uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/lookup/api?apiName=Petstore%20HTTPS&apiPath=/my/api/exists/with/some/more`, + auth: auth, + json: true + }).then(({ response, body }) => { + expect(response.statusCode).to.equal(200); + expect(body).to.be.an('Object'); + expect(body.organizationName).to.equal('Chris Org'); + expect(body.path).to.equal('/my/api/exists'); + nock.cleanAll(); + }); + }); + + it('[apilookup-0002] Should return http 404 for an unknown API', () => { + nock('https://mocked-api-gateway:8075').get('/api/portal/v1.3/proxies?field=name&op=eq&value=UnknownAPI').reply(200, '[]'); + return requestAsync({ + method: 'GET', + uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/lookup/api?apiName=UnknownAPI&apiPath=/any/path`, + auth: auth, + json: true + }).then(({ response, body }) => { + expect(response.statusCode).to.equal(404); + expect(body).to.be.an('Object'); + expect(body.message).to.equal(`No APIs found with name: 'UnknownAPI'`); + }); + }); + }); +}); + diff --git a/elk-traffic-monitor-api/test/test_circuitpath.js b/elk-traffic-monitor-api/test/asAdmin/test_circuitpath.js similarity index 74% rename from elk-traffic-monitor-api/test/test_circuitpath.js rename to elk-traffic-monitor-api/test/asAdmin/test_circuitpath.js index 7cdb698e..fe930074 100644 --- a/elk-traffic-monitor-api/test/test_circuitpath.js +++ b/elk-traffic-monitor-api/test/asAdmin/test_circuitpath.js @@ -1,5 +1,9 @@ const { expect } = require('chai'); -const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('./_base'); +const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('../_base'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); describe('Traffic Monitor API', function () { this.timeout(30000); @@ -7,11 +11,25 @@ describe('Traffic Monitor API', function () { let auth; const indexName = `circuitpath_test_${getRandomInt(9999)}`; + beforeEach(() => { + // Simulate all responses in this test-file to be an admin, which will not lead to any result restriction + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "david" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/adminUserDavid.json'); + }); + + afterEach(() => { + nock.cleanAll(); + }); + /** * Start API Builder. */ before(() => { return new Promise(function(resolve, reject){ + const envFilePath = path.join(__dirname, '../.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } server = startApiBuilder(); auth = { user: server.apibuilder.config.apikey || 'test', @@ -21,7 +39,7 @@ describe('Traffic Monitor API', function () { elasticConfig = server.apibuilder.config.pluginConfig['@axway-api-builder-ext/api-builder-plugin-fn-elasticsearch'].elastic; server.started .then(() => { - const entryset = require('./documents/basic/circuitpath_test_documents'); + const entryset = require('../documents/basic/circuitpath_test_documents'); sendToElasticsearch(elasticConfig, indexName, entryset) .then(() => { resolve(); @@ -42,6 +60,10 @@ describe('Traffic Monitor API', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/stream/4e645e5e4600bb590c881179/*/circuitpath`, + headers: { + 'cookie': 'VIDUSR=circuitpath-0001-DAVID-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -60,6 +82,10 @@ describe('Traffic Monitor API', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/stream/c8705e5ecc00adca32be7472/*/circuitpath`, + headers: { + 'cookie': 'VIDUSR=circuitpath-0002-DAVID-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -84,6 +110,10 @@ describe('Traffic Monitor API', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/stream/edb1705e7d0168a34d74bfba/*/circuitpath`, + headers: { + 'cookie': 'VIDUSR=circuitpath-0003-DAVID-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -96,6 +126,10 @@ describe('Traffic Monitor API', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/stream/111111111111111111111111/*/circuitpath`, + headers: { + 'cookie': 'VIDUSR=circuitpath-0004-DAVID-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -108,6 +142,10 @@ describe('Traffic Monitor API', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/stream/1ab3705e920284217e6aae73/*/circuitpath`, + headers: { + 'cookie': 'VIDUSR=circuitpath-0005-DAVID-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { diff --git a/elk-traffic-monitor-api/test/test_getinfo_endpoint.js b/elk-traffic-monitor-api/test/asAdmin/test_getinfo_endpoint.js similarity index 67% rename from elk-traffic-monitor-api/test/test_getinfo_endpoint.js rename to elk-traffic-monitor-api/test/asAdmin/test_getinfo_endpoint.js index fbfd2561..1b59fe0b 100644 --- a/elk-traffic-monitor-api/test/test_getinfo_endpoint.js +++ b/elk-traffic-monitor-api/test/asAdmin/test_getinfo_endpoint.js @@ -1,5 +1,9 @@ const { expect } = require('chai'); -const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('./_base'); +const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('../_base'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); describe('Endpoints', function () { this.timeout(30000); @@ -7,11 +11,25 @@ describe('Endpoints', function () { let auth; const indexName = `getinfo_test_${getRandomInt(9999)}`; + beforeEach(() => { + // Simulate all responses in this test-file to be an admin, which will not lead to any result restriction + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "david" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/adminUserDavid.json'); + }); + + afterEach(() => { + nock.cleanAll(); + }); + /** * Start API Builder. */ before(() => { return new Promise(function(resolve, reject){ + const envFilePath = path.join(__dirname, '../.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } server = startApiBuilder(); auth = { user: server.apibuilder.config.apikey || 'test', @@ -21,7 +39,7 @@ describe('Endpoints', function () { elasticConfig = server.apibuilder.config.pluginConfig['@axway-api-builder-ext/api-builder-plugin-fn-elasticsearch'].elastic; server.started .then(() => { - const entryset = require('./documents/basic/getinfo_test_documents'); + const entryset = require('../documents/basic/getinfo_test_documents'); sendToElasticsearch(elasticConfig, indexName, entryset) .then(() => { resolve(); @@ -37,11 +55,14 @@ describe('Endpoints', function () { after(() => stopApiBuilder(server)); describe('Search', () => { - it('[Getinfo-0001] Should return http 200 with details and headers for all legs (*) ', () => { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/http/0455ff5e82267be8182a553d/*/getinfo?format=json&details=1&rheaders=1&sheaders=1`, + headers: { + 'cookie': 'VIDUSR=Getinfo-0001-DAVID-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -60,10 +81,14 @@ describe('Endpoints', function () { }); }); - it('[Getinfo-0002 Should return http 200 with details and all headers for leg 0', () => { + it('[Getinfo-0002] Should return http 200 with details and all headers for leg 0', () => { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/http/0455ff5e82267be8182a553d/0/getinfo?format=json&details=1&rheaders=1&sheaders=1`, + headers: { + 'cookie': 'VIDUSR=Getinfo-0002-DAVID-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -76,10 +101,14 @@ describe('Endpoints', function () { expect(body).to.have.property('sheaders'); }); }); - it('[Getinfo-0003 Should return http 200 with details and all headers for leg 1', () => { + it('[Getinfo-0003] Should return http 200 with details and all headers for leg 1', () => { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/http/0455ff5e82267be8182a553d/1/getinfo?format=json&details=1&rheaders=1&sheaders=1`, + headers: { + 'cookie': 'VIDUSR=Getinfo-0003-DAVID-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -92,10 +121,14 @@ describe('Endpoints', function () { expect(body).to.have.property('sheaders'); }); }); - it('[Getinfo-0004 Should return http 200 without details but all headers for all legs (*)', () => { + it('[Getinfo-0004] Should return http 200 without details but all headers for all legs (*)', () => { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/http/0455ff5e82267be8182a553d/*/getinfo?format=json&details=0&rheaders=1&sheaders=1`, + headers: { + 'cookie': 'VIDUSR=Getinfo-0004-DAVID-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -114,10 +147,14 @@ describe('Endpoints', function () { expect(body[1]).to.have.property('sheaders'); }); }); - it('[Getinfo-0005 Should return http 200 with details but no headers for all legs (*)', () => { + it('[Getinfo-0005] Should return http 200 with details but no headers for all legs (*)', () => { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/http/0455ff5e82267be8182a553d/*/getinfo?format=json&details=1&rheaders=0&sheaders=0`, + headers: { + 'cookie': 'VIDUSR=Getinfo-0005-DAVID-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { diff --git a/elk-traffic-monitor-api/test/test_search_count.js b/elk-traffic-monitor-api/test/asAdmin/test_search_count_AsAdmin.js similarity index 65% rename from elk-traffic-monitor-api/test/test_search_count.js rename to elk-traffic-monitor-api/test/asAdmin/test_search_count_AsAdmin.js index 090b215d..dd2387ff 100644 --- a/elk-traffic-monitor-api/test/test_search_count.js +++ b/elk-traffic-monitor-api/test/asAdmin/test_search_count_AsAdmin.js @@ -1,5 +1,9 @@ const { expect } = require('chai'); -const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('./_base'); +const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('../_base'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); describe('Endpoints', function () { this.timeout(30000); @@ -7,11 +11,26 @@ describe('Endpoints', function () { let auth; const indexName = `search_count_test_${getRandomInt(9999)}`; + beforeEach(() => { + // Simulate all responses in this test-file to be an admin, which will not lead to any result restriction + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "david" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/adminUserDavid.json'); + }); + + afterEach(() => { + nock.cleanAll(); + }); + /** * Start API Builder. */ before(() => { return new Promise(function(resolve, reject){ + debugger; + const envFilePath = path.join(__dirname, '../.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } server = startApiBuilder(); auth = { user: server.apibuilder.config.apikey || 'test', @@ -21,7 +40,7 @@ describe('Endpoints', function () { elasticConfig = server.apibuilder.config.pluginConfig['@axway-api-builder-ext/api-builder-plugin-fn-elasticsearch'].elastic; server.started .then(() => { - const entryset = require('./documents/basic/search_count_documents'); + const entryset = require('../documents/basic/search_count_documents'); sendToElasticsearch(elasticConfig, indexName, entryset) .then(() => { resolve(); @@ -41,6 +60,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search`, + headers: { + 'cookie': 'VIDUSR=Search-Count-0001-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -59,6 +82,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?count=5`, + headers: { + 'cookie': 'VIDUSR=Search-Count-0002-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -77,6 +104,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?count=50`, + headers: { + 'cookie': 'VIDUSR=Search-Count-0003-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { diff --git a/elk-traffic-monitor-api/test/test_search_endpoint.js b/elk-traffic-monitor-api/test/asAdmin/test_search_endpoint_AsAdmin.js similarity index 79% rename from elk-traffic-monitor-api/test/test_search_endpoint.js rename to elk-traffic-monitor-api/test/asAdmin/test_search_endpoint_AsAdmin.js index 1de1f97f..dc5c1c5c 100644 --- a/elk-traffic-monitor-api/test/test_search_endpoint.js +++ b/elk-traffic-monitor-api/test/asAdmin/test_search_endpoint_AsAdmin.js @@ -1,6 +1,10 @@ const { expect } = require('chai'); -const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('./_base'); -const getDate = require('./util'); +const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('../_base'); +const getDate = require('../util'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); describe('Endpoints', function () { this.timeout(30000); @@ -8,11 +12,25 @@ describe('Endpoints', function () { let auth; const indexName = `search_test_${getRandomInt(9999)}`; + beforeEach(() => { + // Simulate all responses in this test-file to be an admin, which will not lead to any result restriction + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "david" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/adminUserDavid.json'); + }); + + afterEach(() => { + nock.cleanAll(); + }); + /** * Start API Builder. */ before(() => { return new Promise(function(resolve, reject){ + const envFilePath = path.join(__dirname, '../.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } server = startApiBuilder(); auth = { user: server.apibuilder.config.apikey || 'test', @@ -22,7 +40,7 @@ describe('Endpoints', function () { elasticConfig = server.apibuilder.config.pluginConfig['@axway-api-builder-ext/api-builder-plugin-fn-elasticsearch'].elastic; server.started .then(() => { - const entryset = require('./documents/basic/search_test_documents'); + const entryset = require('../documents/basic/search_test_documents'); sendToElasticsearch(elasticConfig, indexName, entryset) .then(() => { resolve(); @@ -42,6 +60,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search`, + headers: { + 'cookie': 'VIDUSR=Search-0001-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -65,6 +87,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-2/ops/search`, + headers: { + 'cookie': 'VIDUSR=Search-0002-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -84,6 +110,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=uri&value=%2Fv2%2Fpet%2FfindByStatus&field=method&value=GET`, + headers: { + 'cookie': 'VIDUSR=Search-0003-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -104,6 +134,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=duration&op=gt&value=100`, + headers: { + 'cookie': 'VIDUSR=Search-0004-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -122,6 +156,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=operation&value=findPetsByStatus`, + headers: { + 'cookie': 'VIDUSR=Search-0005-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -141,6 +179,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?ago=5m`, // The first entry is generated with 8 minutes in the past + headers: { + 'cookie': 'VIDUSR=Search-0006-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -170,6 +212,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=timestamp&op=gt&value=${greaterThenThisDate}&field=timestamp&op=lt&value=${lowerThanThisDate}`, + headers: { + 'cookie': 'VIDUSR=Search-0007-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -202,6 +248,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=timestamp&op=gt&value=${greaterThenThisDate}&field=timestamp&op=lt&value=${lowerThanThisDate}`, + headers: { + 'cookie': 'VIDUSR=Search-0008-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -222,6 +272,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=localPort&value=8080`, + headers: { + 'cookie': 'VIDUSR=Search-0009-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -241,6 +295,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=localPort&value=8080&field=subject&value=Chris-Test`, + headers: { + 'cookie': 'VIDUSR=Search-0010-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -260,6 +318,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=status&value=404`, + headers: { + 'cookie': 'VIDUSR=Search-0011-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -279,6 +341,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=localAddr&value=1.1.1.1`, + headers: { + 'cookie': 'VIDUSR=Search-0012-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -298,6 +364,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=remoteName&value=TestHost`, + headers: { + 'cookie': 'VIDUSR=Search-0013-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -317,6 +387,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=remotePort&value=59641`, + headers: { + 'cookie': 'VIDUSR=Search-0014-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -336,6 +410,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=serviceName&value=Petstore%20HTTP`, + headers: { + 'cookie': 'VIDUSR=Search-0015-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -355,6 +433,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=wafStatus&value=1`, + headers: { + 'cookie': 'VIDUSR=Search-0016-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -374,6 +456,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=correlationId&value=682c0f5fbe23dc8e1d80efe2`, + headers: { + 'cookie': 'VIDUSR=Search-0017-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -393,6 +479,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=finalStatus&value=Error`, + headers: { + 'cookie': 'VIDUSR=Search-0018-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -411,6 +501,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?field=uri&value=%2Fv2%2Fpet`, + headers: { + 'cookie': 'VIDUSR=Search-0019-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -429,6 +523,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?ago=10m`, + headers: { + 'cookie': 'VIDUSR=Search-0020-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -447,6 +545,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?ago=30m`, + headers: { + 'cookie': 'VIDUSR=Search-0021-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -465,6 +567,10 @@ describe('Endpoints', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search?ago=2h`, + headers: { + 'cookie': 'VIDUSR=Search-0022-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { diff --git a/elk-traffic-monitor-api/test/test_trace_endpoint.js b/elk-traffic-monitor-api/test/asAdmin/test_trace_endpoint.js similarity index 70% rename from elk-traffic-monitor-api/test/test_trace_endpoint.js rename to elk-traffic-monitor-api/test/asAdmin/test_trace_endpoint.js index b2ad19a3..525c510b 100644 --- a/elk-traffic-monitor-api/test/test_trace_endpoint.js +++ b/elk-traffic-monitor-api/test/asAdmin/test_trace_endpoint.js @@ -1,5 +1,9 @@ const { expect } = require('chai'); -const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('./_base'); +const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('../_base'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); describe('Traffic Monitor API', function () { this.timeout(30000); @@ -7,11 +11,25 @@ describe('Traffic Monitor API', function () { let auth; const indexName = `trace_test_${getRandomInt(9999)}`; + beforeEach(() => { + // Simulate all responses in this test-file to be an admin, which will not lead to any result restriction + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "david" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/adminUserDavid.json'); + }); + + afterEach(() => { + nock.cleanAll(); + }); + /** * Start API Builder. */ before(() => { return new Promise(function(resolve, reject){ + const envFilePath = path.join(__dirname, '../.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } server = startApiBuilder(); auth = { user: server.apibuilder.config.apikey || 'test', @@ -21,7 +39,7 @@ describe('Traffic Monitor API', function () { elasticConfig = server.apibuilder.config.pluginConfig['@axway-api-builder-ext/api-builder-plugin-fn-elasticsearch'].elastic; server.started .then(() => { - const entryset = require('./documents/basic/trace_test_documents'); + const entryset = require('../documents/basic/trace_test_documents'); sendToElasticsearch(elasticConfig, indexName, entryset) .then(() => { resolve(); @@ -42,6 +60,10 @@ describe('Traffic Monitor API', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/trace/81adfd5ef8008da2d6186cdb`, + headers: { + 'cookie': 'VIDUSR=trace-0001-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -55,6 +77,10 @@ describe('Traffic Monitor API', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/trace/81adfd5ef8008da2d6186cdb?format=json`, + headers: { + 'cookie': 'VIDUSR=trace-0002-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -68,6 +94,10 @@ describe('Traffic Monitor API', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/trace/81adfd5ef8008da2d6186cdb?format=xml`, + headers: { + 'cookie': 'VIDUSR=trace-0003-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -82,6 +112,10 @@ describe('Traffic Monitor API', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/trace/f1aefd5e3501dd00a16eebc0`, + headers: { + 'cookie': 'VIDUSR=trace-0004-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { @@ -104,6 +138,10 @@ describe('Traffic Monitor API', function () { return requestAsync({ method: 'GET', uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/trace/5bb7e85e940e4dcca856cd26?format=json`, + headers: { + 'cookie': 'VIDUSR=trace-0005-DAVID-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, auth: auth, json: true }).then(({ response, body }) => { diff --git a/elk-traffic-monitor-api/test/documents/basic/circuitpath_test_documents.js b/elk-traffic-monitor-api/test/documents/basic/circuitpath_test_documents.js index 591aed5f..bd2bc26d 100644 --- a/elk-traffic-monitor-api/test/documents/basic/circuitpath_test_documents.js +++ b/elk-traffic-monitor-api/test/documents/basic/circuitpath_test_documents.js @@ -149,7 +149,11 @@ module.exports = [ "method": "findPetsByStatus", "status": "success", "duration": 775, - "client": "Pass Through" + "client": "Pass Through", + "apiOrg": "Chris Org", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" } , "path": "/v2/pet/findByStatus", diff --git a/elk-traffic-monitor-api/test/documents/basic/getinfo_test_documents.js b/elk-traffic-monitor-api/test/documents/basic/getinfo_test_documents.js index 92967665..6cea4763 100644 --- a/elk-traffic-monitor-api/test/documents/basic/getinfo_test_documents.js +++ b/elk-traffic-monitor-api/test/documents/basic/getinfo_test_documents.js @@ -167,7 +167,11 @@ module.exports = [ "client": "Pass Through", "status": "success", "duration": 383, - "method": "Get-all-todo-items" + "method": "Get-all-todo-items", + "apiOrg": "Chris Org", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" } , "protocolSrc": "8065", diff --git a/elk-traffic-monitor-api/test/documents/basic/search_count_documents.js b/elk-traffic-monitor-api/test/documents/basic/search_count_documents.js index 1026d905..8cf81bdc 100644 --- a/elk-traffic-monitor-api/test/documents/basic/search_count_documents.js +++ b/elk-traffic-monitor-api/test/documents/basic/search_count_documents.js @@ -528,7 +528,11 @@ module.exports = [ "service": "Petstore", "client": "4e8634ba-6762-45ca-bbe5-7ca4e99192ac", "monitor": true, - "status": "success" + "status": "success", + "apiOrg": "Chris Org", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" }, "protocolSrc": "8065", "status": "success" @@ -704,7 +708,11 @@ module.exports = [ "service": "Petstore", "client": "4e8634ba-6762-45ca-bbe5-7ca4e99192ac", "monitor": true, - "status": "success" + "status": "success", + "apiOrg": "Max Org", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" }, "protocolSrc": "8065", "status": "success" @@ -880,7 +888,11 @@ module.exports = [ "service": "Petstore", "client": "4e8634ba-6762-45ca-bbe5-7ca4e99192ac", "monitor": true, - "status": "success" + "status": "success", + "apiOrg": "API Development", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" }, "protocolSrc": "8065", "status": "success" @@ -1056,7 +1068,11 @@ module.exports = [ "service": "Petstore", "client": "4e8634ba-6762-45ca-bbe5-7ca4e99192ac", "monitor": true, - "status": "success" + "status": "success", + "apiOrg": "API Development", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" }, "protocolSrc": "8065", "status": "success" @@ -1232,7 +1248,11 @@ module.exports = [ "service": "Petstore", "client": "4e8634ba-6762-45ca-bbe5-7ca4e99192ac", "monitor": true, - "status": "success" + "status": "success", + "apiOrg": "Chris Org", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" }, "protocolSrc": "8065", "status": "success" @@ -1408,7 +1428,11 @@ module.exports = [ "service": "Petstore", "client": "4e8634ba-6762-45ca-bbe5-7ca4e99192ac", "monitor": true, - "status": "success" + "status": "success", + "apiOrg": "API Development", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" }, "protocolSrc": "8065", "status": "success" @@ -1584,7 +1608,11 @@ module.exports = [ "service": "Petstore", "client": "4e8634ba-6762-45ca-bbe5-7ca4e99192ac", "monitor": true, - "status": "success" + "status": "success", + "apiOrg": "API Development", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" }, "protocolSrc": "8065", "status": "success" @@ -1760,7 +1788,11 @@ module.exports = [ "service": "Petstore", "client": "4e8634ba-6762-45ca-bbe5-7ca4e99192ac", "monitor": true, - "status": "success" + "status": "success", + "apiOrg": "API Development", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" }, "protocolSrc": "8065", "status": "success" @@ -1936,7 +1968,11 @@ module.exports = [ "service": "Petstore", "client": "4e8634ba-6762-45ca-bbe5-7ca4e99192ac", "monitor": true, - "status": "success" + "status": "success", + "apiOrg": "Max Org", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" }, "protocolSrc": "8065", "status": "success" diff --git a/elk-traffic-monitor-api/test/documents/basic/search_test_documents.js b/elk-traffic-monitor-api/test/documents/basic/search_test_documents.js index fd66634a..1017c736 100644 --- a/elk-traffic-monitor-api/test/documents/basic/search_test_documents.js +++ b/elk-traffic-monitor-api/test/documents/basic/search_test_documents.js @@ -528,7 +528,11 @@ module.exports = [ "service" : "Petstore", "client" : "4e8634ba-6762-45ca-bbe5-7ca4e99192ac", "monitor" : true, - "status" : "success" + "status" : "success", + "apiOrg": "API Development", + "apiVersion": "1.0.5", + "apiDeprecated": false, + "apiState": "published" }, "protocolSrc" : "8065", "status" : "success" diff --git a/elk-traffic-monitor-api/test/mockedReplies/apigateway/adminUserDavid.json b/elk-traffic-monitor-api/test/mockedReplies/apigateway/adminUserDavid.json new file mode 100644 index 00000000..81dfae93 --- /dev/null +++ b/elk-traffic-monitor-api/test/mockedReplies/apigateway/adminUserDavid.json @@ -0,0 +1,33 @@ +{ + "result": { + "user": "david", + "permissions": [ + "ama_modify", + "fips_modify", + "group_force_unlock", + "traffic_monitor", + "deploy", + "domain_audit", + "domain_audit_modify", + "logs", + "dashboard", + "events", + "adminusers_passwordpolicy_modify", + "settings_modify", + "adminusers", + "settings", + "dashboard_modify", + "fips_read", + "mgmt_modify", + "adminusers_modify", + "monitoring", + "adminusers_reset", + "mgmt", + "ama", + "discovery", + "adminusers_advisorybanner_modify", + "emc", + "config" + ] + } +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/mockedReplies/apigateway/operatorChris.json b/elk-traffic-monitor-api/test/mockedReplies/apigateway/operatorChris.json new file mode 100644 index 00000000..b6ddc699 --- /dev/null +++ b/elk-traffic-monitor-api/test/mockedReplies/apigateway/operatorChris.json @@ -0,0 +1,19 @@ +{ + "result": { + "user": "chris", + "permissions": [ + "adminusers", + "settings", + "mgmt", + "ama", + "fips_read", + "emc", + "traffic_monitor", + "monitoring", + "logs", + "adminusers_reset", + "dashboard", + "events" + ] + } +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/mockedReplies/apigateway/operatorMax.json b/elk-traffic-monitor-api/test/mockedReplies/apigateway/operatorMax.json new file mode 100644 index 00000000..839c584c --- /dev/null +++ b/elk-traffic-monitor-api/test/mockedReplies/apigateway/operatorMax.json @@ -0,0 +1,19 @@ +{ + "result": { + "user": "max", + "permissions": [ + "adminusers", + "settings", + "mgmt", + "ama", + "fips_read", + "emc", + "traffic_monitor", + "monitoring", + "logs", + "adminusers_reset", + "dashboard", + "events" + ] + } +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/mockedReplies/apigateway/operatorRene.json b/elk-traffic-monitor-api/test/mockedReplies/apigateway/operatorRene.json new file mode 100644 index 00000000..a43b90f2 --- /dev/null +++ b/elk-traffic-monitor-api/test/mockedReplies/apigateway/operatorRene.json @@ -0,0 +1,19 @@ +{ + "result": { + "user": "rene", + "permissions": [ + "adminusers", + "settings", + "mgmt", + "ama", + "fips_read", + "emc", + "traffic_monitor", + "monitoring", + "logs", + "adminusers_reset", + "dashboard", + "events" + ] + } +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/mockedReplies/apimanager/apiManagerUserChris.json b/elk-traffic-monitor-api/test/mockedReplies/apimanager/apiManagerUserChris.json new file mode 100644 index 00000000..cb94e74b --- /dev/null +++ b/elk-traffic-monitor-api/test/mockedReplies/apimanager/apiManagerUserChris.json @@ -0,0 +1,15 @@ +[ + { + "id": "d66a42d6-b9c7-4efd-b33a-de8b88545861", + "organizationId": "2bfaa1c2-49ab-4059-832d-CHRIS", + "name": "Chris", + "loginName": "chris", + "email": "chris@axway.com", + "role": "oadmin", + "enabled": true, + "createdOn": 1597338071490, + "state": "approved", + "type": "internal", + "dn": "cn=chris,o=API Development,ou=organizations,ou=APIPortal" + } +] \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/mockedReplies/apimanager/apiManagerUserMax.json b/elk-traffic-monitor-api/test/mockedReplies/apimanager/apiManagerUserMax.json new file mode 100644 index 00000000..b9e61595 --- /dev/null +++ b/elk-traffic-monitor-api/test/mockedReplies/apimanager/apiManagerUserMax.json @@ -0,0 +1,15 @@ +[ + { + "id": "d66a42d6-b9c7-4efd-b33a-de8b88545861", + "organizationId": "2bfaa1c2-49ab-4059-832d-MAX", + "name": "Max", + "loginName": "max", + "email": "max@axway.com", + "role": "admin", + "enabled": true, + "createdOn": 1597338071490, + "state": "approved", + "type": "internal", + "dn": "cn=chris,o=API Development,ou=organizations,ou=APIPortal" + } +] \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/mockedReplies/apimanager/apiManagerUserRene.json b/elk-traffic-monitor-api/test/mockedReplies/apimanager/apiManagerUserRene.json new file mode 100644 index 00000000..7a99a696 --- /dev/null +++ b/elk-traffic-monitor-api/test/mockedReplies/apimanager/apiManagerUserRene.json @@ -0,0 +1,15 @@ +[ + { + "id": "d66a42d6-b9c7-4efd-b33a-de8b88545861", + "organizationId": "2bfaa1c2-49ab-4059-832d-MAX", + "name": "Rene", + "loginName": "Rene", + "email": "rene@axway.com", + "role": "user", + "enabled": true, + "createdOn": 1597338071490, + "state": "approved", + "type": "internal", + "dn": "cn=chris,o=API Development,ou=organizations,ou=APIPortal" + } +] \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/mockedReplies/apimanager/oneApiProxyFound.json b/elk-traffic-monitor-api/test/mockedReplies/apimanager/oneApiProxyFound.json new file mode 100644 index 00000000..0f223c06 --- /dev/null +++ b/elk-traffic-monitor-api/test/mockedReplies/apimanager/oneApiProxyFound.json @@ -0,0 +1,166 @@ +[ + { + "id": "55a27047-a9dc-4d43-ad11-2cbf7a239f8a", + "organizationId": "2bfaa1c2-49ab-4059-832d-CHRIS", + "apiId": "06c58f1c-3f43-40e0-b752-63b6dd2f7d1c", + "name": "Petstore HTTPS", + "version": "1.0.5", + "apiRoutingKey": null, + "vhost": null, + "path": "/my/api/exists", + "descriptionType": "original", + "descriptionManual": null, + "descriptionMarkdown": null, + "descriptionUrl": null, + "summary": null, + "retired": false, + "expired": false, + "image": null, + "retirementDate": 0, + "deprecated": false, + "state": "published", + "createdOn": 1597676259637, + "createdBy": "f60e3e05-cdf3-4b70-affc-4cb61a10f4bb", + "corsProfiles": [ + { + "name": "_default", + "isDefault": true, + "origins": [ + "*" + ], + "allowedHeaders": [], + "exposedHeaders": [ + "X-CorrelationID" + ], + "supportCredentials": false, + "maxAgeSeconds": 0 + } + ], + "securityProfiles": [ + { + "name": "_default", + "isDefault": true, + "devices": [ + { + "name": "API Key", + "type": "apiKey", + "order": 1, + "properties": { + "apiKeyFieldName": "KeyId", + "takeFrom": "HEADER", + "removeCredentialsOnSuccess": "true" + } + } + ] + } + ], + "authenticationProfiles": [ + { + "name": "_default", + "isDefault": true, + "parameters": { + "_id_": 0 + }, + "type": "none" + } + ], + "inboundProfiles": { + "_default": { + "securityProfile": "_default", + "corsProfile": "_default", + "monitorAPI": true, + "monitorSubject": "authentication.subject.id" + } + }, + "outboundProfiles": { + "_default": { + "authenticationProfile": "_default", + "routeType": "proxy", + "requestPolicy": null, + "responsePolicy": null, + "routePolicy": null, + "faultHandlerPolicy": null, + "apiId": null, + "apiMethodId": null, + "parameters": [] + } + }, + "serviceProfiles": { + "_default": { + "apiId": "06c58f1c-3f43-40e0-b752-63b6dd2f7d1c", + "basePath": "https://petstore.swagger.io" + } + }, + "caCerts": [ + { + "certBlob": "MIIFYDCCBEigAwIBAgIQBHaGXD1xHK+7DIzsNpFHkjANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2ZXIgQ0EgMUIxDzANBgNVBAMTBkFtYXpvbjAeFw0yMDA0MTUwMDAwMDBaFw0yMTA1MTUxMjAwMDBaMBcxFTATBgNVBAMMDCouc3dhZ2dlci5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANASN8RW6mBBxfSnwbQOANV2MbRtXYFj+RcZTCeN2GrltOKfhfpI89KNXVmHkqhUjC9FyS9XVQC5XsUGuR2BiCwYDpd13pgFqp0jQDv95IosqPLILQJZVoKerB5xsetRAA/5HYh2EKptJnPkjvj0ZDeNOW32IVzNEG+KZEwnJ0DXp7PQqJrkEmsLfbB413ZJXFFlMgGTP98nfzLewuS3AwlF96Il0BMyFa3UGAvB6LVEauqy7nxxMNmv/vKfA9fi+j7Q9heQCzihal9xUzgh1xSeu5V8M862wHNNkyDDzCYJ3aqGfUF22nnDju4U/+UhLQdshpb4qgb/skfrA3wFKvkCAwEAAaOCAncwggJzMB8GA1UdIwQYMBaAFFmkZgZSoHuVkjyjlAcnlnRb+T3QMB0GA1UdDgQWBBS8ra9FacL0+YDHMzSNEA0IhrYZzDAXBgNVHREEEDAOggwqLnN3YWdnZXIuaW8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3JsLnNjYTFiLmFtYXpvbnRydXN0LmNvbS9zY2ExYi5jcmwwIAYDVR0gBBkwFzALBglghkgBhv1sAQIwCAYGZ4EMAQIBMHUGCCsGAQUFBwEBBGkwZzAtBggrBgEFBQcwAYYhaHR0cDovL29jc3Auc2NhMWIuYW1hem9udHJ1c3QuY29tMDYGCCsGAQUFBzAChipodHRwOi8vY3J0LnNjYTFiLmFtYXpvbnRydXN0LmNvbS9zY2ExYi5jcnQwDAYDVR0TAQH/BAIwADCCAQMGCisGAQQB1nkCBAIEgfQEgfEA7wB2APZclC/RdzAiFFQYCDCUVo7jTRMZM7/fDC8gC8xO8WTjAAABcXtMbIsAAAQDAEcwRQIgaRRwZ/FIuyRHVCa3nK8Ype9EIQNgvFsSnSiYmU3RE6wCIQCQ7ZZkTIW845VmjBJbj46tiGSkG0MzuCiSCPTws6GILQB1AFzcQ5L+5qtFRLFemtRW5hA3+9X6R9yhc5SyXub2xw7KAAABcXtMbLgAAAQDAEYwRAIgfuJGxXn/P2jCCcQS/Z3R2M8u1CV69urvEVQmlnILZJMCIAbd8o82SzcZnzKVYF653+CVH+N6GX2DmwMJ3b81H+MPMA0GCSqGSIb3DQEBCwUAA4IBAQABHMtwCTgDX/RfNwFgCg1Gveq1ut1jVg7jvagglF5keEhDWOVNrRbEuODPf3YmiFsXwngxn5ng7fZdi/xRSRqN4uQqc8KykGgFe7LX+SgcHGkjqfUJ5JbiW0D9Jtw5MDZpBvevBr31gW253V0mL4yAlwBy8F0X0Ny4NJJSkovwLYprM4aglEOpSQvW45pOWccGAvkgayW8zBBIrj7B2jSjBtCdjO1SeMQNLmkErz7/aCnsRSC+Kaw2kfiIrRtwDEuKCa2IgemmlUA1xvIR1GrRwz05QZlCuae6/uvvaqotFWCxdnNtnbUu13Hb7KPCcy742yODpso0R7RAGzFA6Kgo", + "name": "CN=*.swagger.io", + "alias": "CN=*.swagger.io", + "subject": "CN=*.swagger.io", + "issuer": "CN=Amazon, OU=Server CA 1B, O=Amazon, C=US", + "version": 3, + "notValidBefore": 1586908800000, + "notValidAfter": 1621080000000, + "signatureAlgorithm": "RSA (2048 bits)", + "sha1Fingerprint": "2E:40:92:83:A6:F5:FC:C1:1D:F3:18:3B:7A:08:0E:CA:04:72:53:B6", + "md5Fingerprint": "81:AD:AF:05:B1:39:ED:FF:BE:EE:79:94:28:B3:F2:10", + "expired": false, + "notYetValid": false, + "inbound": false, + "outbound": true + }, + { + "certBlob": "MIIESTCCAzGgAwIBAgITBn+UV4WH6Kx33rJTMlu8mYtWDTANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENBIDFCMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCThZn3c68asg3Wuw6MLAd5tES6BIoSMzoKcG5blPVo+sDORrMd4f2AbnZcMzPa43j4wNxhplty6aUKk4T1qe9BOwKFjwK6zmxxLVYo7bHViXsPlJ6qOMpFge5blDP+18x+B26A0piiQOuPkfyDyeR4xQghfj66Yo19V+emU3nazfvpFA+ROz6WoVmB5x+F2pV8xeKNR7u6azDdU5YVX1TawprmxRC1+WsAYmz6qP+z8ArDITC2FMVy2fw0IjKOtEXc/VfmtTFch5+AfGYMGMqqvJ6LcXiAhqG5TI+Dr0RtM88k+8XUBCeQ8IGKuANaL7TiItKZYxK1MMuTJtV9IblAgMBAAGjggE7MIIBNzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUWaRmBlKge5WSPKOUByeWdFv5PdAwHwYDVR0jBBgwFoAUhBjMhTTsvAyUlC4IWZzHshBOCggwewYIKwYBBQUHAQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5yb290Y2ExLmFtYXpvbnRydXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NydC5yb290Y2ExLmFtYXpvbnRydXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY3JsMBMGA1UdIAQMMAowCAYGZ4EMAQIBMA0GCSqGSIb3DQEBCwUAA4IBAQCFkr41u3nPo4FCHOTjY3NTOVI159Gt/a6ZiqyJEi+752+a1U5y6iAwYfmXss2lJwJFqMp2PphKg5625kXg8kP2CN5t6G7bMQcT8C8xDZNtYTd7WPD8UZiRKAJPBXa30/AbwuZe0GaFEQ8ugcYQgSn+IGBI8/LwhBNTZTUVEWuCUUBVV18YtbAiPq3yXqMB48Oz+ctBWuZSkbvkNodPLamkB2g1upRyzQ7qDn1X8nn8N8V7YJ6y68AtkHcNSRAnpTitxBKjtKPISLMVCx7i4hncxHZSyLyKQXhw2W2Xs0qLeC1etA+jTGDK4UfLeC0SF7FSi8o5LL21L8IzApar2pR/", + "name": "CN=Amazon, OU=Server CA 1B, O=Amazon, C=US", + "alias": "CN=Amazon, OU=Server CA 1B, O=Amazon, C=US", + "subject": "CN=Amazon, OU=Server CA 1B, O=Amazon, C=US", + "issuer": "CN=Amazon Root CA 1, O=Amazon, C=US", + "version": 3, + "notValidBefore": 1445472000000, + "notValidAfter": 1760832000000, + "signatureAlgorithm": "RSA (2048 bits)", + "sha1Fingerprint": "91:7E:73:2D:33:0F:9A:12:40:4F:73:D8:BE:A3:69:48:B9:29:DF:FC", + "md5Fingerprint": "EB:26:8E:55:D4:34:FE:BD:A3:6A:97:9A:44:65:4B:6D", + "expired": false, + "notYetValid": false, + "inbound": false, + "outbound": true + }, + { + "certBlob": "MIIEkjCCA3qgAwIBAgITBn+USionzfP6wq4rAfkI7rnExjANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTE1MDUyNTEyMDAwMFoXDTM3MTIzMTAxMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaOCATEwggEtMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSEGMyFNOy8DJSULghZnMeyEE4KCDAfBgNVHSMEGDAWgBScXwDfqgHXMCs4iKK4bUqc8hGRgzB4BggrBgEFBQcBAQRsMGowLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLnJvb3RnMi5hbWF6b250cnVzdC5jb20wOAYIKwYBBQUHMAKGLGh0dHA6Ly9jcnQucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY2VyMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQsFAAOCAQEAYjdCXLwQtT6LLOkMm2xF4gcAevnFWAu5CIw+7bMlPLVvUOTNNWqnkzSWMiGpSESrnO09tKpzbeR/FoCJbM8oAxiDR3mjEH4wW6w7sGDgd9QIpuEdfF7Au/maeyKdpwAJfqxGF4PcnCZXmTA5YpaP7dreqsXMGz7KQ2hsVxa81Q4gLv7/wmpdLqBKbRRYh5TmOTFffHPLkIhqhBGWJ6bt2YFGpn6jcgAKUj6DiAdjd4lpFw85hdKrCEVN0FE6/V1dN2RMfjCyVSRCnTawXZwXgWHxyvkQAiSr6w10kY17RSlQOYiypok1JR4UakcjMS9cmvqtmg5iUaQqqcT5NJ0hGA==", + "name": "CN=Amazon Root CA 1, O=Amazon, C=US", + "alias": "CN=Amazon Root CA 1, O=Amazon, C=US", + "subject": "CN=Amazon Root CA 1, O=Amazon, C=US", + "issuer": "CN=Starfield Services Root Certificate Authority - G2, O=\"Starfield Technologies, Inc.\", L=Scottsdale, ST=Arizona, C=US", + "version": 3, + "notValidBefore": 1432555200000, + "notValidAfter": 2145834000000, + "signatureAlgorithm": "RSA (2048 bits)", + "sha1Fingerprint": "06:B2:59:27:C4:2A:72:16:31:C1:EF:D9:43:1E:64:8F:A6:2E:1E:39", + "md5Fingerprint": "E8:65:A2:2A:AE:52:4D:26:86:9A:F0:44:8D:6F:D8:96", + "expired": false, + "notYetValid": false, + "inbound": false, + "outbound": true + }, + { + "certBlob": "MIIEdTCCA12gAwIBAgIJAKcOSkw0grd/MA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wOTA5MDIwMDAwMDBaFw0zNDA2MjgxNzM5MTZaMIGYMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZpZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVDDrEKvlO4vW+GZdfjohTsR8/y8+fIBNtKTrID30892t2OGPZNmCom15cAICyL1l/9of5JUOG52kbUpqQ4XHj2C0NTm/2yEnZtvMaVq4rtnQU68/7JuMauh2WLmo7WJSJR1b/JaCTcFOD2oR0FMNnngRoOt+OQFodSk7PQ5E751bWAHDLUu57fa4657wx+UX2wmDPE1kCK4DMNEffud6QZW0CzyyRpqbn3oUYSXxmTqM6bam17jQuug0DuDPfR+uxa40l2ZvOgdFFRjKWcIfeAg5JQ4W2bHO7ZOphQazJ1FTfhy/HIrImzJ9ZVGif/L4qL8RVHHVAYBeFAlU5i38FAgMBAAGjgfAwge0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMB8GA1UdIwQYMBaAFL9ft9HO3R+G9FtVrNzXEMIOqYjnME8GCCsGAQUFBwEBBEMwQTAcBggrBgEFBQcwAYYQaHR0cDovL28uc3MyLnVzLzAhBggrBgEFBQcwAoYVaHR0cDovL3guc3MyLnVzL3guY2VyMCYGA1UdHwQfMB0wG6AZoBeGFWh0dHA6Ly9zLnNzMi51cy9yLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBACMd44pXyn3pF3lM8R5V/cxTbj5HD9/GVfKyBDbtgB9TxF00KGu+x1X8Z+rLP3+QsjPNG1gQggL4+C/1E2DUBc7xgQjB3ad1l08YuW3e95ORCLp+QCztweq7dp4zBncdDQh/U90bZKuCJ/Fp1U1ervShw3WnWEQt8jxwmKy6abaVd38PMV4s/KCHOkdp8Hlf9BRUpJVeEXgSYCfOn8J3/yNTd126/+pZ59vPr5KW7ySaNRB6nJHGDn2Z9j8Z3/VyVOEVqQdZe4O/Ui5GjLIAZHYcSNPYeehuVsyuLAOQ1xk4meTKCRlb/weWsKh/NEnfVqn3sF/tM+2MR7cwA130A4w=", + "name": "CN=Starfield Services Root Certificate Authority - G2, O=\"Starfield Technologies, Inc.\", L=Scottsdale, ST=Arizona, C=US", + "alias": "CN=Starfield Services Root Certificate Authority - G2, O=\"Starfield Technologies, Inc.\", L=Scottsdale, ST=Arizona, C=US", + "subject": "CN=Starfield Services Root Certificate Authority - G2, O=\"Starfield Technologies, Inc.\", L=Scottsdale, ST=Arizona, C=US", + "issuer": "OU=Starfield Class 2 Certification Authority, O=\"Starfield Technologies, Inc.\", C=US", + "version": 3, + "notValidBefore": 1251849600000, + "notValidAfter": 2035129156000, + "signatureAlgorithm": "RSA (2048 bits)", + "sha1Fingerprint": "9E:99:A4:8A:99:60:B1:49:26:BB:7F:3B:02:E2:2D:A2:B0:AB:72:80", + "md5Fingerprint": "C6:15:09:25:CF:EA:59:41:DD:C7:FF:2A:0A:50:66:92", + "expired": false, + "notYetValid": false, + "inbound": false, + "outbound": true + } + ], + "tags": {} + } +] \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/mockedReplies/apimanager/organizationChris.json b/elk-traffic-monitor-api/test/mockedReplies/apimanager/organizationChris.json new file mode 100644 index 00000000..8c1d69d7 --- /dev/null +++ b/elk-traffic-monitor-api/test/mockedReplies/apimanager/organizationChris.json @@ -0,0 +1,18 @@ +{ + "id": "2bfaa1c2-49ab-4059-832d-CHRIS", + "name": "Chris Org", + "description": null, + "email": null, + "image": null, + "restricted": false, + "virtualHost": null, + "phone": null, + "enabled": true, + "development": true, + "dn": "o=Chris Org,ou=organizations,ou=APIPortal", + "createdOn": 1597326913559, + "startTrialDate": null, + "endTrialDate": null, + "trialDuration": null, + "isTrial": null +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/mockedReplies/apimanager/organizationMax.json b/elk-traffic-monitor-api/test/mockedReplies/apimanager/organizationMax.json new file mode 100644 index 00000000..beda0633 --- /dev/null +++ b/elk-traffic-monitor-api/test/mockedReplies/apimanager/organizationMax.json @@ -0,0 +1,18 @@ +{ + "id": "2bfaa1c2-49ab-4059-832d-MAX", + "name": "Max Org", + "description": null, + "email": null, + "image": null, + "restricted": false, + "virtualHost": null, + "phone": null, + "enabled": true, + "development": true, + "dn": "o=Max Org,ou=organizations,ou=APIPortal", + "createdOn": 1597326913559, + "startTrialDate": null, + "endTrialDate": null, + "trialDuration": null, + "isTrial": null +} \ No newline at end of file diff --git a/elk-traffic-monitor-api/test/restricted/test_circuitpath_restricted.js b/elk-traffic-monitor-api/test/restricted/test_circuitpath_restricted.js new file mode 100644 index 00000000..4ae7a785 --- /dev/null +++ b/elk-traffic-monitor-api/test/restricted/test_circuitpath_restricted.js @@ -0,0 +1,99 @@ +const { expect } = require('chai'); +const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('../_base'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); + +describe('Traffic Monitor API', function () { + this.timeout(30000); + let server; + let auth; + const indexName = `circuitpath_test_${getRandomInt(9999)}`; + + /** + * Start API Builder. + */ + before(() => { + return new Promise(function(resolve, reject){ + const envFilePath = path.join(__dirname, '../.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } + server = startApiBuilder(); + auth = { + user: server.apibuilder.config.apikey || 'test', + password: '' + }; + server.apibuilder.config.testElasticIndex = indexName; + elasticConfig = server.apibuilder.config.pluginConfig['@axway-api-builder-ext/api-builder-plugin-fn-elasticsearch'].elastic; + server.started + .then(() => { + const entryset = require('../documents/basic/circuitpath_test_documents'); + sendToElasticsearch(elasticConfig, indexName, entryset) + .then(() => { + resolve(); + }) + .catch(err => reject(err)); + }); + }); + }); + + /** + * Stop API Builder after the tests. + */ + after(() => stopApiBuilder(server)); + + describe('circuitpath endpoint tests', () => { + it('[restricted-circuitpath-0001] Should return http 200 and (API Broker/HTTP Petstore) Policy with 2 filters as the transaction belongs to users organization', () => { + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "chris" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/operatorChris.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=chris&field=enabled&op=eq&value=enabled`).replyWithFile(200, './test/mockedReplies/apimanager/apiManagerUserChris.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-CHRIS`).replyWithFile(200, './test/mockedReplies/apimanager/organizationChris.json'); + return requestAsync({ + method: 'GET', + uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/stream/c8705e5ecc00adca32be7472/*/circuitpath`, + headers: { + 'cookie': 'VIDUSR=restricted-circuitpath-0001-CHRIS-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, + auth: auth, + json: true + }).then(({ response, body }) => { + expect(response.statusCode).to.equal(200); + expect(body).to.be.an('Array'); + expect(body).to.have.lengthOf(1); + expect(body[0]).to.be.an('Object'); + expect(body[0]).to.have.property('policy'); + expect(body[0].policy).to.equal('API Broker'); + expect(body[0].filters).to.be.an('Array'); + expect(body[0].filters).to.have.lengthOf(2); + expect(body[0].filters[0].status).to.equal('Pass'); + nock.cleanAll(); + }); + }); + + it('[restricted-circuitpath-0002] Should NOT return anything, as the transaction belongs to a different organization', () => { + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "rene" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/operatorRene.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=rene&field=enabled&op=eq&value=enabled`).replyWithFile(200, './test/mockedReplies/apimanager/apiManagerUserRene.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-MAX`).replyWithFile(200, './test/mockedReplies/apimanager/organizationMax.json'); + return requestAsync({ + method: 'GET', + uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/stream/c8705e5ecc00adca32be7472/*/circuitpath`, + headers: { + 'cookie': 'VIDUSR=restricted-circuitpath-0002-RENE-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, + auth: auth, + json: true + }).then(({ response, body }) => { + expect(response.statusCode).to.equal(200); + expect(body).to.be.an('Array'); + expect(body).to.have.lengthOf(0); + nock.cleanAll(); + }); + }); + }); +}); + diff --git a/elk-traffic-monitor-api/test/restricted/test_getinfo_endpoint_restricted.js b/elk-traffic-monitor-api/test/restricted/test_getinfo_endpoint_restricted.js new file mode 100644 index 00000000..afd0f8b1 --- /dev/null +++ b/elk-traffic-monitor-api/test/restricted/test_getinfo_endpoint_restricted.js @@ -0,0 +1,91 @@ +const { expect } = require('chai'); +const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('../_base'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); + +describe('Endpoints', function () { + this.timeout(30000); + let server; + let auth; + const indexName = `getinfo_test_${getRandomInt(9999)}`; + + /** + * Start API Builder. + */ + before(() => { + return new Promise(function(resolve, reject){ + const envFilePath = path.join(__dirname, '../.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } + server = startApiBuilder(); + auth = { + user: server.apibuilder.config.apikey || 'test', + password: '' + }; + server.apibuilder.config.testElasticIndex = indexName; + elasticConfig = server.apibuilder.config.pluginConfig['@axway-api-builder-ext/api-builder-plugin-fn-elasticsearch'].elastic; + server.started + .then(() => { + const entryset = require('../documents/basic/getinfo_test_documents'); + sendToElasticsearch(elasticConfig, indexName, entryset) + .then(() => { + resolve(); + }) + .catch(err => reject(err)); + }); + }); + }); + + /** + * Stop API Builder after the tests. + */ + after(() => stopApiBuilder(server)); + + describe('Search', () => { + + it('[Restricted-Getinfo-0001] Should return a result, as the transaction belongs to the users org', () => { + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "chris" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/operatorChris.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=chris&field=enabled&op=eq&value=enabled`).replyWithFile(200, './test/mockedReplies/apimanager/apiManagerUserChris.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-CHRIS`).replyWithFile(200, './test/mockedReplies/apimanager/organizationChris.json'); + return requestAsync({ + method: 'GET', + uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/http/0455ff5e82267be8182a553d/*/getinfo?format=json&details=1&rheaders=1&sheaders=1`, + headers: { + 'cookie': 'VIDUSR=Restricted-Getinfo-0001-CHRIS-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, + auth: auth, + json: true + }).then(({ response, body }) => { + expect(response.statusCode).to.equal(200); + expect(body).to.be.an('Array'); + expect(body).to.have.lengthOf(2); + nock.cleanAll(); + }); + }); + + it('[Restricted-Getinfo-0002 Should NOT return anything, as the transaction is for a different org', () => { + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "rene" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/operatorRene.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=rene&field=enabled&op=eq&value=enabled`).replyWithFile(200, './test/mockedReplies/apimanager/apiManagerUserRene.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-MAX`).replyWithFile(200, './test/mockedReplies/apimanager/organizationMax.json'); + return requestAsync({ + method: 'GET', + uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/http/0455ff5e82267be8182a553d/0/getinfo?format=json&details=1&rheaders=1&sheaders=1`, + headers: { + 'cookie': 'VIDUSR=Getinfo-0002-CHRIS-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, + auth: auth, + json: true + }).then(({ response, body }) => { + expect(response.statusCode).to.equal(500); + }); + }); + }); +}); + diff --git a/elk-traffic-monitor-api/test/restricted/test_search_restricted.js b/elk-traffic-monitor-api/test/restricted/test_search_restricted.js new file mode 100644 index 00000000..473b3c56 --- /dev/null +++ b/elk-traffic-monitor-api/test/restricted/test_search_restricted.js @@ -0,0 +1,121 @@ +const { expect } = require('chai'); +const { startApiBuilder, stopApiBuilder, requestAsync, sendToElasticsearch, getRandomInt } = require('../_base'); +const path = require('path'); +const fs = require('fs'); +const nock = require('nock'); +const envLoader = require('dotenv'); + +describe('Endpoints', function () { + this.timeout(30000); + let server; + let auth; + const indexName = `search_count_test_${getRandomInt(9999)}`; + + /** + * Start API Builder. + */ + before(() => { + return new Promise(function(resolve, reject){ + const envFilePath = path.join(__dirname, '../.env'); + if (fs.existsSync(envFilePath)) { + envLoader.config({ path: envFilePath }); + } + server = startApiBuilder(); + auth = { + user: server.apibuilder.config.apikey || 'test', + password: '' + }; + server.apibuilder.config.testElasticIndex = indexName; + elasticConfig = server.apibuilder.config.pluginConfig['@axway-api-builder-ext/api-builder-plugin-fn-elasticsearch'].elastic; + server.started + .then(() => { + const entryset = require('../documents/basic/search_count_documents'); + sendToElasticsearch(elasticConfig, indexName, entryset) + .then(() => { + resolve(); + }) + .catch(err => reject(err)); + }); + }); + }); + + /** + * Stop API Builder after the tests. + */ + after(() => { + stopApiBuilder(server); + }); + + describe('Search', () => { + it('[Restricted-Search-0001] Execute a search as Org-Admin without any filter - Only two of them belong to Chris-Org', () => { + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "chris" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/operatorChris.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=chris&field=enabled&op=eq&value=enabled`).replyWithFile(200, './test/mockedReplies/apimanager/apiManagerUserChris.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-CHRIS`).replyWithFile(200, './test/mockedReplies/apimanager/organizationChris.json'); + return requestAsync({ + method: 'GET', + uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search`, + headers: { + 'cookie': 'VIDUSR=Restricted-Search-0001-CHRIS-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, + auth: auth, + json: true + }).then(({ response, body }) => { + expect(response.statusCode).to.equal(200); + expect(body).to.be.an('Object'); + expect(body).to.have.property('data'); + expect(body.data).to.have.lengthOf(2); + nock.cleanAll(); + }); + }); + + it('[Restricted-Search-0002] Execute a search - NOT being an API-GW-Admin - But admin in API-Manager', () => { + // For that kind of user all APIs having a service-context should be returned + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "max" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/operatorMax.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=max&field=enabled&op=eq&value=enabled`).replyWithFile(200, './test/mockedReplies/apimanager/apiManagerUserMax.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-MAX`).replyWithFile(200, './test/mockedReplies/apimanager/organizationMax.json'); + return requestAsync({ + method: 'GET', + uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search`, + headers: { + 'cookie': 'VIDUSR=Restricted-Search-0002-MAX-1597468226-Z+qdRW4rGZnwzQ==', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, + auth: auth, + json: true + }).then(({ response, body }) => { + expect(response.statusCode).to.equal(200); + expect(body).to.be.an('Object'); + expect(body).to.have.property('data'); + expect(body.data).to.have.lengthOf(9); // Nine entries have any kind of serviceContext + nock.cleanAll(); + }); + }); + + it('[Restricted-Search-0003] Execute a search - NOT being an API-GW-Admin - Normal user in API-Manager', () => { + // For that kind of user all APIs having a service-context should be returned + nock('https://mocked-api-gateway:8090').get('/api/rbac/currentuser').reply(200, { "result": "rene" }); + nock('https://mocked-api-gateway:8090').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/mockedReplies/apigateway/operatorRene.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=rene&field=enabled&op=eq&value=enabled`).replyWithFile(200, './test/mockedReplies/apimanager/apiManagerUserRene.json'); + nock('https://mocked-api-gateway:8075').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-MAX`).replyWithFile(200, './test/mockedReplies/apimanager/organizationMax.json'); + return requestAsync({ + method: 'GET', + uri: `http://localhost:${server.apibuilder.port}/api/elk/v1/api/router/service/instance-1/ops/search`, + headers: { + 'cookie': '_ga=GA1.1.177509375.1593442001; iconSize=16x16; cookie_pressed_153=false; portal.logintypesso=false; portal.demo=off; portal.isgridSortIgnoreCase=on; VIDUSR=Restricted-Search-0003-RENE-1597762865-iUI5a8+v+zLkNA%3d%3d; APIMANAGERSTATIC=92122e5c-6bb3-4fd1-ad2f-08b65554d116', + 'csrf-token': '04F9F07E59F588CDE469FC367A12ED3A4B845FDA9A9AE2D9A77686823067CDDC' + }, + auth: auth, + json: true + }).then(({ response, body }) => { + expect(response.statusCode).to.equal(200); + expect(body).to.be.an('Object'); + expect(body).to.have.property('data'); + expect(body.data).to.have.lengthOf(2); + nock.cleanAll(); + }); + }); + }); +}); \ No newline at end of file diff --git a/logstash/config/traffic_details_index_template.json b/logstash/config/traffic_details_index_template.json index 6e54a555..42a1328d 100644 --- a/logstash/config/traffic_details_index_template.json +++ b/logstash/config/traffic_details_index_template.json @@ -122,6 +122,18 @@ "transactionElements.leg4.duration": { "type": "integer" }, "transactionElements.leg4.finalStatus": { "type": "keyword" }, + "transactionElements.leg5.protocolInfo.http.remoteName": { "type": "text", "norms": false }, + "transactionElements.leg5.protocolInfo.http.wafStatus": { "type": "integer" }, + "transactionElements.leg5.protocolInfo.http.remotePort": { "type": "integer" }, + "transactionElements.leg5.protocolInfo.http.status": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword" } } }, + "transactionElements.leg5.protocolInfo.http.authSubjectId": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword" } } }, + "transactionElements.leg5.protocolInfo.http.localPort": { "type": "integer" }, + "transactionElements.leg5.protocolInfo.http.localAddr": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword" } } }, + "transactionElements.leg5.protocolInfo.http.method": { "type": "text", "norms": false, "fields": { "keyword": {"type": "keyword" } } }, + "transactionElements.leg5.protocolInfo.http.uri": { "type": "text","norms": false, "fields": { "keyword": { "type": "keyword" } } }, + "transactionElements.leg5.duration": { "type": "integer" }, + "transactionElements.leg5.finalStatus": { "type": "keyword" }, + "transactionSummary.status": { "type": "keyword" }, @@ -168,6 +180,21 @@ } }, "norms": false + }, + "transactionSummary.serviceContext.appOrg": { + "type": "keyword" + }, + "transactionSummary.serviceContext.apiOrg": { + "type": "keyword" + }, + "transactionSummary.serviceContext.apiVersion": { + "type": "keyword" + }, + "transactionSummary.serviceContext.apiDeprecated": { + "type": "boolean" + }, + "transactionSummary.serviceContext.apiState": { + "type": "keyword" } } } diff --git a/logstash/pipeline/pipeline.conf b/logstash/pipeline/pipeline.conf index 90f74a15..841a6c8a 100644 --- a/logstash/pipeline/pipeline.conf +++ b/logstash/pipeline/pipeline.conf @@ -45,7 +45,38 @@ filter { } mutate { remove_field => "[transactionSummary][serviceContexts]" + rename => ["[transactionSummary][serviceContext][org]", "[transactionSummary][serviceContext][appOrg]" ] } + # Future plan is to perform side-calls only if not yet already cached + #mutate { + # add_field => { "apiCacheKey" => "%{[transactionSummary][serviceContext][service]}---%{[transactionSummary][path]}" } + #} + #memcached { + # namespace => "api_details" + # ttl => 300 + # get => { "apiCacheKey" => "[transactionSummary][serviceContext][serviceOrg]" } + # remove_field => [ "apiCacheKey" ] + #} + #if ![transactionSummary][serviceContext][serviceOrg] { + # Perform a side-call to load organization details for the API + if([transactionSummary][serviceContext]) { + http { + url => "${API_BUILDER_URL}/api/elk/v1/api/lookup/api" + query => { + "apiName" => "%{[transactionSummary][serviceContext][service]}" + "apiPath" => "%{[transactionSummary][path]}" + } + target_body => "apiDetails" + add_field => { + "[transactionSummary][serviceContext][apiOrg]" => "%{[apiDetails][organizationName]}" + "[transactionSummary][serviceContext][apiVersion]" => "%{[apiDetails][version]}" + "[transactionSummary][serviceContext][apiDeprecated]" => "%{[apiDetails][deprecated]}" + "[transactionSummary][serviceContext][apiState]" => "%{[apiDetails][state]}" + } + remove_field => [ "apiDetails", "headers" ] + } + } + #} } } else if([logtype] == "trace") { if [message] =~ /^#/ { @@ -82,6 +113,16 @@ output { hosts => "elasticsearch1:9200" index => "apigw-traffic-trace-%{+YYYY.MM.dd}" } + } else if "_httprequestfailure" in [tags] { + elasticsearch { + hosts => "elasticsearch1:9200" + index => "apigw-traffic-details-err-%{+YYYY}" + template => "${HOME}/config/traffic_details_index_template.json" + template_overwrite => true + document_id => "%{correlationId}" + action => "update" + doc_as_upsert => true + } } else { elasticsearch { hosts => "elasticsearch1:9200" diff --git a/logstash/test/test-openlog-events.json b/logstash/test/test-openlog-events.json index bbfa33f4..6900e133 100644 --- a/logstash/test/test-openlog-events.json +++ b/logstash/test/test-openlog-events.json @@ -77,6 +77,9 @@ "serviceName": "instance-3", "version": "7.7.20200530" }, + "tags": [ + "_httprequestfailure" + ], "transactionSummary": { "path": "/petstore/v2/user/Chris", "protocol": "https", @@ -86,7 +89,7 @@ "service": "Petstore", "monitor": true, "client": null, - "org": null, + "appOrg": null, "app": null, "method": "getUserByName", "status": "success",