external-token.test.ts•13.1 kB
import { apId, DefaultProjectRole, PiecesFilterType, PieceType, ProjectRole } from '@activepieces/shared'
import { faker } from '@faker-js/faker'
import { FastifyBaseLogger, FastifyInstance } from 'fastify'
import { StatusCodes } from 'http-status-codes'
import { initializeDatabase } from '../../../../src/app/database'
import { databaseConnection } from '../../../../src/app/database/database-connection'
import { stripeHelper } from '../../../../src/app/ee/platform/platform-plan/stripe-helper'
import { setupServer } from '../../../../src/app/server'
import { generateMockExternalToken } from '../../../helpers/auth'
import {
createMockPieceMetadata,
createMockPieceTag,
createMockProject,
createMockSigningKey,
createMockTag,
mockAndSaveBasicSetup,
mockBasicUser,
} from '../../../helpers/mocks'
let app: FastifyInstance | null = null
let mockLog: FastifyBaseLogger
beforeAll(async () => {
await initializeDatabase({ runMigrations: false })
app = await setupServer()
mockLog = app!.log!
})
beforeEach(async () => {
stripeHelper(mockLog).createCustomer = jest
.fn()
.mockResolvedValue(faker.string.alphanumeric())
})
afterAll(async () => {
await databaseConnection().destroy()
await app?.close()
})
describe('Managed Authentication API', () => {
describe('External token endpoint', () => {
it('Signs up new users', async () => {
// arrange
const { mockPlatform } = await mockAndSaveBasicSetup()
const mockSigningKey = createMockSigningKey({
platformId: mockPlatform.id,
})
await databaseConnection()
.getRepository('signing_key')
.save(mockSigningKey)
const { mockExternalToken, mockExternalTokenPayload } = generateMockExternalToken({
platformId: mockPlatform.id,
signingKeyId: mockSigningKey.id,
})
// act
const response = await app?.inject({
method: 'POST',
url: '/v1/managed-authn/external-token',
body: {
externalAccessToken: mockExternalToken,
},
})
// assert
const responseBody = response?.json()
expect(response?.statusCode).toBe(StatusCodes.OK)
expect(responseBody?.id).toHaveLength(21)
expect(responseBody?.firstName).toBe(mockExternalTokenPayload.firstName)
expect(responseBody?.lastName).toBe(mockExternalTokenPayload.lastName)
expect(responseBody?.trackEvents).toBe(true)
expect(responseBody?.newsLetter).toBe(false)
expect(responseBody?.password).toBeUndefined()
expect(responseBody?.status).toBe('ACTIVE')
expect(responseBody?.verified).toBe(true)
expect(responseBody?.externalId).toBe(
mockExternalTokenPayload.externalUserId,
)
expect(responseBody?.platformId).toBe(mockPlatform.id)
expect(responseBody?.projectId).toHaveLength(21)
expect(responseBody?.token).toBeDefined()
})
it('Creates new project', async () => {
// arrange
const { mockPlatform } = await mockAndSaveBasicSetup()
const mockSigningKey = createMockSigningKey({
platformId: mockPlatform.id,
})
await databaseConnection()
.getRepository('signing_key')
.save(mockSigningKey)
const { mockExternalToken, mockExternalTokenPayload } =
generateMockExternalToken({
platformId: mockPlatform.id,
signingKeyId: mockSigningKey.id,
})
// act
const response = await app?.inject({
method: 'POST',
url: '/v1/managed-authn/external-token',
body: {
externalAccessToken: mockExternalToken,
},
})
// assert
const responseBody = response?.json()
expect(response?.statusCode).toBe(StatusCodes.OK)
const generatedProject = await databaseConnection()
.getRepository('project')
.findOneBy({
id: responseBody?.projectId,
})
expect(generatedProject?.displayName).toBe(
mockExternalTokenPayload.externalProjectId,
)
expect(generatedProject?.ownerId).toBe(mockPlatform.ownerId)
expect(generatedProject?.platformId).toBe(mockPlatform.id)
expect(generatedProject?.externalId).toBe(
mockExternalTokenPayload.externalProjectId,
)
})
it('Sync Pieces when exchanging external token', async () => {
// arrange
const { mockPlatform } = await mockAndSaveBasicSetup()
const mockPieceMetadata1 = createMockPieceMetadata({
name: '@ap/a',
version: '0.0.1',
pieceType: PieceType.OFFICIAL,
})
await databaseConnection()
.getRepository('piece_metadata')
.save(mockPieceMetadata1)
const mockTag = createMockTag({
id: apId(),
platformId: mockPlatform.id,
name: 'free',
})
await databaseConnection()
.getRepository('tag')
.save(mockTag)
const mockPieceTag = createMockPieceTag({
platformId: mockPlatform.id,
tagId: mockTag.id,
pieceName: '@ap/a',
})
await databaseConnection()
.getRepository('piece_tag')
.save(mockPieceTag)
const mockSigningKey = createMockSigningKey({
platformId: mockPlatform.id,
})
await databaseConnection()
.getRepository('signing_key')
.save(mockSigningKey)
const { mockExternalToken } = generateMockExternalToken({
platformId: mockPlatform.id,
signingKeyId: mockSigningKey.id,
pieces: {
filterType: PiecesFilterType.ALLOWED,
tags: ['free'],
},
})
// act
const response = await app?.inject({
method: 'POST',
url: '/v1/managed-authn/external-token',
body: {
externalAccessToken: mockExternalToken,
},
})
// assert
const responseBody = response?.json()
expect(response?.statusCode).toBe(StatusCodes.OK)
const generatedProject = await databaseConnection()
.getRepository('project_plan')
.findOneBy({ projectId: responseBody?.projectId })
expect(generatedProject?.piecesFilterType).toBe('ALLOWED')
expect(generatedProject?.pieces).toStrictEqual(['@ap/a'])
})
it('Adds new user as a member in new project', async () => {
// arrange
const { mockPlatform } = await mockAndSaveBasicSetup()
const mockSigningKey = createMockSigningKey({
platformId: mockPlatform.id,
})
await databaseConnection()
.getRepository('signing_key')
.save(mockSigningKey)
const projectRole = await databaseConnection().getRepository('project_role').findOneByOrFail({ name: DefaultProjectRole.VIEWER }) as ProjectRole
const { mockExternalToken } = generateMockExternalToken({
platformId: mockPlatform.id,
signingKeyId: mockSigningKey.id,
projectRole: projectRole.name,
})
// act
const response = await app?.inject({
method: 'POST',
url: '/v1/managed-authn/external-token',
body: {
externalAccessToken: mockExternalToken,
},
})
// assert
const responseBody = response?.json()
expect(response?.statusCode).toBe(StatusCodes.OK)
const generatedProjectMember = await databaseConnection()
.getRepository('project_member')
.findOneBy({
projectId: responseBody?.projectId,
userId: responseBody?.id,
})
expect(generatedProjectMember?.projectId).toBe(responseBody?.projectId)
expect(generatedProjectMember?.userId).toBe(responseBody?.id)
expect(generatedProjectMember?.platformId).toBe(mockPlatform.id)
expect(generatedProjectMember?.projectRoleId).toBe(projectRole.id)
})
it('Adds new user to existing project', async () => {
// arrange
const { mockOwner, mockPlatform } = await mockAndSaveBasicSetup()
const mockSigningKey = createMockSigningKey({
platformId: mockPlatform.id,
})
await databaseConnection()
.getRepository('signing_key')
.save(mockSigningKey)
const mockExternalProjectId = apId()
const mockProject = createMockProject({
ownerId: mockOwner.id,
platformId: mockPlatform.id,
externalId: mockExternalProjectId,
})
await databaseConnection().getRepository('project').save(mockProject)
const { mockExternalToken } = generateMockExternalToken({
platformId: mockPlatform.id,
signingKeyId: mockSigningKey.id,
externalProjectId: mockExternalProjectId,
})
// act
const response = await app?.inject({
method: 'POST',
url: '/v1/managed-authn/external-token',
body: {
externalAccessToken: mockExternalToken,
},
})
// assert
const responseBody = response?.json()
expect(response?.statusCode).toBe(StatusCodes.OK)
expect(responseBody?.projectId).toBe(mockProject.id)
})
it('Signs in existing users', async () => {
// arrange
const { mockOwner, mockPlatform } = await mockAndSaveBasicSetup()
const mockSigningKey = createMockSigningKey({
platformId: mockPlatform.id,
})
await databaseConnection()
.getRepository('signing_key')
.save(mockSigningKey)
const { mockExternalToken, mockExternalTokenPayload } = generateMockExternalToken({
platformId: mockPlatform.id,
signingKeyId: mockSigningKey.id,
})
const { mockUser } = await mockBasicUser({
user: {
externalId: mockExternalTokenPayload.externalUserId,
platformId: mockPlatform.id,
},
})
const mockProject = createMockProject({
ownerId: mockOwner.id,
platformId: mockPlatform.id,
externalId: mockExternalTokenPayload.externalProjectId,
})
await databaseConnection().getRepository('project').save(mockProject)
// act
const response = await app?.inject({
method: 'POST',
url: '/v1/managed-authn/external-token',
body: {
externalAccessToken: mockExternalToken,
},
})
// assert
const responseBody = response?.json()
expect(response?.statusCode).toBe(StatusCodes.OK)
expect(responseBody?.projectId).toBe(mockProject.id)
expect(responseBody?.id).toBe(mockUser.id)
})
it('Fails if signing key is not found', async () => {
// arrange
await mockAndSaveBasicSetup()
const nonExistentSigningKeyId = apId()
const { mockExternalToken } = generateMockExternalToken({
signingKeyId: nonExistentSigningKeyId,
})
// act
const response = await app?.inject({
method: 'POST',
url: '/v1/managed-authn/external-token',
body: {
externalAccessToken: mockExternalToken,
},
})
// assert
const responseBody = response?.json()
expect(response?.statusCode).toBe(StatusCodes.UNAUTHORIZED)
expect(responseBody?.params?.message).toBe(
`signing key not found signingKeyId=${nonExistentSigningKeyId}`,
)
})
})
})