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

Commit 1223dfd

Browse files
author
Chris Wiechmann
committed
On API-Builder start-up validate API-Manager configuration
1 parent 2c53f5e commit 1223dfd

File tree

10 files changed

+329
-129
lines changed

10 files changed

+329
-129
lines changed

elk-traffic-monitor-api/conf/axway-api-utils.default.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ module.exports = {
1313
},
1414
// This is true, when running as part of the CI-Pipeline (GitHub Actions)
1515
// If true, some test API-Requests are then mocked
16-
MOCK_LOOKUP_API: process.env.MOCK_LOOKUP_API
16+
MOCK_LOOKUP_API: process.env.MOCK_LOOKUP_API,
17+
// This optionally disables the validation of the configuration on API-Builder startup
18+
validateConfig: (process.env.VALIDATE_CONFIG) ? process.env.VALIDATE_CONFIG : true
1719
}
1820
}
1921
};

elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/config/axway-api-utils.default.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ module.exports = {
99
'apimanager': {
1010
url: process.env.API_MANAGER, // If not set, the API-Gateway hostname is used
1111
username: process.env.API_MANAGER_USERNAME, // User with Admin-Privileges required
12-
password: process.env.API_MANAGER_PASSWORD
13-
}
12+
password: process.env.API_MANAGER_PASSWORD
13+
},
14+
// This is true, when running as part of the CI-Pipeline (GitHub Actions)
15+
// If true, some test API-Requests are then mocked
16+
MOCK_LOOKUP_API: process.env.MOCK_LOOKUP_API,
17+
// This optionally disables the validation of the configuration on API-Builder startup
18+
validateConfig: (process.env.VALIDATE_CONFIG) ? process.env.VALIDATE_CONFIG : true
1419
}
1520
}
1621
};

elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/actions.js

Lines changed: 7 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const https = require('https');
2+
const { sendRequest, _getCookie } = require('./utils');
23

34
var pluginConfig = {};
45
var cache = {};
@@ -123,7 +124,7 @@ async function _getCurrentGWUser(VIDUSR) {
123124
};
124125
loginName = await sendRequest(pluginConfig.apigateway.url, options)
125126
.then(response => {
126-
return response.result;
127+
return response.body.result;
127128
})
128129
.catch(err => {
129130
throw new Error(`Error getting current user Request sent to: '${pluginConfig.apigateway.hostname}'. ${err}`);
@@ -142,7 +143,7 @@ async function _getCurrentGWPermissions(VIDUSR, csrfToken, loginName) {
142143
};
143144
result = await sendRequest(pluginConfig.apigateway.url, options)
144145
.then(response => {
145-
return response.result;
146+
return response.body.result;
146147
})
147148
.catch(err => {
148149
throw new Error(err);
@@ -163,7 +164,7 @@ async function _getManagerUser(user) {
163164
};
164165
managerUser = await sendRequest(pluginConfig.apimanager.url, options)
165166
.then(response => {
166-
return response;
167+
return response.body;
167168
})
168169
.catch(err => {
169170
throw new Error(err);
@@ -181,63 +182,14 @@ async function _getAPIProxy(apiName) {
181182
};
182183
apiProxy = await sendRequest(pluginConfig.apimanager.url, options)
183184
.then(response => {
184-
return response;
185+
return response.body;
185186
})
186187
.catch(err => {
187188
throw new Error(`Error getting APIs with API-Name: ${apiName}. Request sent to: '${pluginConfig.apimanager.url}'. ${err}`);
188189
});
189190
return apiProxy;
190191
}
191192

192-
async function sendRequest(url, options) {
193-
return new Promise((resolve, reject) => {
194-
try {
195-
options.path = encodeURI(options.path);
196-
var req = https.request(url, options, function (response) {
197-
var chunks = [];
198-
var statusCode = response.statusCode;
199-
response.on("data", function (chunk) {
200-
chunks.push(chunk);
201-
});
202-
203-
response.on("end", function () {
204-
var body = Buffer.concat(chunks);
205-
if (statusCode < 200 || statusCode > 299) {
206-
reject(`Unexpected response for HTTP-Request. Response-Code: ${statusCode}`);
207-
return;
208-
}
209-
const userResponse = body.toString();
210-
if (!userResponse) {
211-
resolve(userResponse);
212-
return;
213-
}
214-
resolve(JSON.parse(userResponse));
215-
return;
216-
});
217-
});
218-
req.on("error", function (error) {
219-
reject(error);
220-
return;
221-
});
222-
req.end();
223-
} catch (ex) {
224-
reject(ex);
225-
}
226-
});
227-
}
228-
229-
function _getCookie(cookies, cookieName) {
230-
const fields = cookies.split(";");
231-
for (var i = 0; i < fields.length; ++i) {
232-
var cookie = fields[i].trim();
233-
const foundCookie = cookie.substring(0, cookie.indexOf("="));
234-
if(cookieName == foundCookie) {
235-
return cookie.substring(cookie.indexOf("=")+1);
236-
}
237-
}
238-
return;
239-
}
240-
241193
async function _getOrganization(orgId) {
242194
if(cache.has(`ORG-${orgId}`)) {
243195
var org = cache.get(`ORG-${orgId}`);
@@ -253,10 +205,10 @@ async function _getOrganization(orgId) {
253205
};
254206
org = await sendRequest(pluginConfig.apimanager.url, options)
255207
.then(response => {
256-
if(!response) {
208+
if(!response.body) {
257209
throw new Error(`Organization with : '${orgId}' not found in API-Manager.`);
258210
}
259-
return response;
211+
return response.body;
260212
})
261213
.catch(err => {
262214
throw new Error(err);

elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/src/index.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ const path = require('path');
22
const { SDK } = require('@axway/api-builder-sdk');
33
const actions = require('./actions');
44
const NodeCache = require( "node-cache" );
5+
const { sendRequest, _getSession } = require('./utils');
6+
const https = require('https');
57

68
/**
79
* Resolves the API Builder plugin.
@@ -40,11 +42,64 @@ async function getPlugin(pluginConfig, options) {
4042
if(!pluginConfig.apimanager.password) {
4143
throw new Error(`Required parameter: apimanager.password is not set.`)
4244
}
45+
if(pluginConfig.validateConfig==true) {
46+
var isAdmin = await isAPIManagerUserAdmin(pluginConfig.apimanager, options.logger);
47+
if(!isAdmin) {
48+
throw new Error(`Configured API-Manager user: ${pluginConfig.apimanager.username} is either incorrect or has no Admin-Role.`);
49+
} else {
50+
options.logger.info("Connection to API-Manager successfully validated.");
51+
}
52+
}
4353
}
4454
sdk.load(path.resolve(__dirname, 'flow-nodes.yml'), actions, { pluginContext: { cache: cache }, pluginConfig});
4555
return sdk.getPlugin();
4656
}
4757

58+
async function isAPIManagerUserAdmin(apiManagerConfig, logger) {
59+
try {
60+
var data = `username=${apiManagerConfig.username}&password=${apiManagerConfig.password}`;
61+
var options = {
62+
path: `/api/portal/v1.3/login`,
63+
method: 'POST',
64+
headers: {
65+
'Content-Type': 'application/x-www-form-urlencoded',
66+
'Content-Length': data.length
67+
},
68+
agent: new https.Agent({ rejectUnauthorized: false })
69+
};
70+
result = await sendRequest(apiManagerConfig.url, options, data, 303)
71+
.then(response => {
72+
return response;
73+
})
74+
.catch(err => {
75+
throw new Error(`Cant login to API-Manager: ${err}`);
76+
});
77+
const session = _getSession(result.headers);
78+
var options = {
79+
path: `/api/portal/v1.3/currentuser`,
80+
headers: {
81+
'Cookie': `APIMANAGERSESSION=${session}`
82+
},
83+
agent: new https.Agent({ rejectUnauthorized: false })
84+
};
85+
const currentUser = await sendRequest(apiManagerConfig.url, options)
86+
.then(response => {
87+
return response;
88+
})
89+
.catch(err => {
90+
throw new Error(`Cant get current user: ${err}`);
91+
});
92+
if(currentUser.body.role!='admin') {
93+
logger.error(`User: ${currentUser.body.loginName} has no admin role.`);
94+
return false;
95+
}
96+
return true;
97+
} catch (ex) {
98+
logger.error(ex);
99+
throw ex;
100+
}
101+
}
102+
48103
/**
49104
* This adds a number of Keys into the cache that are triggered
50105
* by the Logstash-Pipeline tests.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
const https = require('https');
2+
3+
async function sendRequest(url, options, data, expectedRC) {
4+
return new Promise((resolve, reject) => {
5+
try {
6+
options.path = encodeURI(options.path);
7+
var req = https.request(url, options, function (response) {
8+
var chunks = [];
9+
var statusCode = response.statusCode;
10+
response.on("data", function (chunk) {
11+
chunks.push(chunk);
12+
});
13+
14+
response.on("end", function () {
15+
var body = Buffer.concat(chunks);
16+
if (statusCode < 200 || statusCode > 299 && statusCode!=expectedRC) {
17+
reject(`Unexpected response for HTTP-Request. Response-Code: ${statusCode}`);
18+
return;
19+
}
20+
const userResponse = body.toString();
21+
if (!userResponse) {
22+
resolve({body: userResponse, headers: response.headers });
23+
return;
24+
}
25+
resolve({body: JSON.parse(userResponse), headers: response.headers });
26+
return;
27+
});
28+
});
29+
req.on("error", function (error) {
30+
reject(error);
31+
return;
32+
});
33+
if(data) {
34+
req.write(data);
35+
}
36+
req.end();
37+
} catch (ex) {
38+
reject(ex);
39+
}
40+
});
41+
}
42+
43+
function _getCookie(cookies, cookieName) {
44+
const fields = cookies.split(";");
45+
for (var i = 0; i < fields.length; ++i) {
46+
var cookie = fields[i].trim();
47+
const foundCookie = cookie.substring(0, cookie.indexOf("="));
48+
if(cookieName == foundCookie) {
49+
return cookie.substring(cookie.indexOf("=")+1);
50+
}
51+
}
52+
return;
53+
}
54+
55+
function _getSession(headers) {
56+
const setCookieHeaders = headers['set-cookie'];
57+
for (var i = 0; i < setCookieHeaders.length; ++i) {
58+
var setCookie = setCookieHeaders[i].trim();
59+
if(setCookie.startsWith('APIMANAGERSESSION=')) {
60+
session = setCookie.substring(setCookie.indexOf("=")+1, setCookie.indexOf(";"));
61+
return session;
62+
}
63+
}
64+
throw new Error('No session found.');
65+
}
66+
67+
/**
68+
* Tests whether or not the API Builder application is in developer mode. The test
69+
* is to check to see if @axway/api-builder-admin exists.
70+
*
71+
* @returns {boolean} True if in developer mode.
72+
*/
73+
function isDeveloperMode() {
74+
try {
75+
// If we are in "development mode" we are going to have @axway/api-builder-admin
76+
// dependency installed. So we guarantee that only generate config files in
77+
// "development mode" and ensure immutable production environments.
78+
// eslint-disable-next-line import/no-unresolved
79+
require('@axway/api-builder-admin');
80+
return true;
81+
} catch (ex) {
82+
// when we run plugin test suite @axway/api-builder-admin is not there
83+
// so we are kind of simulating production mode
84+
return false;
85+
}
86+
}
87+
88+
89+
module.exports = {
90+
sendRequest,
91+
_getCookie,
92+
_getSession,
93+
isDeveloperMode
94+
}

elk-traffic-monitor-api/custom_flow_nodes/api-builder-plugin-axway-api-management/test/.env

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@ API_MANAGER_PASSWORD=changeme
55

66
ADMIN_NODE_MANAGER=https://mocked-api-gateway:8190
77
API_GATEWAY_USERNAME=apiadmin
8-
API_GATEWAY_PASSWORD=changeme
8+
API_GATEWAY_PASSWORD=changeme
9+
10+
# Dont validate API-Manager configuration when running tests, which are mocked anyway
11+
VALIDATE_CONFIG=false

0 commit comments

Comments
 (0)