Add GRIST_ENABLE_SCIM env variable

This commit is contained in:
fflorent 2024-09-06 20:31:13 +02:00
parent 4ba322d1cb
commit 7c8c2f2057
2 changed files with 588 additions and 558 deletions

View File

@ -890,7 +890,12 @@ export class FlexServer implements GristServer {
public addScimApi() { public addScimApi() {
if (this._check('scim', 'api', 'homedb', 'json', 'api-mw')) { return; } if (this._check('scim', 'api', 'homedb', 'json', 'api-mw')) { return; }
this.app.use('/api/scim', buildScimRouter(this._dbManager, this._installAdmin)); const scimRouter = isAffirmative(process.env.GRIST_ENABLE_SCIM) ?
buildScimRouter(this._dbManager, this._installAdmin) :
() => {
throw new ApiError('SCIM API is not enabled', 501);
};
this.app.use('/api/scim', scimRouter);
} }

View File

@ -30,26 +30,19 @@ const USER_CONFIG_BY_NAME = {
type UserConfigByName = typeof USER_CONFIG_BY_NAME; type UserConfigByName = typeof USER_CONFIG_BY_NAME;
describe('Scim', () => { describe('Scim', () => {
testUtils.setTmpLogLevel('error');
const setupTestServer = (env: NodeJS.ProcessEnv) => {
let homeUrl: string;
let oldEnv: testUtils.EnvironmentSnapshot; let oldEnv: testUtils.EnvironmentSnapshot;
let server: TestServer; let server: TestServer;
let homeUrl: string;
const userIdByName: {[name in keyof UserConfigByName]?: number} = {};
const scimUrl = (path: string) => (homeUrl + '/api/scim/v2' + path);
testUtils.setTmpLogLevel('error');
before(async function () { before(async function () {
oldEnv = new testUtils.EnvironmentSnapshot(); oldEnv = new testUtils.EnvironmentSnapshot();
process.env.GRIST_DEFAULT_EMAIL = 'chimpy@getgrist.com';
process.env.GRIST_SCIM_EMAIL = 'charon@getgrist.com';
process.env.TYPEORM_DATABASE = ':memory:'; process.env.TYPEORM_DATABASE = ':memory:';
Object.assign(process.env, env);
server = new TestServer(this); server = new TestServer(this);
homeUrl = await server.start(); homeUrl = await server.start();
const userNames = Object.keys(USER_CONFIG_BY_NAME) as Array<keyof UserConfigByName>;
for (const user of userNames) {
userIdByName[user] = await getOrCreateUserId(user);
}
}); });
after(async () => { after(async () => {
@ -57,6 +50,37 @@ describe('Scim', () => {
await server.stop(); await server.stop();
}); });
return {
scimUrl: (path: string) => (homeUrl + '/api/scim/v2' + path),
getDbManager: () => server.dbManager,
};
};
describe('when disabled', function () {
const { scimUrl } = setupTestServer({});
it('should return 501 for /api/scim/v2/Users', async function () {
const res = await axios.get(scimUrl('/Users'), chimpy);
assert.equal(res.status, 501);
assert.deepEqual(res.data, { error: 'SCIM API is not enabled' });
});
});
describe('when enabled using GRIST_ENABLE_SCIM=1', function () {
const { scimUrl, getDbManager } = setupTestServer({
GRIST_ENABLE_SCIM: '1',
GRIST_DEFAULT_EMAIL: 'chimpy@getgrist.com',
GRIST_SCIM_EMAIL: 'charon@getgrist.com',
});
const userIdByName: {[name in keyof UserConfigByName]?: number} = {};
before(async function () {
const userNames = Object.keys(USER_CONFIG_BY_NAME) as Array<keyof UserConfigByName>;
for (const user of userNames) {
userIdByName[user] = await getOrCreateUserId(user);
}
});
function personaToSCIMMYUserWithId(user: keyof UserConfigByName) { function personaToSCIMMYUserWithId(user: keyof UserConfigByName) {
return toSCIMUserWithId(user, userIdByName[user]!); return toSCIMUserWithId(user, userIdByName[user]!);
} }
@ -82,12 +106,12 @@ describe('Scim', () => {
} }
async function getOrCreateUserId(user: string) { async function getOrCreateUserId(user: string) {
return (await server.dbManager.getUserByLogin(user + '@getgrist.com'))!.id; return (await getDbManager().getUserByLogin(user + '@getgrist.com'))!.id;
} }
async function cleanupUser(userId: number) { async function cleanupUser(userId: number) {
if (await server.dbManager.getUser(userId)) { if (await getDbManager().getUser(userId)) {
await server.dbManager.deleteUser({ userId: userId }, userId); await getDbManager().deleteUser({ userId: userId }, userId);
} }
} }
@ -107,7 +131,7 @@ describe('Scim', () => {
assert.equal(res.status, 401); assert.equal(res.status, 401);
}); });
it('should return 401 for kiwi', async function () { it('should return 403 for kiwi', async function () {
const res: any = await makeCallWith('kiwi'); const res: any = await makeCallWith('kiwi');
assert.deepEqual(res.data, { assert.deepEqual(res.data, {
schemas: [ 'urn:ietf:params:scim:api:messages:2.0:Error' ], schemas: [ 'urn:ietf:params:scim:api:messages:2.0:Error' ],
@ -245,7 +269,7 @@ describe('Scim', () => {
try { try {
await cb(userName); await cb(userName);
} finally { } finally {
const user = await server.dbManager.getExistingUserByLogin(userName + "@getgrist.com"); const user = await getDbManager().getExistingUserByLogin(userName + "@getgrist.com");
if (user) { if (user) {
await cleanupUser(user.id); await cleanupUser(user.id);
} }
@ -490,7 +514,7 @@ describe('Scim', () => {
afterEach(async function () { afterEach(async function () {
for (const email of usersToCleanupEmails) { for (const email of usersToCleanupEmails) {
const user = await server.dbManager.getExistingUserByLogin(email); const user = await getDbManager().getExistingUserByLogin(email);
if (user) { if (user) {
await cleanupUser(user.id); await cleanupUser(user.id);
} }
@ -668,3 +692,4 @@ describe('Scim', () => {
assert.property(res.data, 'filter'); assert.property(res.data, 'filter');
}); });
}); });
});