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

Commit 9526fa3

Browse files
author
Chris Wiechmann
authored
Merge pull request #142 from Axway-API-Management-Plus/multi-org-support
This PR adds adds support for user having multiple organizations in API-Manager
2 parents 284dae2 + a7ea11d commit 9526fa3

File tree

8 files changed

+140
-20
lines changed

8 files changed

+140
-20
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+
### Added
9+
- Traffic-Monitor Authorization should support Multi-Organization [#141](https://github.com/Axway-API-Management-Plus/apigateway-openlogging-elk/issues/141)
10+
711
## [3.4.0] 2021-09-02
812
### Fixed
913
- Service name filtering is not working as expected [#129](https://github.com/Axway-API-Management-Plus/apigateway-openlogging-elk/issues/129)

UPDATE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ On the other hand, the API builder Docker image, as a central component of the s
5656
| 3.3.1 | [X](#api-builderlogstashmemcached) | - | - | - | - | - | [X](#parameters)|- | 7.12.1 | |
5757
| 3.3.2 | [X](#api-builderlogstashmemcached) | - | - | - | - | - | - |- | 7.12.1 | |
5858
| 3.4.0 | [X](#api-builderlogstashmemcached) | [X](#api-builderlogstashmemcached) | - | - | - | [X](#dashboards)| [X](#parameters)|[X](#elastic-config)| 7.14.0 | |
59+
| 3.5.0 | [X](#api-builderlogstashmemcached) | - | - | - | - | - | - |- | 7.14.0 |Unreleased |
5960

6061
### Update from Version 1.0.0
6162

apibuilder4elastic/custom_flow_nodes/api-builder-plugin-authorization/src/actions.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,37 @@ async function addApiManagerOrganizationFilter(params, options) {
6767
if (user.gatewayManager.isUnrestricted) {
6868
return elasticQuery;
6969
}
70-
var filters = elasticQuery.bool.must;
70+
// Initialize the filter array, if not given
71+
if(!elasticQuery.bool.filter) {
72+
elasticQuery.bool.filter = [];
73+
}
74+
var filters = elasticQuery.bool.filter;
7175
var filter;
7276
// If the user is an API-Manager Admin, he should see all traffic passed API-Manager (has a ServiceContext)
7377
if (user.apiManager.role == "admin") {
7478
// The serviceContext may be at different places depending on the queried index
75-
filter = {
79+
80+
filters.push( {
7681
bool: {
7782
should: [
83+
// Either transactionSummary.serviceContext or serviceContext should be found
7884
{ exists: { "field" : "transactionSummary.serviceContext" } },
7985
{ exists: { "field" : "serviceContext" } }
8086
]
8187
}
82-
};
88+
});
8389
} else {
84-
filter = { term: {} };
85-
filter.term[indexProperty] = user.apiManager.organizationName;
90+
filter = { terms: {} };
91+
filter.terms[indexProperty] = [user.apiManager.organizationName];
92+
// If the user has multiple organizations add them all to the terms filter
93+
// This might even include Non-Dev Orgs - It doesn't harm as they just never match to any of the documents
94+
if(user.apiManager.orgs2Name) {
95+
for (const [key, val] of Object.entries(user.apiManager.orgs2Name)) {
96+
filter.terms[indexProperty].push(val);
97+
}
98+
}
99+
filters.push(filter);
86100
}
87-
filters.push(filter);
88101
return elasticQuery;
89102
}
90103

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"gatewayManager": {
3+
"isUnrestricted": false
4+
},
5+
"loginName": "anna",
6+
"apiManager": {
7+
"id": "0dded6b7-98da-4af0-b4c7-799fbadb7e8d",
8+
"organizationId": "f5e79a5a-eadf-48ce-a8c2-c23f7b111f85",
9+
"name": "Anna Owen",
10+
"description": "Anna is the Application Owner",
11+
"loginName": "anna",
12+
"email": "anna@demo.axway.com",
13+
"role": "oadmin",
14+
"image": "/api/portal/v1.3/users/0dded6b7-98da-4af0-b4c7-799fbadb7e8d/image",
15+
"enabled": true,
16+
"createdOn": 1557135802934,
17+
"state": "approved",
18+
"type": "external",
19+
"dn": "cn=anna,o=API Development,ou=organizations,ou=APIPortal",
20+
"organizationName": "API Development",
21+
"orgs2Name": {
22+
"3fec2611-17a1-46fa-be9f-dd00862ace7c": "FastCars",
23+
"ea62bff5-2859-46d7-a29e-1731b2717795": "Partners"
24+
},
25+
"orgs2Role": {
26+
"3fec2611-17a1-46fa-be9f-dd00862ace7c": "oadmin",
27+
"ea62bff5-2859-46d7-a29e-1731b2717795": "user"
28+
}
29+
}
30+
}

apibuilder4elastic/custom_flow_nodes/api-builder-plugin-authorization/test/testAPIManagerOrgAuthZ.js

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,7 @@ describe('flow-node Authorization', () => {
110110
user: user, elasticQuery: elasticQuery
111111
});
112112

113-
expectedQuery.bool.must.push({
114-
term: { "serviceContext.apiOrg" : "API Development" }
115-
});
113+
expectedQuery.bool.filter = [ { terms: { "serviceContext.apiOrg": ["API Development"]} } ];
116114

117115
expect(value).to.be.instanceOf(Object);
118116
expect(value).to.deep.equal(expectedQuery);
@@ -127,15 +125,11 @@ describe('flow-node Authorization', () => {
127125
const { value, output } = await flowNode.addApiManagerOrganizationFilter({
128126
user: adminUser, elasticQuery: elasticQuery
129127
});
130-
131-
expectedQuery.bool.must.push({
132-
bool: {
133-
should: [
134-
{ exists: { "field" : "transactionSummary.serviceContext" } },
135-
{ exists: { "field" : "serviceContext" } }
136-
]
137-
}
138-
});
128+
129+
expectedQuery.bool.filter = [{bool: { should: [
130+
{ "exists": { "field": "transactionSummary.serviceContext" }},
131+
{ "exists": { "field": "serviceContext" }}
132+
] } }];
139133

140134
expect(value).to.be.instanceOf(Object);
141135
expect(value).to.deep.equal(expectedQuery);
@@ -151,10 +145,23 @@ describe('flow-node Authorization', () => {
151145
user: user, elasticQuery: elasticQuery, indexProperty: "transactionSummary.serviceContext.apiOrg"
152146
});
153147

154-
expectedQuery.bool.must.push({
155-
term: { "transactionSummary.serviceContext.apiOrg" : "API Development" }
148+
expectedQuery.bool.filter = [{ "terms" : {"transactionSummary.serviceContext.apiOrg" : ["API Development"] } }];
149+
150+
expect(value).to.be.instanceOf(Object);
151+
expect(value).to.deep.equal(expectedQuery);
152+
expect(output).to.equal('next');
153+
});
154+
155+
it('should add the filter for Multiple Organizations for a Non-Admin user to the query', async () => {
156+
var user = JSON.parse(fs.readFileSync('./test/mock/noAdminUserObjectMultiOrg.json'), null);
157+
var elasticQuery = JSON.parse(fs.readFileSync('./test/mock/givenElasticQuery.json'), null);
158+
let expectedQuery = JSON.parse(JSON.stringify(elasticQuery));
159+
160+
const { value, output } = await flowNode.addApiManagerOrganizationFilter({
161+
user: user, elasticQuery: elasticQuery
156162
});
157163

164+
expectedQuery.bool.filter = [ { "terms": { "serviceContext.apiOrg": [ "API Development", "FastCars", "Partners" ] } } ];
158165
expect(value).to.be.instanceOf(Object);
159166
expect(value).to.deep.equal(expectedQuery);
160167
expect(output).to.equal('next');

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ async function lookupCurrentUser(params, options) {
108108
throw new Error(`User: '${user.loginName}' not found in API-Manager.`);
109109
}
110110
user.apiManager = users[0];
111+
// Get the name of the primary organization
111112
var org = await _getOrganization(user.apiManager, null, null, options);
112113
user.apiManager.organizationName = org.name;
113114
logger.debug(`User: '${user.loginName}' (Role: ${user.apiManager.role}) found in API-Manager. Organization: '${user.apiManager.organizationName}'`);

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,47 @@ describe('Tests User-Lookup with complete configuration parameters', () => {
200200
expect(output).to.equal('next');
201201
});
202202

203+
it('should result into a Multi-Org user (NOT HAVING permission: adminusers_modify), which requires user lookup to the API-Manager', async () => {
204+
nock('https://mocked-api-gateway:8190').get('/api/rbac/currentuser').reply(200, { "result": "chris" });
205+
nock('https://mocked-api-gateway:8190').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/testReplies/gateway/operatorRoleOnlyPermissions.json');
206+
nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/users?field=loginName&op=eq&value=chris${enabledField}`).replyWithFile(200, './test/testReplies/apimanager/apiManagerUserChrisMultiOrg.json');
207+
nock('https://mocked-api-gateway:8175').get(`/api/portal/v1.3/organizations/2bfaa1c2-49ab-4059-832d-f833ca1c0a74`).replyWithFile(200, './test/testReplies/apimanager/organizationAPIDevelopment.json');
208+
209+
const { value, output } = await flowNode.lookupCurrentUser({
210+
requestHeaders: {"host":"api-gateway:8090","max-forwards":"20", "cookie":"VIDUSR=1597381095-XTawGDtJhBA7Zw==;", "csrf-token": "CF2796B3BD18C1B0B5AB1C8E95B75662E92FBC04BD799DEB97838FC5B9C39348"}
211+
});
212+
213+
expect(value).to.deep.equal({
214+
"loginName": "chris",
215+
"gatewayManager": {
216+
"isUnrestricted": false
217+
},
218+
"apiManager": {
219+
"id": "d66a42d6-b9c7-4efd-b33a-de8b88545861",
220+
"organizationId": "2bfaa1c2-49ab-4059-832d-f833ca1c0a74",
221+
"organizationName": "API Development",
222+
"name": "Chris",
223+
"loginName": "chris",
224+
"email": "chris@axway.com",
225+
"role": "oadmin",
226+
"enabled": true,
227+
"createdOn": 1597338071490,
228+
"state": "approved",
229+
"type": "internal",
230+
"dn": "cn=chris,o=API Development,ou=organizations,ou=APIPortal",
231+
"orgs2Name": {
232+
"3fec2611-17a1-46fa-be9f-dd00862ace7c": "API Development",
233+
"ea62bff5-2859-46d7-a29e-1731b2717795": "Partners"
234+
},
235+
"orgs2Role": {
236+
"3fec2611-17a1-46fa-be9f-dd00862ace7c": "oadmin",
237+
"ea62bff5-2859-46d7-a29e-1731b2717795": "user"
238+
}
239+
}
240+
});
241+
expect(output).to.equal('next');
242+
});
243+
203244
it('should should cache the result', async () => {
204245
nock('https://mocked-api-gateway:8190').get('/api/rbac/currentuser').reply(200, { "result": "chris" });
205246
nock('https://mocked-api-gateway:8190').get('/api/rbac/permissions/currentuser').replyWithFile(200, './test/testReplies/gateway/operatorRoleOnlyPermissions.json');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[
2+
{
3+
"id": "d66a42d6-b9c7-4efd-b33a-de8b88545861",
4+
"organizationId": "2bfaa1c2-49ab-4059-832d-f833ca1c0a74",
5+
"name": "Chris",
6+
"loginName": "chris",
7+
"email": "chris@axway.com",
8+
"role": "oadmin",
9+
"enabled": true,
10+
"createdOn": 1597338071490,
11+
"state": "approved",
12+
"type": "internal",
13+
"dn": "cn=chris,o=API Development,ou=organizations,ou=APIPortal",
14+
"orgs2Role": {
15+
"ea62bff5-2859-46d7-a29e-1731b2717795": "user",
16+
"3fec2611-17a1-46fa-be9f-dd00862ace7c": "oadmin"
17+
},
18+
"orgs2Name": {
19+
"ea62bff5-2859-46d7-a29e-1731b2717795": "Partners",
20+
"3fec2611-17a1-46fa-be9f-dd00862ace7c": "API Development"
21+
}
22+
}
23+
]

0 commit comments

Comments
 (0)