Skip to content
132 changes: 120 additions & 12 deletions ui/src/__tests__/server/handlers/api.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const config = {
userDomain: 'test-user-domain',
serviceHeaderLinks: [],
templates: ['openhouse'],
callCloudSSO: true,
};
const SEVEN_SECONDS_TIMEOUT = 1000 * 7;
const secrets = {};
Expand All @@ -56,6 +57,22 @@ describe('Fetchr Server API Test', () => {
sinon.stub(CLIENTS, 'load').returns(Promise.resolve());
sinon.stub(CLIENTS, 'middleware').returns((req, res, next) => {
req.clients = {
cloud_sso: {
getResourceAccessList: (params, callback) =>
params.action === 'forcefailcloudsso' ||
params.action === 'forcefailboth'
? callback({ status: 503 }, null)
: callback(undefined, {
resources: {
principal: 'user.dummy1',
assertions: [
{
dummyProperty: 'dummyValue',
},
],
},
}),
},
zms: {
putAssertion: (params, callback) =>
params.forcefail
Expand Down Expand Up @@ -312,14 +329,20 @@ describe('Fetchr Server API Test', () => {
],
}),
getResourceAccessList: (params, callback) =>
params.forcefail
? callback({ status: 404 }, null)
params.action === 'forcefailboth'
? callback(
{
status: 503,
message: { message: 'zms fail' },
},
null
)
: callback(undefined, {
resources: {
principal: 'user.dummy1',
principal: 'user.dummy2',
assertions: [
{
dummyProperty: 'dummyValue',
dummyProperty: 'dummyValue2',
},
],
},
Expand Down Expand Up @@ -362,6 +385,8 @@ describe('Fetchr Server API Test', () => {
};
next();
});
});
beforeEach(async () => {
api.load(config, secrets).then(() => {
expressApp.use(bodyParser.urlencoded({ extended: false }));
expressApp.use(bodyParser.json());
Expand Down Expand Up @@ -1161,6 +1186,52 @@ describe('Fetchr Server API Test', () => {
]);
});
});
it('getResourceAccessList test cloudsso success', async () => {
await request(expressApp)
.get('/api/v1/resource-access')
.then((res) => {
expect(res.body).toEqual({
resources: {
principal: 'user.dummy1',
assertions: [
{
dummyProperty: 'dummyValue',
},
],
},
});
});
});

it('getResourceAccessList test callCloudSSO is false, zms call success', async () => {
api.load({ ...config, callCloudSSO: false }, secrets).then(() => {
expressApp.use(bodyParser.urlencoded({ extended: false }));
expressApp.use(bodyParser.json());
expressApp.use((req, res, next) => {
req.session = {
shortId: 'testuser',
};
req.csrfToken = () => '1234';
next();
});
api.route(expressApp);
});

await request(expressApp)
.get('/api/v1/resource-access')
.then((res) => {
expect(res.body).toEqual({
resources: {
principal: 'user.dummy2',
assertions: [
{
dummyProperty: 'dummyValue2',
},
],
},
});
});
});
});
describe('failure tests', () => {
it('putAssertion test failure', async () => {
Expand Down Expand Up @@ -1317,22 +1388,59 @@ describe('Fetchr Server API Test', () => {
expect(res.status).toEqual(404);
});
});
it('getResourceAccessList test success', async () => {

it('getResourceAccessList test cloudsso fail zms success', async () => {
await request(expressApp)
.get('/api/v1/resource-access')
.post('/api/v1')
.send({
requests: {
g0: {
resource: 'resource-access',
operation: 'read',
params: {
action: 'forcefailcloudsso',
},
},
},
})
.then((res) => {
expect(res.body).toEqual({
resources: {
principal: 'user.dummy1',
assertions: [
{
dummyProperty: 'dummyValue',
g0: {
data: {
resources: {
principal: 'user.dummy2',
assertions: [
{
dummyProperty: 'dummyValue2',
},
],
},
],
},
meta: {},
},
});
});
});
it('getResourceAccessList test both cloudsso and zms fail', async () => {
await request(expressApp)
.post('/api/v1/resource-access')
.send({
requests: {
g0: {
resource: 'resource-access',
operation: 'read',
params: {
action: 'forcefailboth',
},
},
},
})
.then((res) => {
expect(res.body).toEqual({
message: 'zms fail',
});
});
});
it('getRolesForReview test success', async () => {
await request(expressApp)
.get('/api/v1/roles-review')
Expand Down
2 changes: 2 additions & 0 deletions ui/src/config/default-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ const config = {
numberOfRetry: 2,
serverCipherSuites:
'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256',
callCloudSSO: true,
},
unittest: {
testdata: { ...testdata },
Expand Down Expand Up @@ -227,6 +228,7 @@ const config = {
numberOfRetry: 2,
serverCipherSuites:
'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256',
callCloudSSO: true,
},
};

Expand Down
1 change: 1 addition & 0 deletions ui/src/server/clients.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ module.exports.middleware = function middleware() {
msd: CLIENTS.msd(req, setCookieinClients(req)),
zts: CLIENTS.zts(req, setCookieinClients(req)),
ums: CLIENTS.ums(req, setCookieinClients(req)),
cloud_sso: CLIENTS.zms(req, setOktaCookieinClients(req)),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might be a better idea to create a separate client for cloud_sso but point it to zms rdl. Also is this the first cloud_sso is being referenced in here? If yes, lets add a small comment on the rationale behind CLIENTS.cloud_sso

};
next();
};
Expand Down
81 changes: 58 additions & 23 deletions ui/src/server/handlers/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -3226,34 +3226,68 @@ Fetchr.registerService({
Fetchr.registerService({
name: 'resource-access',
read(req, resource, params, config, callback) {
req.clients.zms.getResourceAccessList(
{
action: params.action,
principal: `${appConfig.userDomain}.${req.session.shortId}`,
},
(err, list) => {
if (err) {
if (err.status === 404) {
callback(null, []);
let cloudSSOCallFailed = false;
if (appConfig.callCloudSSO) {
req.clients.cloud_sso.getResourceAccessList(
{
action: params.action,
principal: `${appConfig.userDomain}.${req.session.shortId}`,
},
(err, list) => {
if (err) {
if (err.status === 404) {
callback(null, []);
} else {
debug(
`principal: ${req.session.shortId} rid: ${
req.headers.rid
} Error from Cloud SSO while calling getResourceAccessList API: ${JSON.stringify(
errorHandler.fetcherError(err)
)}`
);
// Fallback to ZMS if Cloud SSO call fails
cloudSSOCallFailed = true;
}
} else {
debug(
`principal: ${req.session.shortId} rid: ${
req.headers.rid
} Error from ZMS while calling getResourceAccessList API: ${JSON.stringify(
errorHandler.fetcherError(err)
)}`
);
callback(errorHandler.fetcherError(err));
if (!list || !list.resources) {
callback(null, []);
} else {
callback(null, list);
}
}
} else {
if (!list || !list.resources) {
callback(null, []);
}
);
}
if (!appConfig.callCloudSSO || cloudSSOCallFailed) {
req.clients.zms.getResourceAccessList(
{
action: params.action,
principal: `${appConfig.userDomain}.${req.session.shortId}`,
},
(err, list) => {
if (err) {
if (err.status === 404) {
callback(null, []);
} else {
debug(
`principal: ${req.session.shortId} rid: ${
req.headers.rid
} Error from ZMS while calling getResourceAccessList API: ${JSON.stringify(
errorHandler.fetcherError(err)
)}`
);
callback(errorHandler.fetcherError(err));
}
} else {
callback(null, list);
if (!list || !list.resources) {
callback(null, []);
} else {
callback(null, list);
}
}
}
}
);
);
}
},
});

Expand Down Expand Up @@ -3346,6 +3380,7 @@ module.exports.load = function (config, secrets) {
serviceHeaderLinks: config.serviceHeaderLinks,
templates: config.templates,
numberOfRetry: config.numberOfRetry,
callCloudSSO: config.callCloudSSO,
};
return CLIENTS.load(config, secrets);
};
Expand Down
Loading