mirror of https://github.com/boxyhq/jackson.git
updated tap (#1615)
* updated tap * Fix the tests * Update package-lock.json * upgrade to 18.1.1 * Update package-lock.json * Update package.json --------- Co-authored-by: Kiran K <mailtokirankk@gmail.com> Co-authored-by: Kiran K <kiran@boxyhq.com>
This commit is contained in:
parent
c74ff3be80
commit
89d44ca903
|
@ -45,3 +45,4 @@ publishTag.txt
|
|||
.env
|
||||
_dev/docker/dynamodb/shared-local-instance.db
|
||||
public/terminus/sprites.png
|
||||
**/.tap/**
|
||||
|
|
|
@ -46,5 +46,5 @@ const map = {
|
|||
};
|
||||
|
||||
module.exports = (testFile) => {
|
||||
return map[testFile];
|
||||
return map[testFile] || [];
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,15 +29,11 @@
|
|||
"db:migration:run:mariadb": "cross-env DB_TYPE=mariadb DB_URL=mariadb://root@localhost:3306/mysql ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
|
||||
"db:migration:run:mssql": "cross-env DB_TYPE=mssql DB_URL='sqlserver://localhost:1433;database=master;username=sa;password=123ABabc!' ts-node --transpile-only ./node_modules/typeorm/cli.js migration:run -d typeorm.ts",
|
||||
"prepublishOnly": "npm run build",
|
||||
"test": "cross-env BOXYHQ_NO_ANALYTICS=1 tap -T --ts --coverage-map=map.js test/**/*.test.ts",
|
||||
"test": "cross-env BOXYHQ_NO_ANALYTICS=1 tap --timeout=0 --allow-incomplete-coverage --allow-empty-coverage test/**/*.test.ts",
|
||||
"sort": "npx sort-package-json"
|
||||
},
|
||||
"tap": {
|
||||
"branches": 50,
|
||||
"coverage-map": "map.js",
|
||||
"functions": 70,
|
||||
"lines": 70,
|
||||
"statements": 70
|
||||
"coverage-map": "map.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-dynamodb": "3.417.0",
|
||||
|
@ -74,7 +70,7 @@
|
|||
"cross-env": "7.0.3",
|
||||
"nock": "13.3.3",
|
||||
"sinon": "16.0.0",
|
||||
"tap": "16.3.8",
|
||||
"tap": "18.1.1",
|
||||
"ts-node": "10.9.1",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.2.2"
|
||||
|
|
|
@ -25,105 +25,108 @@ tap.before(async () => {
|
|||
});
|
||||
|
||||
tap.teardown(async () => {
|
||||
// Delete the directory after test
|
||||
await directorySync.directories.delete(directory.id);
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
tap.test('Directory groups / ', async (t) => {
|
||||
let createdGroup: any;
|
||||
|
||||
tap.beforeEach(async () => {
|
||||
// Create a group before each test
|
||||
const { data } = await directorySync.requests.handle(groupsRequest.create(directory, groups[0]));
|
||||
|
||||
createdGroup = data;
|
||||
tap.test('Directory groups /', async (t) => {
|
||||
t.teardown(async () => {
|
||||
await directorySync.directories.delete(directory.id);
|
||||
});
|
||||
|
||||
tap.afterEach(async () => {
|
||||
// Delete the group after each test
|
||||
await directorySync.groups.delete(createdGroup.id);
|
||||
});
|
||||
t.test('Directory groups /', async (t) => {
|
||||
let createdGroup: any;
|
||||
|
||||
t.test('Should be able to create a new group', async (t) => {
|
||||
t.ok(createdGroup);
|
||||
t.hasStrict(createdGroup, groups[0]);
|
||||
t.ok('id' in createdGroup);
|
||||
});
|
||||
t.beforeEach(async () => {
|
||||
// Create a group before each test
|
||||
const { data } = await directorySync.requests.handle(groupsRequest.create(directory, groups[0]));
|
||||
|
||||
t.test('Should be able to get the group by id', async (t) => {
|
||||
const request = groupsRequest.getById(directory, createdGroup.id);
|
||||
|
||||
const { status, data } = await directorySync.requests.handle(request);
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data, createdGroup);
|
||||
t.hasStrict(data, groups[0]);
|
||||
});
|
||||
|
||||
t.test('Should be able to get the group by displayName', async (t) => {
|
||||
const request = groupsRequest.filterByDisplayName(directory, createdGroup.displayName);
|
||||
|
||||
const { status, data } = await directorySync.requests.handle(request);
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data.Resources[0], createdGroup);
|
||||
t.hasStrict(data.Resources[0], groups[0]);
|
||||
t.equal(data.Resources.length, 1);
|
||||
});
|
||||
|
||||
t.test('Should be able to get all groups', async (t) => {
|
||||
const request = groupsRequest.getAll(directory);
|
||||
|
||||
const { status, data } = await directorySync.requests.handle(request);
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data.Resources[0], createdGroup);
|
||||
t.hasStrict(data.Resources[0], groups[0]);
|
||||
t.equal(data.totalResults, 1);
|
||||
t.equal(data.Resources[0].members.length, 0);
|
||||
});
|
||||
|
||||
t.test('Should be able to update the group name', async (t) => {
|
||||
const request = groupsRequest.updateName(directory, createdGroup.id, {
|
||||
...createdGroup,
|
||||
displayName: 'Developers Updated',
|
||||
createdGroup = data;
|
||||
});
|
||||
|
||||
const callback = async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.updated');
|
||||
t.match(event.data, { id: createdGroup.id, name: 'Developers Updated' });
|
||||
};
|
||||
t.afterEach(async () => {
|
||||
// Delete the group after each test
|
||||
await directorySync.groups.delete(createdGroup.id);
|
||||
});
|
||||
|
||||
const { status, data } = await directorySync.requests.handle(request, callback);
|
||||
t.test('Should be able to create a new group', async (t) => {
|
||||
t.ok(createdGroup);
|
||||
t.hasStrict(createdGroup, groups[0]);
|
||||
t.ok('id' in createdGroup);
|
||||
});
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.equal(data.displayName, 'Developers Updated');
|
||||
});
|
||||
t.test('Should be able to get the group by id', async (t) => {
|
||||
const request = groupsRequest.getById(directory, createdGroup.id);
|
||||
|
||||
t.test('Should be able to delete a group', async (t) => {
|
||||
const request = groupsRequest.deleteById(directory, createdGroup.id);
|
||||
const { status, data } = await directorySync.requests.handle(request);
|
||||
|
||||
const callback = async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.deleted');
|
||||
t.match(event.data, { id: createdGroup.id, name: 'Developers' });
|
||||
};
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data, createdGroup);
|
||||
t.hasStrict(data, groups[0]);
|
||||
});
|
||||
|
||||
const { status } = await directorySync.requests.handle(request, callback);
|
||||
t.test('Should be able to get the group by displayName', async (t) => {
|
||||
const request = groupsRequest.filterByDisplayName(directory, createdGroup.displayName);
|
||||
|
||||
t.equal(status, 200);
|
||||
const { status, data } = await directorySync.requests.handle(request);
|
||||
|
||||
// Try to get the group
|
||||
try {
|
||||
await directorySync.requests.handle(groupsRequest.getById(directory, createdGroup.id));
|
||||
} catch (e: any) {
|
||||
t.equal(e.statusCode, 404);
|
||||
t.equal(e.message, `Group with id ${createdGroup.id} not found.`);
|
||||
}
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data.Resources[0], createdGroup);
|
||||
t.hasStrict(data.Resources[0], groups[0]);
|
||||
t.equal(data.Resources.length, 1);
|
||||
});
|
||||
|
||||
t.test('Should be able to get all groups', async (t) => {
|
||||
const request = groupsRequest.getAll(directory);
|
||||
|
||||
const { status, data } = await directorySync.requests.handle(request);
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data.Resources[0], createdGroup);
|
||||
t.hasStrict(data.Resources[0], groups[0]);
|
||||
t.equal(data.totalResults, 1);
|
||||
t.equal(data.Resources[0].members.length, 0);
|
||||
});
|
||||
|
||||
t.test('Should be able to update the group name', async (t) => {
|
||||
const request = groupsRequest.updateName(directory, createdGroup.id, {
|
||||
...createdGroup,
|
||||
displayName: 'Developers Updated',
|
||||
});
|
||||
|
||||
const callback = async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.updated');
|
||||
t.match(event.data, { id: createdGroup.id, name: 'Developers Updated' });
|
||||
};
|
||||
|
||||
const { status, data } = await directorySync.requests.handle(request, callback);
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.equal(data.displayName, 'Developers Updated');
|
||||
});
|
||||
|
||||
t.test('Should be able to delete a group', async (t) => {
|
||||
const request = groupsRequest.deleteById(directory, createdGroup.id);
|
||||
|
||||
const callback = async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.deleted');
|
||||
t.match(event.data, { id: createdGroup.id, name: 'Developers' });
|
||||
};
|
||||
|
||||
const { status } = await directorySync.requests.handle(request, callback);
|
||||
|
||||
t.equal(status, 200);
|
||||
|
||||
// Try to get the group
|
||||
try {
|
||||
await directorySync.requests.handle(groupsRequest.getById(directory, createdGroup.id));
|
||||
} catch (e: any) {
|
||||
t.equal(e.statusCode, 404);
|
||||
t.equal(e.message, `Group with id ${createdGroup.id} not found.`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -43,118 +43,122 @@ tap.before(async () => {
|
|||
});
|
||||
|
||||
tap.teardown(async () => {
|
||||
await directorySync.directories.delete(directory.id);
|
||||
await directorySync.groups.delete(group.id);
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
tap.test('Directory groups membership / ', async (t) => {
|
||||
const { data: user1 } = await directorySync.requests.handle(usersRequest.create(directory, users[0]));
|
||||
const { data: user2 } = await directorySync.requests.handle(usersRequest.create(directory, users[1]));
|
||||
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user1.id), false);
|
||||
|
||||
let request = createGroupMembershipRequest(directory, group, [
|
||||
{
|
||||
op: 'add',
|
||||
path: 'members',
|
||||
value: [
|
||||
{
|
||||
value: user1.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
// Add a member to an existing group
|
||||
await directorySync.requests.handle(request, async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.user_added');
|
||||
t.match(event.data.id, user1.id);
|
||||
|
||||
if ('group' in event.data) {
|
||||
t.match(event.data.group.id, group.id);
|
||||
t.match(event.data.group.name, 'Developers');
|
||||
}
|
||||
tap.test('Directory groups membership /', async (t) => {
|
||||
t.teardown(async () => {
|
||||
await directorySync.directories.delete(directory.id);
|
||||
await directorySync.groups.delete(group.id);
|
||||
});
|
||||
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user1.id), true);
|
||||
t.test('Directory groups membership /', async (t) => {
|
||||
const { data: user1 } = await directorySync.requests.handle(usersRequest.create(directory, users[0]));
|
||||
const { data: user2 } = await directorySync.requests.handle(usersRequest.create(directory, users[1]));
|
||||
|
||||
request = createGroupMembershipRequest(directory, group, [
|
||||
{
|
||||
op: 'remove',
|
||||
path: `members[value eq "${user1.id}"]`,
|
||||
},
|
||||
]);
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user1.id), false);
|
||||
|
||||
// Remove a member from an existing group
|
||||
await directorySync.requests.handle(request, async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.user_removed');
|
||||
t.match(event.data.id, user1.id);
|
||||
let request = createGroupMembershipRequest(directory, group, [
|
||||
{
|
||||
op: 'add',
|
||||
path: 'members',
|
||||
value: [
|
||||
{
|
||||
value: user1.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
if ('group' in event.data) {
|
||||
t.match(event.data.group.id, group.id);
|
||||
t.match(event.data.group.name, 'Developers');
|
||||
}
|
||||
// Add a member to an existing group
|
||||
await directorySync.requests.handle(request, async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.user_added');
|
||||
t.match(event.data.id, user1.id);
|
||||
|
||||
if ('group' in event.data) {
|
||||
t.match(event.data.group.id, group.id);
|
||||
t.match(event.data.group.name, 'Developers');
|
||||
}
|
||||
});
|
||||
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user1.id), true);
|
||||
|
||||
request = createGroupMembershipRequest(directory, group, [
|
||||
{
|
||||
op: 'remove',
|
||||
path: `members[value eq "${user1.id}"]`,
|
||||
},
|
||||
]);
|
||||
|
||||
// Remove a member from an existing group
|
||||
await directorySync.requests.handle(request, async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.user_removed');
|
||||
t.match(event.data.id, user1.id);
|
||||
|
||||
if ('group' in event.data) {
|
||||
t.match(event.data.group.id, group.id);
|
||||
t.match(event.data.group.name, 'Developers');
|
||||
}
|
||||
});
|
||||
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user1.id), false);
|
||||
|
||||
request = createGroupMembershipRequest(directory, group, [
|
||||
{
|
||||
op: 'add',
|
||||
path: 'members',
|
||||
value: [
|
||||
{
|
||||
value: user1.id,
|
||||
},
|
||||
{
|
||||
value: user2.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
// Handle multiple operations in a single request
|
||||
await directorySync.requests.handle(request, async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.user_added');
|
||||
t.match([user1.id, user2.id].includes(event.data.id), true);
|
||||
|
||||
if ('group' in event.data) {
|
||||
t.match(event.data.group.id, group.id);
|
||||
t.match(event.data.group.name, 'Developers');
|
||||
}
|
||||
});
|
||||
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user1.id), true);
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user2.id), true);
|
||||
|
||||
request = createGroupMembershipRequest(directory, group, [
|
||||
{
|
||||
op: 'remove',
|
||||
path: 'members',
|
||||
value: [
|
||||
{
|
||||
value: user1.id,
|
||||
},
|
||||
{
|
||||
value: user2.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
// Remove all members from an existing group
|
||||
await directorySync.requests.handle(request, async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.user_removed');
|
||||
t.match([user1.id, user2.id].includes(event.data.id), true);
|
||||
|
||||
if ('group' in event.data) {
|
||||
t.match(event.data.group.id, group.id);
|
||||
t.match(event.data.group.name, 'Developers');
|
||||
}
|
||||
});
|
||||
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user1.id), false);
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user2.id), false);
|
||||
});
|
||||
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user1.id), false);
|
||||
|
||||
request = createGroupMembershipRequest(directory, group, [
|
||||
{
|
||||
op: 'add',
|
||||
path: 'members',
|
||||
value: [
|
||||
{
|
||||
value: user1.id,
|
||||
},
|
||||
{
|
||||
value: user2.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
// Handle multiple operations in a single request
|
||||
await directorySync.requests.handle(request, async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.user_added');
|
||||
t.match([user1.id, user2.id].includes(event.data.id), true);
|
||||
|
||||
if ('group' in event.data) {
|
||||
t.match(event.data.group.id, group.id);
|
||||
t.match(event.data.group.name, 'Developers');
|
||||
}
|
||||
});
|
||||
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user1.id), true);
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user2.id), true);
|
||||
|
||||
request = createGroupMembershipRequest(directory, group, [
|
||||
{
|
||||
op: 'remove',
|
||||
path: 'members',
|
||||
value: [
|
||||
{
|
||||
value: user1.id,
|
||||
},
|
||||
{
|
||||
value: user2.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
// Remove all members from an existing group
|
||||
await directorySync.requests.handle(request, async (event: DirectorySyncEvent) => {
|
||||
t.match(event.event, 'group.user_removed');
|
||||
t.match([user1.id, user2.id].includes(event.data.id), true);
|
||||
|
||||
if ('group' in event.data) {
|
||||
t.match(event.data.group.id, group.id);
|
||||
t.match(event.data.group.name, 'Developers');
|
||||
}
|
||||
});
|
||||
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user1.id), false);
|
||||
t.match(await directorySync.groups.isUserInGroup(group.id, user2.id), false);
|
||||
});
|
||||
|
|
|
@ -25,148 +25,153 @@ tap.before(async () => {
|
|||
});
|
||||
|
||||
tap.teardown(async () => {
|
||||
// Delete the directory after test
|
||||
await directorySync.directories.delete(directory.id);
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
tap.test('Directory users / ', async (t) => {
|
||||
let createdUser: any;
|
||||
|
||||
tap.beforeEach(async () => {
|
||||
// Create a user before each test
|
||||
const { data } = await directorySync.requests.handle(requests.create(directory, users[0]));
|
||||
|
||||
createdUser = data;
|
||||
tap.test('Directory users /', async (t) => {
|
||||
t.teardown(async () => {
|
||||
await directorySync.directories.delete(directory.id);
|
||||
});
|
||||
|
||||
tap.afterEach(async () => {
|
||||
// Delete the user after each test
|
||||
await directorySync.users.delete(createdUser.id);
|
||||
});
|
||||
t.test('Directory users /', async (t) => {
|
||||
let createdUser: any;
|
||||
|
||||
t.test('Should be able to get the user by userName', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.filterByUsername(directory, createdUser.userName)
|
||||
);
|
||||
t.beforeEach(async () => {
|
||||
// Create a user before each test
|
||||
const { data } = await directorySync.requests.handle(requests.create(directory, users[0]));
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data.Resources[0], createdUser);
|
||||
t.hasStrict(data.Resources[0], users[0]);
|
||||
});
|
||||
createdUser = data;
|
||||
});
|
||||
|
||||
t.test('Should be able to get the user by id', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(requests.getById(directory, createdUser.id));
|
||||
t.afterEach(async () => {
|
||||
// Delete the user after each test
|
||||
await directorySync.users.delete(createdUser.id);
|
||||
});
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data, users[0]);
|
||||
});
|
||||
t.test('Should be able to get the user by userName', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.filterByUsername(directory, createdUser.userName)
|
||||
);
|
||||
|
||||
t.test('Should be able to update the user using PUT request', async (t) => {
|
||||
const toUpdate = {
|
||||
...users[0],
|
||||
name: {
|
||||
givenName: 'Jackson Updated',
|
||||
familyName: 'M',
|
||||
},
|
||||
city: 'New York',
|
||||
};
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data.Resources[0], createdUser);
|
||||
t.hasStrict(data.Resources[0], users[0]);
|
||||
});
|
||||
|
||||
const { status, data: updatedUser } = await directorySync.requests.handle(
|
||||
requests.updateById(directory, createdUser.id, toUpdate)
|
||||
);
|
||||
t.test('Should be able to get the user by id', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.getById(directory, createdUser.id)
|
||||
);
|
||||
|
||||
t.ok(updatedUser);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(updatedUser, toUpdate);
|
||||
t.match(updatedUser.city, toUpdate.city);
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data, users[0]);
|
||||
});
|
||||
|
||||
// Make sure the user was updated
|
||||
const { data: user } = await directorySync.requests.handle(requests.getById(directory, createdUser.id));
|
||||
t.test('Should be able to update the user using PUT request', async (t) => {
|
||||
const toUpdate = {
|
||||
...users[0],
|
||||
name: {
|
||||
givenName: 'Jackson Updated',
|
||||
familyName: 'M',
|
||||
},
|
||||
city: 'New York',
|
||||
};
|
||||
|
||||
t.ok(user);
|
||||
t.hasStrict(user, toUpdate);
|
||||
t.match(user.city, toUpdate.city);
|
||||
});
|
||||
const { status, data: updatedUser } = await directorySync.requests.handle(
|
||||
requests.updateById(directory, createdUser.id, toUpdate)
|
||||
);
|
||||
|
||||
t.test('Should be able to delete the user using PATCH request', async (t) => {
|
||||
const toUpdate = {
|
||||
...users[0],
|
||||
active: false,
|
||||
};
|
||||
t.ok(updatedUser);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(updatedUser, toUpdate);
|
||||
t.match(updatedUser.city, toUpdate.city);
|
||||
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.updateOperationById(directory, createdUser.id)
|
||||
);
|
||||
// Make sure the user was updated
|
||||
const { data: user } = await directorySync.requests.handle(requests.getById(directory, createdUser.id));
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data, toUpdate);
|
||||
});
|
||||
t.ok(user);
|
||||
t.hasStrict(user, toUpdate);
|
||||
t.match(user.city, toUpdate.city);
|
||||
});
|
||||
|
||||
t.test('should be able to update the user with multi-valued properties', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.multiValuedProperties(directory, createdUser.id)
|
||||
);
|
||||
t.test('Should be able to delete the user using PATCH request', async (t) => {
|
||||
const toUpdate = {
|
||||
...users[0],
|
||||
active: false,
|
||||
};
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.equal(data.active, false);
|
||||
t.equal(data.name.givenName, 'David');
|
||||
t.equal(data.name.familyName, 'Jones');
|
||||
});
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.updateOperationById(directory, createdUser.id)
|
||||
);
|
||||
|
||||
t.test('Should be able to update the custom user attributes', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.customAttributes(directory, createdUser.id)
|
||||
);
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.hasStrict(data, toUpdate);
|
||||
});
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.equal(data.companyName, 'BoxyHQ');
|
||||
t.equal(data.address.streetAddress, '123 Main St');
|
||||
});
|
||||
t.test('should be able to update the user with multi-valued properties', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.multiValuedProperties(directory, createdUser.id)
|
||||
);
|
||||
|
||||
t.test('Should be able to fetch all users', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(requests.getAll(directory));
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.equal(data.active, false);
|
||||
t.equal(data.name.givenName, 'David');
|
||||
t.equal(data.name.familyName, 'Jones');
|
||||
});
|
||||
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.ok(data.Resources);
|
||||
t.equal(data.Resources.length, 1);
|
||||
t.hasStrict(data.Resources[0], users[0]);
|
||||
t.equal(data.totalResults, 1);
|
||||
});
|
||||
t.test('Should be able to update the custom user attributes', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.customAttributes(directory, createdUser.id)
|
||||
);
|
||||
|
||||
t.test('Should be able to delete the user', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.deleteById(directory, createdUser.id)
|
||||
);
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.equal(data.companyName, 'BoxyHQ');
|
||||
t.equal(data.address.streetAddress, '123 Main St');
|
||||
});
|
||||
|
||||
t.equal(status, 200);
|
||||
t.ok(data);
|
||||
t.strictSame(data, createdUser);
|
||||
t.test('Should be able to fetch all users', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(requests.getAll(directory));
|
||||
|
||||
// Make sure the user was deleted
|
||||
const { data: user } = await directorySync.requests.handle(
|
||||
requests.filterByUsername(directory, createdUser.userName)
|
||||
);
|
||||
t.ok(data);
|
||||
t.equal(status, 200);
|
||||
t.ok(data.Resources);
|
||||
t.equal(data.Resources.length, 1);
|
||||
t.hasStrict(data.Resources[0], users[0]);
|
||||
t.equal(data.totalResults, 1);
|
||||
});
|
||||
|
||||
t.hasStrict(user.Resources, []);
|
||||
t.hasStrict(user.totalResults, 0);
|
||||
});
|
||||
t.test('Should be able to delete the user', async (t) => {
|
||||
const { status, data } = await directorySync.requests.handle(
|
||||
requests.deleteById(directory, createdUser.id)
|
||||
);
|
||||
|
||||
t.test('Should be able to delete all users using deleteAll() method', async (t) => {
|
||||
directorySync.users.setTenantAndProduct(directory.tenant, directory.product);
|
||||
t.equal(status, 200);
|
||||
t.ok(data);
|
||||
t.strictSame(data, createdUser);
|
||||
|
||||
await directorySync.users.deleteAll(directory.id);
|
||||
// Make sure the user was deleted
|
||||
const { data: user } = await directorySync.requests.handle(
|
||||
requests.filterByUsername(directory, createdUser.userName)
|
||||
);
|
||||
|
||||
// Make sure all the user was deleted
|
||||
const { data: users } = await directorySync.users.getAll();
|
||||
t.hasStrict(user.Resources, []);
|
||||
t.hasStrict(user.totalResults, 0);
|
||||
});
|
||||
|
||||
t.equal(users?.length, 0);
|
||||
t.test('Should be able to delete all users using deleteAll() method', async (t) => {
|
||||
directorySync.users.setTenantAndProduct(directory.tenant, directory.product);
|
||||
|
||||
await directorySync.users.deleteAll(directory.id);
|
||||
|
||||
// Make sure all the user was deleted
|
||||
const { data: users } = await directorySync.users.getAll();
|
||||
|
||||
t.equal(users?.length, 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -52,246 +52,249 @@ tap.before(async () => {
|
|||
});
|
||||
|
||||
tap.teardown(async () => {
|
||||
// Delete the directory after the test
|
||||
await directorySync.directories.delete(directory.id);
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
tap.test('Webhook Events / ', async (t) => {
|
||||
tap.afterEach(async () => {
|
||||
await directorySync.webhookLogs.deleteAll(directory.id);
|
||||
tap.test('Webhook Events /', async (t) => {
|
||||
t.teardown(async () => {
|
||||
await directorySync.directories.delete(directory.id);
|
||||
});
|
||||
|
||||
t.test("Should be able to get the directory's webhook", async (t) => {
|
||||
t.match(directory.webhook.endpoint, webhook.endpoint);
|
||||
t.match(directory.webhook.secret, webhook.secret);
|
||||
});
|
||||
|
||||
t.test('Should not log events if the directory has no webhook', async (t) => {
|
||||
await directorySync.directories.update(directory.id, {
|
||||
webhook: {
|
||||
endpoint: '',
|
||||
secret: '',
|
||||
},
|
||||
t.test('Webhook Events / ', async (t) => {
|
||||
t.afterEach(async () => {
|
||||
await directorySync.webhookLogs.deleteAll(directory.id);
|
||||
});
|
||||
|
||||
// Create a user
|
||||
await directorySync.requests.handle(usersRequest.create(directory, users[0]), eventCallback);
|
||||
|
||||
const events = await directorySync.webhookLogs.getAll();
|
||||
|
||||
t.equal(events.length, 0);
|
||||
|
||||
// Restore the directory's webhook
|
||||
await directorySync.directories.update(directory.id, {
|
||||
webhook: {
|
||||
endpoint: webhook.endpoint,
|
||||
secret: webhook.secret,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
t.test('Should not log webhook events if the logging is turned off', async (t) => {
|
||||
// Turn off webhook event logging for the directory
|
||||
await directorySync.directories.update(directory.id, {
|
||||
log_webhook_events: false,
|
||||
t.test("Should be able to get the directory's webhook", async (t) => {
|
||||
t.match(directory.webhook.endpoint, webhook.endpoint);
|
||||
t.match(directory.webhook.secret, webhook.secret);
|
||||
});
|
||||
|
||||
// Create a user
|
||||
await directorySync.requests.handle(usersRequest.create(directory, users[0]), eventCallback);
|
||||
t.test('Should not log events if the directory has no webhook', async (t) => {
|
||||
await directorySync.directories.update(directory.id, {
|
||||
webhook: {
|
||||
endpoint: '',
|
||||
secret: '',
|
||||
},
|
||||
});
|
||||
|
||||
const events = await directorySync.webhookLogs.getAll();
|
||||
// Create a user
|
||||
await directorySync.requests.handle(usersRequest.create(directory, users[0]), eventCallback);
|
||||
|
||||
t.equal(events.length, 0);
|
||||
const events = await directorySync.webhookLogs.getAll();
|
||||
|
||||
// Turn on webhook event logging for the directory
|
||||
await directorySync.directories.update(directory.id, {
|
||||
log_webhook_events: true,
|
||||
t.equal(events.length, 0);
|
||||
|
||||
// Restore the directory's webhook
|
||||
await directorySync.directories.update(directory.id, {
|
||||
webhook: {
|
||||
endpoint: webhook.endpoint,
|
||||
secret: webhook.secret,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
t.test('Should be able to get an event by id', async (t) => {
|
||||
// Create a user
|
||||
await directorySync.requests.handle(usersRequest.create(directory, users[0]), eventCallback);
|
||||
t.test('Should not log webhook events if the logging is turned off', async (t) => {
|
||||
// Turn off webhook event logging for the directory
|
||||
await directorySync.directories.update(directory.id, {
|
||||
log_webhook_events: false,
|
||||
});
|
||||
|
||||
const logs = await directorySync.webhookLogs.getAll();
|
||||
// Create a user
|
||||
await directorySync.requests.handle(usersRequest.create(directory, users[0]), eventCallback);
|
||||
|
||||
const log = await directorySync.webhookLogs.get(logs[0].id);
|
||||
const events = await directorySync.webhookLogs.getAll();
|
||||
|
||||
t.equal(log.id, logs[0].id);
|
||||
});
|
||||
t.equal(events.length, 0);
|
||||
|
||||
t.test('Should send user related events', async (t) => {
|
||||
const mock = sinon.mock(axios);
|
||||
// Turn on webhook event logging for the directory
|
||||
await directorySync.directories.update(directory.id, {
|
||||
log_webhook_events: true,
|
||||
});
|
||||
});
|
||||
|
||||
mock.expects('post').thrice().withArgs(webhook.endpoint).throws();
|
||||
t.test('Should be able to get an event by id', async (t) => {
|
||||
// Create a user
|
||||
await directorySync.requests.handle(usersRequest.create(directory, users[0]), eventCallback);
|
||||
|
||||
// Create the user
|
||||
const { data: createdUser } = await directorySync.requests.handle(
|
||||
usersRequest.create(directory, users[0]),
|
||||
eventCallback
|
||||
);
|
||||
const logs = await directorySync.webhookLogs.getAll();
|
||||
|
||||
// Update the user
|
||||
const { data: updatedUser } = await directorySync.requests.handle(
|
||||
usersRequest.updateById(directory, createdUser.id, users[0]),
|
||||
eventCallback
|
||||
);
|
||||
const log = await directorySync.webhookLogs.get(logs[0].id);
|
||||
|
||||
// Delete the user
|
||||
const { data: deletedUser } = await directorySync.requests.handle(
|
||||
usersRequest.deleteById(directory, createdUser.id),
|
||||
eventCallback
|
||||
);
|
||||
t.equal(log.id, logs[0].id);
|
||||
});
|
||||
|
||||
mock.verify();
|
||||
mock.restore();
|
||||
t.test('Should send user related events', async (t) => {
|
||||
const mock = sinon.mock(axios);
|
||||
|
||||
const logs = await directorySync.webhookLogs.getAll();
|
||||
mock.expects('post').thrice().withArgs(webhook.endpoint).throws();
|
||||
|
||||
t.ok(logs);
|
||||
t.equal(logs.length, 3);
|
||||
// Create the user
|
||||
const { data: createdUser } = await directorySync.requests.handle(
|
||||
usersRequest.create(directory, users[0]),
|
||||
eventCallback
|
||||
);
|
||||
|
||||
t.match(logs[0].event, 'user.deleted');
|
||||
t.match(logs[0].directory_id, directory.id);
|
||||
t.hasStrict(logs[0].data.raw, deletedUser);
|
||||
// Update the user
|
||||
const { data: updatedUser } = await directorySync.requests.handle(
|
||||
usersRequest.updateById(directory, createdUser.id, users[0]),
|
||||
eventCallback
|
||||
);
|
||||
|
||||
t.match(logs[1].event, 'user.updated');
|
||||
t.match(logs[1].directory_id, directory.id);
|
||||
t.hasStrict(logs[1].data.raw, updatedUser);
|
||||
// Delete the user
|
||||
const { data: deletedUser } = await directorySync.requests.handle(
|
||||
usersRequest.deleteById(directory, createdUser.id),
|
||||
eventCallback
|
||||
);
|
||||
|
||||
t.match(logs[2].event, 'user.created');
|
||||
t.match(logs[2].directory_id, directory.id);
|
||||
t.hasStrict(logs[2].data.raw, createdUser);
|
||||
mock.verify();
|
||||
mock.restore();
|
||||
|
||||
await directorySync.users.deleteAll(directory.id);
|
||||
});
|
||||
const logs = await directorySync.webhookLogs.getAll();
|
||||
|
||||
t.test('Should send group related events', async (t) => {
|
||||
const mock = sinon.mock(axios);
|
||||
t.ok(logs);
|
||||
t.equal(logs.length, 3);
|
||||
|
||||
mock.expects('post').thrice().withArgs(webhook.endpoint).throws();
|
||||
t.match(logs[0].event, 'user.deleted');
|
||||
t.match(logs[0].directory_id, directory.id);
|
||||
t.hasStrict(logs[0].data.raw, deletedUser);
|
||||
|
||||
// Create the group
|
||||
const { data: createdGroup } = await directorySync.requests.handle(
|
||||
groupRequest.create(directory, groups[0]),
|
||||
eventCallback
|
||||
);
|
||||
t.match(logs[1].event, 'user.updated');
|
||||
t.match(logs[1].directory_id, directory.id);
|
||||
t.hasStrict(logs[1].data.raw, updatedUser);
|
||||
|
||||
// Update the group
|
||||
const { data: updatedGroup } = await directorySync.requests.handle(
|
||||
groupRequest.updateById(directory, createdGroup.id, groups[0]),
|
||||
eventCallback
|
||||
);
|
||||
t.match(logs[2].event, 'user.created');
|
||||
t.match(logs[2].directory_id, directory.id);
|
||||
t.hasStrict(logs[2].data.raw, createdUser);
|
||||
|
||||
// Delete the group
|
||||
const { data: deletedGroup } = await directorySync.requests.handle(
|
||||
groupRequest.deleteById(directory, createdGroup.id),
|
||||
eventCallback
|
||||
);
|
||||
await directorySync.users.deleteAll(directory.id);
|
||||
});
|
||||
|
||||
mock.verify();
|
||||
mock.restore();
|
||||
t.test('Should send group related events', async (t) => {
|
||||
const mock = sinon.mock(axios);
|
||||
|
||||
const logs = await directorySync.webhookLogs.getAll();
|
||||
mock.expects('post').thrice().withArgs(webhook.endpoint).throws();
|
||||
|
||||
t.ok(logs);
|
||||
t.equal(logs.length, 3);
|
||||
// Create the group
|
||||
const { data: createdGroup } = await directorySync.requests.handle(
|
||||
groupRequest.create(directory, groups[0]),
|
||||
eventCallback
|
||||
);
|
||||
|
||||
t.match(logs[0].event, 'group.deleted');
|
||||
t.match(logs[0].directory_id, directory.id);
|
||||
t.hasStrict(logs[0].data.raw, deletedGroup);
|
||||
// Update the group
|
||||
const { data: updatedGroup } = await directorySync.requests.handle(
|
||||
groupRequest.updateById(directory, createdGroup.id, groups[0]),
|
||||
eventCallback
|
||||
);
|
||||
|
||||
t.match(logs[1].event, 'group.updated');
|
||||
t.match(logs[1].directory_id, directory.id);
|
||||
t.hasStrict(logs[1].data.raw, updatedGroup);
|
||||
// Delete the group
|
||||
const { data: deletedGroup } = await directorySync.requests.handle(
|
||||
groupRequest.deleteById(directory, createdGroup.id),
|
||||
eventCallback
|
||||
);
|
||||
|
||||
t.match(logs[2].event, 'group.created');
|
||||
t.match(logs[2].directory_id, directory.id);
|
||||
t.hasStrict(logs[2].data.raw, createdGroup);
|
||||
});
|
||||
mock.verify();
|
||||
mock.restore();
|
||||
|
||||
t.test('Should send group membership related events', async (t) => {
|
||||
const mock = sinon.mock(axios);
|
||||
const logs = await directorySync.webhookLogs.getAll();
|
||||
|
||||
mock.expects('post').exactly(4).withArgs(webhook.endpoint).throws();
|
||||
t.ok(logs);
|
||||
t.equal(logs.length, 3);
|
||||
|
||||
// Create the user
|
||||
const { data: createdUser } = await directorySync.requests.handle(
|
||||
usersRequest.create(directory, users[0]),
|
||||
eventCallback
|
||||
);
|
||||
t.match(logs[0].event, 'group.deleted');
|
||||
t.match(logs[0].directory_id, directory.id);
|
||||
t.hasStrict(logs[0].data.raw, deletedGroup);
|
||||
|
||||
// Create the group
|
||||
const { data: createdGroup } = await directorySync.requests.handle(
|
||||
groupRequest.create(directory, groups[0]),
|
||||
eventCallback
|
||||
);
|
||||
t.match(logs[1].event, 'group.updated');
|
||||
t.match(logs[1].directory_id, directory.id);
|
||||
t.hasStrict(logs[1].data.raw, updatedGroup);
|
||||
|
||||
// Add the user to the group
|
||||
await directorySync.requests.handle(
|
||||
groupRequest.addMembers(directory, createdGroup.id, [{ value: createdUser.id }]),
|
||||
eventCallback
|
||||
);
|
||||
t.match(logs[2].event, 'group.created');
|
||||
t.match(logs[2].directory_id, directory.id);
|
||||
t.hasStrict(logs[2].data.raw, createdGroup);
|
||||
});
|
||||
|
||||
// Remove the user from the group
|
||||
await directorySync.requests.handle(
|
||||
groupRequest.removeMembers(
|
||||
directory,
|
||||
createdGroup.id,
|
||||
[{ value: createdUser.id }],
|
||||
`members[value eq "${createdUser.id}"]`
|
||||
),
|
||||
eventCallback
|
||||
);
|
||||
t.test('Should send group membership related events', async (t) => {
|
||||
const mock = sinon.mock(axios);
|
||||
|
||||
mock.verify();
|
||||
mock.restore();
|
||||
mock.expects('post').exactly(4).withArgs(webhook.endpoint).throws();
|
||||
|
||||
const logs = await directorySync.webhookLogs.getAll();
|
||||
// Create the user
|
||||
const { data: createdUser } = await directorySync.requests.handle(
|
||||
usersRequest.create(directory, users[0]),
|
||||
eventCallback
|
||||
);
|
||||
|
||||
t.ok(logs);
|
||||
t.equal(logs.length, 4);
|
||||
// Create the group
|
||||
const { data: createdGroup } = await directorySync.requests.handle(
|
||||
groupRequest.create(directory, groups[0]),
|
||||
eventCallback
|
||||
);
|
||||
|
||||
t.match(logs[0].event, 'group.user_removed');
|
||||
t.match(logs[0].directory_id, directory.id);
|
||||
t.hasStrict(logs[0].data.raw, createdUser);
|
||||
// Add the user to the group
|
||||
await directorySync.requests.handle(
|
||||
groupRequest.addMembers(directory, createdGroup.id, [{ value: createdUser.id }]),
|
||||
eventCallback
|
||||
);
|
||||
|
||||
t.match(logs[1].event, 'group.user_added');
|
||||
t.match(logs[1].directory_id, directory.id);
|
||||
t.hasStrict(logs[1].data.raw, createdUser);
|
||||
// Remove the user from the group
|
||||
await directorySync.requests.handle(
|
||||
groupRequest.removeMembers(
|
||||
directory,
|
||||
createdGroup.id,
|
||||
[{ value: createdUser.id }],
|
||||
`members[value eq "${createdUser.id}"]`
|
||||
),
|
||||
eventCallback
|
||||
);
|
||||
|
||||
await directorySync.users.delete(createdUser.id);
|
||||
await directorySync.groups.delete(createdGroup.id);
|
||||
});
|
||||
mock.verify();
|
||||
mock.restore();
|
||||
|
||||
t.test('createSignatureString()', async (t) => {
|
||||
const event: DirectorySyncEvent = {
|
||||
event: 'user.created',
|
||||
directory_id: directory.id,
|
||||
tenant: directory.tenant,
|
||||
product: directory.product,
|
||||
data: {
|
||||
raw: [],
|
||||
id: 'user-id',
|
||||
first_name: 'Kiran',
|
||||
last_name: 'Krishnan',
|
||||
email: 'kiran@boxyhq.com',
|
||||
active: true,
|
||||
},
|
||||
};
|
||||
const logs = await directorySync.webhookLogs.getAll();
|
||||
|
||||
const signatureString = createSignatureString(directory.webhook.secret, event);
|
||||
const parts = signatureString.split(',');
|
||||
t.ok(logs);
|
||||
t.equal(logs.length, 4);
|
||||
|
||||
t.ok(signatureString);
|
||||
t.ok(parts[0].match(/^t=[0-9a-f]/));
|
||||
t.ok(parts[1].match(/^s=[0-9a-f]/));
|
||||
t.match(logs[0].event, 'group.user_removed');
|
||||
t.match(logs[0].directory_id, directory.id);
|
||||
t.hasStrict(logs[0].data.raw, createdUser);
|
||||
|
||||
// Empty secret should create an empty signature
|
||||
const emptySignatureString = createSignatureString('', event);
|
||||
t.match(logs[1].event, 'group.user_added');
|
||||
t.match(logs[1].directory_id, directory.id);
|
||||
t.hasStrict(logs[1].data.raw, createdUser);
|
||||
|
||||
t.match(emptySignatureString, '');
|
||||
await directorySync.users.delete(createdUser.id);
|
||||
await directorySync.groups.delete(createdGroup.id);
|
||||
});
|
||||
|
||||
t.test('createSignatureString()', async (t) => {
|
||||
const event: DirectorySyncEvent = {
|
||||
event: 'user.created',
|
||||
directory_id: directory.id,
|
||||
tenant: directory.tenant,
|
||||
product: directory.product,
|
||||
data: {
|
||||
raw: [],
|
||||
id: 'user-id',
|
||||
first_name: 'Kiran',
|
||||
last_name: 'Krishnan',
|
||||
email: 'kiran@boxyhq.com',
|
||||
active: true,
|
||||
},
|
||||
};
|
||||
|
||||
const signatureString = createSignatureString(directory.webhook.secret, event);
|
||||
const parts = signatureString.split(',');
|
||||
|
||||
t.ok(signatureString);
|
||||
t.ok(parts[0].match(/^t=[0-9a-f]/));
|
||||
t.ok(parts[1].match(/^s=[0-9a-f]/));
|
||||
|
||||
// Empty secret should create an empty signature
|
||||
const emptySignatureString = createSignatureString('', event);
|
||||
|
||||
t.match(emptySignatureString, '');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -51,72 +51,79 @@ tap.before(async () => {
|
|||
});
|
||||
});
|
||||
|
||||
tap.test('Federated SAML flow', async () => {
|
||||
const relayStateFromSP = 'sp-saml-request-relay-state';
|
||||
|
||||
const requestXML = await fs.readFile(path.join(__dirname, '/data/request.xml'), 'utf8');
|
||||
const responseXML = await fs.readFile(path.join(__dirname, '/data/response.xml'), 'utf8');
|
||||
|
||||
const samlRequestFromSP = Buffer.from(await deflateRawAsync(requestXML)).toString('base64');
|
||||
const samlResponseFromIdP = Buffer.from(responseXML).toString('base64');
|
||||
|
||||
let jacksonRelayState: string | null = null;
|
||||
|
||||
tap.test('Should be able to accept SAML Request from SP and generate SAML Request for IdP', async (t) => {
|
||||
const response = await samlFederatedController.sso.getAuthorizeUrl({
|
||||
request: samlRequestFromSP,
|
||||
relayState: relayStateFromSP,
|
||||
});
|
||||
|
||||
// Extract relay state created by Jackson
|
||||
jacksonRelayState = new URL(response.redirectUrl).searchParams.get('RelayState');
|
||||
|
||||
t.ok(
|
||||
response.redirectUrl?.startsWith(`${connection.idpMetadata.sso.redirectUrl}`),
|
||||
'Should have a SSO URL that starts with IdP SSO URL'
|
||||
);
|
||||
t.ok(response.redirectUrl, 'Should have a redirect URL');
|
||||
t.ok(response.redirectUrl?.includes('SAMLRequest'), 'Should have a SAMLRequest in the redirect URL');
|
||||
t.ok(response.redirectUrl?.includes('RelayState'), 'Should have a RelayState in the redirect URL');
|
||||
});
|
||||
|
||||
tap.test('Should be able to accept SAML Response from IdP and generate SAML Response for SP', async (t) => {
|
||||
const stubValidate = sinon.stub(saml, 'validate').resolves({
|
||||
audience: 'https://saml.boxyhq.com',
|
||||
claims: {
|
||||
id: '00u3e3cmpdDydXdzV5d7',
|
||||
email: 'kiran@boxyhq.com',
|
||||
firstName: 'Kiran',
|
||||
lastName: 'Krishnan',
|
||||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier': 'kiran@boxyhq.com',
|
||||
},
|
||||
issuer: 'https://saml.example.com/entityid',
|
||||
sessionIndex: '_a30730c45288bbc4986b',
|
||||
});
|
||||
|
||||
const response = await oauthController.samlResponse({
|
||||
SAMLResponse: samlResponseFromIdP,
|
||||
RelayState: jacksonRelayState ?? '',
|
||||
});
|
||||
|
||||
t.ok(response);
|
||||
t.ok('responseForm' in response);
|
||||
t.ok(response.responseForm?.includes('SAMLResponse'), 'Should have a SAMLResponse in the response form');
|
||||
t.ok(response.responseForm?.includes('RelayState'), 'Should have a RelayState in the response form');
|
||||
|
||||
const relayState = response.responseForm
|
||||
? response.responseForm.match(/<input type="hidden" name="RelayState" value="(.*)"\/>/)?.[1]
|
||||
: null;
|
||||
|
||||
t.match(relayState, relayStateFromSP, 'Should have the same relay state as the one sent by SP');
|
||||
|
||||
stubValidate.restore();
|
||||
});
|
||||
});
|
||||
|
||||
tap.teardown(async () => {
|
||||
await samlFederatedController.app.delete(app.id);
|
||||
await connectionAPIController.deleteConnections({ tenant, product });
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
tap.test('Federated SAML flow', async (t) => {
|
||||
t.teardown(async () => {
|
||||
await samlFederatedController.app.delete(app.id);
|
||||
await connectionAPIController.deleteConnections({ tenant, product });
|
||||
});
|
||||
|
||||
t.test('Federated SAML flow', async (t) => {
|
||||
const relayStateFromSP = 'sp-saml-request-relay-state';
|
||||
|
||||
const requestXML = await fs.readFile(path.join(__dirname, '/data/request.xml'), 'utf8');
|
||||
const responseXML = await fs.readFile(path.join(__dirname, '/data/response.xml'), 'utf8');
|
||||
|
||||
const samlRequestFromSP = Buffer.from(await deflateRawAsync(requestXML)).toString('base64');
|
||||
const samlResponseFromIdP = Buffer.from(responseXML).toString('base64');
|
||||
|
||||
let jacksonRelayState: string | null = null;
|
||||
|
||||
t.test('Should be able to accept SAML Request from SP and generate SAML Request for IdP', async (t) => {
|
||||
const response = await samlFederatedController.sso.getAuthorizeUrl({
|
||||
request: samlRequestFromSP,
|
||||
relayState: relayStateFromSP,
|
||||
});
|
||||
|
||||
// Extract relay state created by Jackson
|
||||
jacksonRelayState = new URL(response.redirectUrl).searchParams.get('RelayState');
|
||||
|
||||
t.ok(
|
||||
response.redirectUrl?.startsWith(`${connection.idpMetadata.sso.redirectUrl}`),
|
||||
'Should have a SSO URL that starts with IdP SSO URL'
|
||||
);
|
||||
t.ok(response.redirectUrl, 'Should have a redirect URL');
|
||||
t.ok(response.redirectUrl?.includes('SAMLRequest'), 'Should have a SAMLRequest in the redirect URL');
|
||||
t.ok(response.redirectUrl?.includes('RelayState'), 'Should have a RelayState in the redirect URL');
|
||||
});
|
||||
|
||||
t.test('Should be able to accept SAML Response from IdP and generate SAML Response for SP', async (t) => {
|
||||
const stubValidate = sinon.stub(saml, 'validate').resolves({
|
||||
audience: 'https://saml.boxyhq.com',
|
||||
claims: {
|
||||
id: '00u3e3cmpdDydXdzV5d7',
|
||||
email: 'kiran@boxyhq.com',
|
||||
firstName: 'Kiran',
|
||||
lastName: 'Krishnan',
|
||||
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier': 'kiran@boxyhq.com',
|
||||
},
|
||||
issuer: 'https://saml.example.com/entityid',
|
||||
sessionIndex: '_a30730c45288bbc4986b',
|
||||
});
|
||||
|
||||
const response = await oauthController.samlResponse({
|
||||
SAMLResponse: samlResponseFromIdP,
|
||||
RelayState: jacksonRelayState ?? '',
|
||||
});
|
||||
|
||||
t.ok(response);
|
||||
t.ok('responseForm' in response);
|
||||
t.ok(
|
||||
response.responseForm?.includes('SAMLResponse'),
|
||||
'Should have a SAMLResponse in the response form'
|
||||
);
|
||||
t.ok(response.responseForm?.includes('RelayState'), 'Should have a RelayState in the response form');
|
||||
|
||||
const relayState = response.responseForm
|
||||
? response.responseForm.match(/<input type="hidden" name="RelayState" value="(.*)"\/>/)?.[1]
|
||||
: null;
|
||||
|
||||
t.match(relayState, relayStateFromSP, 'Should have the same relay state as the one sent by SP');
|
||||
|
||||
stubValidate.restore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue