Merge pull request #2108 from automatisch/aut-1282
test(access-token): write model tests
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`AccessToken model > jsonSchema should have correct validations 1`] = `
|
||||
{
|
||||
"properties": {
|
||||
"expiresIn": {
|
||||
"type": "integer",
|
||||
},
|
||||
"id": {
|
||||
"format": "uuid",
|
||||
"type": "string",
|
||||
},
|
||||
"revokedAt": {
|
||||
"format": "date-time",
|
||||
"type": [
|
||||
"string",
|
||||
"null",
|
||||
],
|
||||
},
|
||||
"samlSessionId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null",
|
||||
],
|
||||
},
|
||||
"token": {
|
||||
"minLength": 32,
|
||||
"type": "string",
|
||||
},
|
||||
"userId": {
|
||||
"format": "uuid",
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"token",
|
||||
"expiresIn",
|
||||
],
|
||||
"type": "object",
|
||||
}
|
||||
`;
|
@@ -34,24 +34,25 @@ class AccessToken extends Base {
|
||||
return;
|
||||
}
|
||||
|
||||
const user = await this
|
||||
.$relatedQuery('user');
|
||||
const user = await this.$relatedQuery('user');
|
||||
|
||||
const firstIdentity = await user
|
||||
.$relatedQuery('identities')
|
||||
.first();
|
||||
const firstIdentity = await user.$relatedQuery('identities').first();
|
||||
|
||||
const samlAuthProvider = await firstIdentity
|
||||
.$relatedQuery('samlAuthProvider')
|
||||
.throwIfNotFound();
|
||||
|
||||
const response = await samlAuthProvider.terminateRemoteSession(this.samlSessionId);
|
||||
const response = await samlAuthProvider.terminateRemoteSession(
|
||||
this.samlSessionId
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async revoke() {
|
||||
const response = await this.$query().patch({ revokedAt: new Date().toISOString() });
|
||||
const response = await this.$query().patch({
|
||||
revokedAt: new Date().toISOString(),
|
||||
});
|
||||
|
||||
try {
|
||||
await this.terminateRemoteSamlSession();
|
||||
|
84
packages/backend/src/models/access-token.test.js
Normal file
84
packages/backend/src/models/access-token.test.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import AccessToken from './access-token.js';
|
||||
import User from './user.js';
|
||||
import Base from './base.js';
|
||||
import SamlAuthProvider from './saml-auth-provider.ee.js';
|
||||
import { createAccessToken } from '../../test/factories/access-token.js';
|
||||
import { createUser } from '../../test/factories/user.js';
|
||||
import { createIdentity } from '../../test/factories/identity.js';
|
||||
|
||||
describe('AccessToken model', () => {
|
||||
it('tableName should return correct name', () => {
|
||||
expect(AccessToken.tableName).toBe('access_tokens');
|
||||
});
|
||||
|
||||
it('jsonSchema should have correct validations', () => {
|
||||
expect(AccessToken.jsonSchema).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('relationMappings should return correct associations', () => {
|
||||
const relationMappings = AccessToken.relationMappings();
|
||||
|
||||
const expectedRelations = {
|
||||
user: {
|
||||
relation: Base.BelongsToOneRelation,
|
||||
modelClass: User,
|
||||
join: {
|
||||
from: 'access_tokens.user_id',
|
||||
to: 'users.id',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(relationMappings).toStrictEqual(expectedRelations);
|
||||
});
|
||||
|
||||
it('revoke should set revokedAt and terminate remote SAML session', async () => {
|
||||
const accessToken = await createAccessToken();
|
||||
|
||||
const terminateRemoteSamlSessionSpy = vi
|
||||
.spyOn(accessToken, 'terminateRemoteSamlSession')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
await accessToken.revoke();
|
||||
|
||||
expect(terminateRemoteSamlSessionSpy).toHaveBeenCalledOnce();
|
||||
expect(accessToken.revokedAt).not.toBeUndefined();
|
||||
});
|
||||
|
||||
describe('terminateRemoteSamlSession', () => {
|
||||
it('should terminate remote SAML session when exists', async () => {
|
||||
const user = await createUser();
|
||||
const accessToken = await createAccessToken({
|
||||
userId: user.id,
|
||||
samlSessionId: 'random-remote-session-id',
|
||||
});
|
||||
await createIdentity({ userId: user.id });
|
||||
|
||||
const terminateRemoteSamlSessionSpy = vi
|
||||
.spyOn(SamlAuthProvider.prototype, 'terminateRemoteSession')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
await accessToken.terminateRemoteSamlSession();
|
||||
|
||||
expect(terminateRemoteSamlSessionSpy).toHaveBeenCalledWith(
|
||||
accessToken.samlSessionId
|
||||
);
|
||||
});
|
||||
|
||||
it(`should return undefined when remote SALM session doesn't exist`, async () => {
|
||||
const user = await createUser();
|
||||
const accessToken = await createAccessToken({ userId: user.id });
|
||||
await createIdentity({ userId: user.id });
|
||||
|
||||
const terminateRemoteSamlSessionSpy = vi
|
||||
.spyOn(SamlAuthProvider.prototype, 'terminateRemoteSession')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
const expected = await accessToken.terminateRemoteSamlSession();
|
||||
|
||||
expect(terminateRemoteSamlSessionSpy).not.toHaveBeenCalledOnce();
|
||||
expect(expected).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
13
packages/backend/test/factories/access-token.js
Normal file
13
packages/backend/test/factories/access-token.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import crypto from 'crypto';
|
||||
import AccessToken from '../../src/models/access-token.js';
|
||||
import { createUser } from './user.js';
|
||||
|
||||
export const createAccessToken = async (params = {}) => {
|
||||
params.userId = params.userId || (await createUser()).id;
|
||||
params.token = params.token || (await crypto.randomBytes(48).toString('hex'));
|
||||
params.expiresIn = params.expiresIn || 14 * 24 * 60 * 60; // 14 days in seconds
|
||||
|
||||
const accessToken = await AccessToken.query().insertAndFetch(params);
|
||||
|
||||
return accessToken;
|
||||
};
|
15
packages/backend/test/factories/identity.js
Normal file
15
packages/backend/test/factories/identity.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { faker } from '@faker-js/faker';
|
||||
import Identity from '../../src/models/identity.ee.js';
|
||||
import { createUser } from './user.js';
|
||||
import { createSamlAuthProvider } from './saml-auth-provider.ee.js';
|
||||
|
||||
export const createIdentity = async (params = {}) => {
|
||||
params.userId = params.userId || (await createUser()).id;
|
||||
params.remoteId = params.remoteId || faker.string.uuid();
|
||||
params.providerId = params.providerId || (await createSamlAuthProvider()).id;
|
||||
params.providerType = 'saml';
|
||||
|
||||
const identity = await Identity.query().insertAndFetch(params);
|
||||
|
||||
return identity;
|
||||
};
|
Reference in New Issue
Block a user