Skip to main content
Glama
okta.test.ts7.09 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { ContentType, createReference } from '@medplum/core'; import type { AccessPolicy } from '@medplum/fhirtypes'; import { randomUUID } from 'crypto'; import express from 'express'; import request from 'supertest'; import { initApp, shutdownApp } from '../app'; import { registerNew } from '../auth/register'; import { loadTestConfig } from '../config/loader'; import { getSystemRepo } from '../fhir/repo'; // Based on: https://developer.okta.com/docs/guides/scim-provisioning-integration-prepare/main/ describe('Okta SCIM Tests', () => { const app = express(); let accessToken: string; beforeAll(async () => { const config = await loadTestConfig(); await initApp(app, config); const registration = await registerNew({ firstName: 'Alice', lastName: 'Smith', projectName: 'Alice Project', email: `alice${randomUUID()}@example.com`, password: 'password!@#', }); accessToken = registration.accessToken; const systemRepo = getSystemRepo(); // Create default access policy const accessPolicy = await systemRepo.createResource<AccessPolicy>({ resourceType: 'AccessPolicy', resource: [{ resourceType: 'Patient' }], }); // Update project with default access policy await systemRepo.updateResource({ ...registration.project, defaultPatientAccessPolicy: createReference(accessPolicy), }); }); afterAll(async () => { await shutdownApp(); }); test('Okta script', async () => { // #1 Required Test: Test Users endpoint const res1 = await request(app) .get('/scim/v2/Users') .set('Authorization', 'Bearer ' + accessToken); expect(res1.status).toBe(200); expect(res1.body.Resources).not.toBeNull(); expect(res1.body.schemas).toContain('urn:ietf:params:scim:api:messages:2.0:ListResponse'); expect(res1.body.itemsPerPage).toBeDefined(); expect(res1.body.startIndex).toBeDefined(); expect(res1.body.totalResults).toBeDefined(); expect(res1.body.Resources[0].id).toBeDefined(); expect(res1.body.Resources[0].name.familyName).toBeDefined(); expect(res1.body.Resources[0].name.givenName).toBeDefined(); expect(res1.body.Resources[0].userName).toBeDefined(); expect(res1.body.Resources[0].active).toBe(true); expect(res1.body.Resources[0].emails[0].value).toBeDefined(); const isvUserId = res1.body.Resources[0].id; // #2 Required Test: Get Users/{{id}} const res2 = await request(app) .get(`/scim/v2/Users/${isvUserId}`) .set('Authorization', 'Bearer ' + accessToken); expect(res2.status).toBe(200); expect(res2.body.id).toBeDefined(); expect(res2.body.name.familyName).toBeDefined(); expect(res2.body.name.givenName).toBeDefined(); expect(res2.body.userName).toBeDefined(); expect(res2.body.active).toBe(true); expect(res2.body.emails[0].value).toBeDefined(); expect(res2.body.id).toBe(isvUserId); // #3 Required Test: Test invalid User by username const res3 = await request(app) .get('/scim/v2/Users?filter=' + encodeURIComponent('userName eq "abcdefgh@atko.com"')) .set('Authorization', 'Bearer ' + accessToken); expect(res3.status).toBe(200); expect(res3.body.schemas).toContain('urn:ietf:params:scim:api:messages:2.0:ListResponse'); expect(res3.body.totalResults).toBe(0); // #4 Required Test: Test invalid User by ID const res4 = await request(app) .get('/scim/v2/Users/invaliduserid') .set('Authorization', 'Bearer ' + accessToken); expect(res4.status).toBe(404); expect(res4.body.detail).toBe('Not found'); expect(res4.body.schemas).toContain('urn:ietf:params:scim:api:messages:2.0:Error'); // #5 Required Test: Test invalid User by username const res5 = await request(app) .get('/scim/v2/Users?filter=' + encodeURIComponent('userName eq "Runscope258Fuhpfuwaw309@atko.com"')) .set('Authorization', 'Bearer ' + accessToken); expect(res5.status).toBe(200); expect(res5.body.schemas).toContain('urn:ietf:params:scim:api:messages:2.0:ListResponse'); expect(res5.body.totalResults).toBe(0); // #6 Required Test: Create Okta user with realisitic value const res6 = await request(app) .post(`/scim/v2/Users`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.JSON) .send({ schemas: ['urn:ietf:params:scim:schemas:core:2.0:User'], userName: 'Runscope258Fuhpfuwaw309@atko.com', name: { givenName: 'Runscope258', familyName: 'Fuhpfuwaw309' }, emails: [{ primary: true, value: 'Runscope258Fuhpfuwaw309@atko.com', type: 'work' }], displayName: 'Runscope258 Fuhpfuwaw309', active: true, }); expect(res6.status).toBe(201); expect(res6.body.active).toBe(true); expect(res6.body.id).toBeDefined(); expect(res6.body.name.familyName).toBe('Fuhpfuwaw309'); expect(res6.body.name.givenName).toBe('Runscope258'); expect(res6.body.schemas).toContain('urn:ietf:params:scim:schemas:core:2.0:User'); expect(res6.body.userName).toBe('Runscope258Fuhpfuwaw309@atko.com'); const idUserOne = res6.body.id; const randomUserEmail = res6.body.emails[0].value; // #7 Required Test: Verify that user was created const res7 = await request(app) .get(`/scim/v2/Users/${idUserOne}`) .set('Authorization', 'Bearer ' + accessToken); expect(res7.status).toBe(200); expect(res7.body.userName).toBe('Runscope258Fuhpfuwaw309@atko.com'); expect(res7.body.name.familyName).toBe('Fuhpfuwaw309'); expect(res7.body.name.givenName).toBe('Runscope258'); expect(res7.body.emails[0].value).toBe(randomUserEmail); // #8 Required Test: Expect failure when recreating user with same values const res8 = await request(app) .post(`/scim/v2/Users`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.JSON) .send({ schemas: ['urn:ietf:params:scim:schemas:core:2.0:User'], userName: 'Runscope258Fuhpfuwaw309@atko.com', name: { givenName: 'Runscope258', familyName: 'Fuhpfuwaw309' }, emails: [{ primary: true, value: 'Runscope258Fuhpfuwaw309@atko.com', type: 'work' }], displayName: 'Runscope258 Fuhpfuwaw309', active: true, }); expect(res8.status).toBe(409); expect(res8.body.detail).toBe('User is already a member of this project'); expect(res8.body.schemas).toContain('urn:ietf:params:scim:api:messages:2.0:Error'); // #9 Required Test: Username Case Sensitivity Check const res9 = await request(app) .get('/scim/v2/Users?filter=' + encodeURIComponent('userName eq "RUNSCOPE258FUHPFUWAW309@ATKO.COM"')) .set('Authorization', 'Bearer ' + accessToken); expect(res9.status).toBe(200); expect(res9.body.schemas).toContain('urn:ietf:params:scim:api:messages:2.0:ListResponse'); expect(res9.body.totalResults).toBe(1); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server