Skip to content
This repository was archived by the owner on Dec 14, 2022. It is now read-only.

Commit 770ff0e

Browse files
author
Chris Wiechmann
authored
Merge pull request #79 from Axway-API-Management-Plus/group-not-specified
API_MANAGER parameter parsing refactored and unit tests added
2 parents 37ba511 + 2af8656 commit 770ff0e

File tree

11 files changed

+440
-116
lines changed

11 files changed

+440
-116
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/)
55
and this project adheres to [Semantic Versioning](http://semver.org/).
66

7+
## Unreleased
8+
### Fixed
9+
- Parse error when using multiple API_MANAGER configuration [#76](https://github.com/Axway-API-Management-Plus/apigateway-openlogging-elk/issues/76)
10+
711
## [2.1.1] 2021-02-05
812
### Fixed
913
- Race-Condition, causing wrong organization assigned to API under heavy load [#75](https://github.com/Axway-API-Management-Plus/apigateway-openlogging-elk/issues/75)

UPDATE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ On the other hand, the API builder Docker image, as a central component of the s
4242
| 2.0.2 | [X](#api-builderlogstashmemcached) | - | - | - | - | - | - | - | 7.10.0 | |
4343
| 2.1.0 | [X](#api-builderlogstashmemcached) | [X](#api-builderlogstashmemcached) | - | - | - | - | [X](#parameters)|[X](#elastic-config)| 7.10.0 | |
4444
| 2.1.1 | [X](#api-builderlogstashmemcached) | - | - | - | - | - | - |- | 7.10.0 | |
45+
| 2.1.2 | [X](#api-builderlogstashmemcached) | - | - | - | - | - | - |- | 7.10.0 | |
4546

4647
### Update from Version 1.0.0
4748

apibuilder4elastic/custom_flow_nodes/api-builder-plugin-axway-api-management/package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apibuilder4elastic/custom_flow_nodes/api-builder-plugin-axway-api-management/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"decache": "^4.6.0",
3030
"dotenv": "^8.2.0",
3131
"mocha": "^7.1.1",
32-
"nock": "^13.0.4"
32+
"nock": "^13.0.4",
33+
"simple-mock": "^0.8.0"
3334
},
3435
"scripts": {
3536
"test": "mocha ./test --recursive -R spec",

apibuilder4elastic/custom_flow_nodes/api-builder-plugin-axway-api-management/src/actions.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,6 @@ async function _getGroupRegionFilename(basefilename, groupId, region) {
364364
}
365365

366366
async function _getCurrentGWUser(requestHeaders) {
367-
debugger;
368367
var options = {
369368
path: '/api/rbac/currentuser',
370369
headers: requestHeaders,

apibuilder4elastic/custom_flow_nodes/api-builder-plugin-axway-api-management/src/index.js

Lines changed: 5 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const { SDK } = require('@axway/api-builder-sdk');
33
const { lookupCurrentUser, lookupAPIDetails, getCustomPropertiesConfig, isIgnoreAPI, lookupApplication } = require('./actions');
44
const { mergeCustomProperties } = require('./customProperties');
55
const NodeCache = require( "node-cache" );
6-
const { sendRequest, _getSession, getManagerConfig } = require('./utils');
6+
const { checkAPIManagers, parseAPIManagerConfig } = require('./utils');
77
const https = require('https');
88

99
/**
@@ -32,44 +32,11 @@ async function getPlugin(pluginConfig, options) {
3232
if(!pluginConfig.apigateway.url) {
3333
throw new Error(`Required parameter: apigateway.url is not set.`);
3434
}
35-
if(!pluginConfig.apimanager.url) {
36-
// If no API-Manager URL is given, use the Admin-Node-Manager URL
37-
const managerURL = new URL(pluginConfig.apigateway.url);
38-
managerURL.port = 8075;
39-
pluginConfig.apimanager.url = managerURL.toString();
40-
} else {
41-
// Check, if multiple API-Manager URLs based on the groupId and regions are given (Format: groupId|managerUrl or groupId|region|managerUrl)
42-
if(pluginConfig.apimanager.url.indexOf('|')!=-1) {
43-
pluginConfig.apimanager.perGroupAndRegion = true;
44-
// Looks like manager URLs are given based on groupIds and regions
45-
pluginConfig.apimanager.url.split(',').forEach(groupRegionAndURL => {
46-
groupRegionAndURL = groupRegionAndURL.trim().toLowerCase().split('|');
47-
if(groupRegionAndURL.length == 1) {
48-
// The default API-Manager
49-
pluginConfig.apimanager.url = groupRegionAndURL[0]
50-
} else if(groupRegionAndURL.length == 2) {
51-
// Just the Group-ID is given
52-
pluginConfig.apimanager[groupRegionAndURL[0]] = { url: groupRegionAndURL[1] };
53-
} else if(groupRegionAndURL.length == 3) {
54-
// Group-ID and region is given (Just create a map with a special key)
55-
pluginConfig.apimanager[`${groupRegionAndURL[0]}###${groupRegionAndURL[1]}`] = { url: groupRegionAndURL[2] };
56-
} else {
57-
return Promise.reject(`Unexpected API-Manager format: ${groupRegionAndURL}`);
58-
59-
}
60-
});
61-
}
62-
}
63-
if(!pluginConfig.apimanager.username) {
64-
throw new Error(`Required parameter: apimanager.username is not set.`)
65-
}
66-
if(!pluginConfig.apimanager.password) {
67-
throw new Error(`Required parameter: apimanager.password is not set.`)
68-
}
35+
await parseAPIManagerConfig(pluginConfig, options);
6936
if(pluginConfig.validateConfig==true) {
70-
var isAdmin = await isAPIManagerUserAdmin(pluginConfig.apimanager, options.logger);
71-
if(!isAdmin) {
72-
throw new Error(`Configured API-Manager user: ${pluginConfig.apimanager.username} is either incorrect or has no Admin-Role.`);
37+
var result = await checkAPIManagers(pluginConfig.apimanager, options);
38+
if(!result.isValid) {
39+
throw new Error(`Error checking configured API-Manager(s). ${JSON.stringify(result)}`);
7340
} else {
7441
options.logger.info("Connection to API-Manager successfully validated.");
7542
}
@@ -82,65 +49,6 @@ async function getPlugin(pluginConfig, options) {
8249
return sdk.getPlugin();
8350
}
8451

85-
async function isAPIManagerUserAdmin(apiManagerConfig, logger) {
86-
let groupIds = [];
87-
if(apiManagerConfig.url.indexOf('#') != -1) {
88-
apiManagerConfig.url.split(',').forEach(groupAndURL => {
89-
groupAndURL = groupAndURL.trim().split();
90-
groupIds.push(getManagerConfig(apiManagerConfig, groupAndURL[0]));
91-
});
92-
} else {
93-
// The groupId doesn't matter if we don't have multiple configured
94-
groupIds[0] = "NOT_SPECIFIED";
95-
}
96-
for (var i = 0; i < groupIds.length; ++i) {
97-
var groupId = groupIds[i].trim();
98-
let config = getManagerConfig(apiManagerConfig, groupId);
99-
try {
100-
var data = `username=${config.username}&password=${config.password}`;
101-
var options = {
102-
path: `/api/portal/v1.3/login`,
103-
method: 'POST',
104-
headers: {
105-
'Content-Type': 'application/x-www-form-urlencoded',
106-
'Content-Length': data.length
107-
},
108-
agent: new https.Agent({ rejectUnauthorized: false })
109-
};
110-
const result = await sendRequest(config.url, options, data, 303)
111-
.then(response => {
112-
return response;
113-
})
114-
.catch(err => {
115-
throw new Error(`Cannot login to API-Manager: '${config.url}'. Got error: ${err}`);
116-
});
117-
const session = _getSession(result.headers);
118-
var options = {
119-
path: `/api/portal/v1.3/currentuser`,
120-
headers: {
121-
'Cookie': `APIMANAGERSESSION=${session}`
122-
},
123-
agent: new https.Agent({ rejectUnauthorized: false })
124-
};
125-
const currentUser = await sendRequest(apiManagerConfig.url, options)
126-
.then(response => {
127-
return response;
128-
})
129-
.catch(err => {
130-
throw new Error(`Cant get current user: ${err}`);
131-
});
132-
if(currentUser.body.role!='admin') {
133-
logger.error(`User: ${currentUser.body.loginName} has no admin role.`);
134-
return false;
135-
}
136-
return true;
137-
} catch (ex) {
138-
logger.error(ex);
139-
throw ex;
140-
}
141-
}
142-
}
143-
14452
/**
14553
* This adds a number of Keys into the cache that are triggered
14654
* by the Logstash-Pipeline tests.

apibuilder4elastic/custom_flow_nodes/api-builder-plugin-axway-api-management/src/utils.js

Lines changed: 118 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,32 +85,140 @@ function isDeveloperMode() {
8585
}
8686
}
8787

88+
async function parseAPIManagerConfig(pluginConfig, options) {
89+
if(!pluginConfig.apimanager.username) {
90+
throw new Error(`Required parameter: apimanager.username is not set.`)
91+
}
92+
if(!pluginConfig.apimanager.password) {
93+
throw new Error(`Required parameter: apimanager.password is not set.`)
94+
}
95+
if(!pluginConfig.apimanager.url) {
96+
// If no API-Manager URL is given, use the Admin-Node-Manager URL
97+
const managerURL = new URL(pluginConfig.apigateway.url);
98+
managerURL.port = 8075;
99+
options.logger.info(`Parameter API_MANAGER not set. Expect API-Manager on URL: ${managerURL.toString()}`);
100+
pluginConfig.apimanager.default = {
101+
url: managerURL.toString(),
102+
username: pluginConfig.apimanager.username,
103+
password: pluginConfig.apimanager.password
104+
}
105+
} else {
106+
// Check, if multiple API-Manager URLs based on the groupId and regions are given (Format: groupId|managerUrl or groupId|region|managerUrl)
107+
if(pluginConfig.apimanager.url.indexOf('|')!=-1) {
108+
pluginConfig.apimanager.perGroupAndRegion = true;
109+
options.logger.info(`Parse group/region based API_MANAGER: ${pluginConfig.apimanager.url}.`);
110+
// Looks like manager URLs are given based on groupIds and regions
111+
pluginConfig.apimanager.url.split(',').forEach(groupRegionAndURL => {
112+
groupRegionAndURL = groupRegionAndURL.trim().toLowerCase().split('|');
113+
if(groupRegionAndURL.length == 1) {
114+
// The default API-Manager
115+
options.logger.debug(`Found default API-Manager URL: ${groupRegionAndURL[0]}`);
116+
pluginConfig.apimanager.default = { url: groupRegionAndURL[0], username: pluginConfig.apimanager.username, password: pluginConfig.apimanager.password }
117+
} else if(groupRegionAndURL.length == 2) {
118+
// Only the Group-ID is given
119+
options.logger.debug(`Found API-Manager URL: ${groupRegionAndURL[1]} for group: ${groupRegionAndURL[0]}`);
120+
pluginConfig.apimanager[groupRegionAndURL[0]] = { url: groupRegionAndURL[1], username: pluginConfig.apimanager.username, password: pluginConfig.apimanager.password }
121+
} else if(groupRegionAndURL.length == 3) {
122+
// Group-ID and region is given (Just create a map with a special key)
123+
options.logger.debug(`Found API-Manager URL: ${groupRegionAndURL[2]} for group: ${groupRegionAndURL[1]} and region: ${groupRegionAndURL[1]}`);
124+
pluginConfig.apimanager[`${groupRegionAndURL[0]}###${groupRegionAndURL[1]}`] = { url: groupRegionAndURL[2], username: pluginConfig.apimanager.username, password: pluginConfig.apimanager.password}
125+
} else {
126+
return Promise.reject(`Unexpected API-Manager format: ${groupRegionAndURL}`);
127+
}
128+
});
129+
} else { // If not, create a default API-Manager
130+
options.logger.info(`Using only default API_MANAGER: ${pluginConfig.apimanager.url}.`);
131+
pluginConfig.apimanager.default = {
132+
url: pluginConfig.apimanager.url,
133+
username: pluginConfig.apimanager.username,
134+
password: pluginConfig.apimanager.password
135+
}
136+
}
137+
}
138+
}
139+
88140
function getManagerConfig(apiManagerConfig, groupId, region) {
89141
if(groupId == undefined && region == undefined) {
90-
return apiManagerConfig;
142+
if(apiManagerConfig.default == undefined) {
143+
throw new Error(`Cannot return API-Manager config without groupId and region as no default API-Manager is configured.`);
144+
} else {
145+
return apiManagerConfig.default;
146+
}
91147
}
92148
var key = groupId;
93149
if(region != undefined) {
94150
key = `${groupId}###${region}`.toLowerCase();
95151
}
152+
// Check if the requested combination based on groupId and region exists and return it directly
96153
if (apiManagerConfig[key]) {
97-
if (!apiManagerConfig[key].password) {
98-
apiManagerConfig[key].password = apiManagerConfig.password;
99-
apiManagerConfig[key].username = apiManagerConfig.username;
100-
}
101154
return apiManagerConfig[key];
102155
} else {
103-
if (apiManagerConfig.perGroupAndRegion) {
104-
throw new Error(`You have configured API-Manager URLs based on groupIds (e.g. group-a|https://manager-host.com:8075), but the groupId: ${groupId} is NOT configured. Please check the configuration parameter: API_MANAGER`);
156+
//
157+
if (apiManagerConfig.perGroupAndRegion && !apiManagerConfig.default) {
158+
throw new Error(`You have configured API-Manager URLs based on groupIds (e.g. group-a|https://manager-host.com:8075), but the groupId: ${groupId} is NOT configured and no default is configured. Please check the configuration parameter: API_MANAGER`);
159+
}
160+
return apiManagerConfig.default;
161+
}
162+
}
163+
164+
async function checkAPIManagers(apiManagerConfig, options) {
165+
var finalResult = { isValid: true };
166+
for (const [key, config] of Object.entries(apiManagerConfig)) {
167+
if(typeof config != 'object') continue;
168+
finalResult[key] = config;
169+
try {
170+
var data = `username=${config.username}&password=${config.password}`;
171+
var reqOptions = {
172+
path: `/api/portal/v1.3/login`,
173+
method: 'POST',
174+
headers: {
175+
'Content-Type': 'application/x-www-form-urlencoded',
176+
'Content-Length': data.length
177+
},
178+
agent: new https.Agent({ rejectUnauthorized: false })
179+
};
180+
const result = await sendRequest(config.url, reqOptions, data, 303)
181+
.then(response => {
182+
return response;
183+
})
184+
.catch(err => {
185+
throw new Error(`Cannot login to API-Manager: '${config.url}'. Got error: ${err}`);
186+
});
187+
const session = _getSession(result.headers);
188+
var reqOptions = {
189+
path: `/api/portal/v1.3/currentuser`,
190+
headers: {
191+
'Cookie': `APIMANAGERSESSION=${session}`
192+
},
193+
agent: new https.Agent({ rejectUnauthorized: false })
194+
};
195+
const currentUser = await sendRequest(config.url, reqOptions)
196+
.then(response => {
197+
return response;
198+
})
199+
.catch(err => {
200+
throw new Error(`Cant get current user: ${err}`);
201+
});
202+
if(currentUser.body.role!='admin') {
203+
options.logger.error(`User: ${currentUser.body.loginName} has no admin role on API-Manager: ${config.url}.`);
204+
finalResult.isValid = false;
205+
finalResult[key].isValid = false;
206+
} else {
207+
finalResult[key].isValid = true;
208+
}
209+
} catch (ex) {
210+
options.logger.error(ex);
211+
throw ex;
105212
}
106-
return apiManagerConfig;
107213
}
214+
return finalResult;
108215
}
109216

110217
module.exports = {
111218
sendRequest,
112219
_getCookie,
113-
_getSession,
114220
isDeveloperMode,
115-
getManagerConfig
221+
getManagerConfig,
222+
checkAPIManagers,
223+
parseAPIManagerConfig
116224
}

apibuilder4elastic/custom_flow_nodes/api-builder-plugin-axway-api-management/test/test-grp-based-apilookup.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,19 @@ describe('Test group based API lookup', () => {
2828

2929
describe('#lookupAPIDetails', () => {
3030
// This only fails, if really multiple API-Manager are configured (for that the parameter-value of API_MANAGER is checked if it contains a #)
31-
it('should return an error for a given groupId: group-unknown, which is not configured', async () => {
32-
31+
it('should use the default API-Manager for the given unknown group', async () => {
32+
// default
33+
nock('https://mocked-api-manager-0:8075').get('/api/portal/v1.3/proxies?field=name&op=eq&value=Petstore HTTPS').replyWithFile(200, './test/testReplies/apimanager/manager-1/apiProxyManager1.json');
34+
nock('https://mocked-api-manager-0:8075').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-team-a`).replyWithFile(200, './test/testReplies/apimanager/manager-1/orgTeamA.json');
3335
const { value, output } = await flowNode.lookupAPIDetails({
3436
apiName: 'Petstore HTTPS', apiPath: '/v1/petstore', groupId: 'group-unknown'
3537
});
3638

37-
expect(value).to.be.instanceOf(Error)
38-
.and.to.have.property('message', 'You have configured API-Manager URLs based on groupIds (e.g. group-a|https://manager-host.com:8075), but the groupId: group-unknown is NOT configured. Please check the configuration parameter: API_MANAGER');
39-
expect(output).to.equal('error');
39+
expect(value.organizationName).to.equal(`Team A`);
40+
expect(value.name).to.equal(`Petstore HTTPS`);
41+
expect(value.path).to.equal(`/v1/petstore`);
42+
expect(value.version).to.equal(`1.0.5 Manager 1`);
43+
expect(output).to.equal('next');
4044
});
4145

4246
it('should return the API-Details from the correct API-Manager based on the given groupId', async () => {

apibuilder4elastic/custom_flow_nodes/api-builder-plugin-axway-api-management/test/test-setup.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ describe('Configuration parameter tests', () => {
9292
expect(output).to.equal('error');
9393
} catch(e) {
9494
expect(e).to.be.an('Error')
95-
.and.to.have.property('message', 'Configured API-Manager user: user is either incorrect or has no Admin-Role.');
95+
.and.to.have.property('message', 'Error checking configured API-Manager(s). {"isValid":false,"default":{"url":"https://mocked-api-gateway:8175","username":"user","password":"invalid","isValid":false}}');
9696
}
9797
nock.cleanAll();
9898
});

0 commit comments

Comments
 (0)