From 9d9bf1c88d72f6af90bfe1a46170d912a0afca0e Mon Sep 17 00:00:00 2001 From: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com> Date: Sat, 5 Oct 2024 18:16:23 +0200 Subject: [PATCH] chore: auth unit tests (#13207) --- server/src/services/auth.service.spec.ts | 54 +++++++++++++++++++++++- server/src/services/auth.service.ts | 4 -- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/server/src/services/auth.service.spec.ts b/server/src/services/auth.service.spec.ts index 6ab256db7b552..9f81e03171154 100644 --- a/server/src/services/auth.service.spec.ts +++ b/server/src/services/auth.service.spec.ts @@ -3,7 +3,7 @@ import { Issuer, generators } from 'openid-client'; import { AuthDto, SignUpDto } from 'src/dtos/auth.dto'; import { UserMetadataEntity } from 'src/entities/user-metadata.entity'; import { UserEntity } from 'src/entities/user.entity'; -import { AuthType } from 'src/enum'; +import { AuthType, Permission } from 'src/enum'; import { IKeyRepository } from 'src/interfaces/api-key.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IEventRepository } from 'src/interfaces/event.interface'; @@ -288,6 +288,17 @@ describe('AuthService', () => { ).rejects.toBeInstanceOf(UnauthorizedException); }); + it('should not accept a key on a non-shared route', async () => { + sharedLinkMock.getByKey.mockResolvedValue(sharedLinkStub.valid); + await expect( + sut.authenticate({ + headers: { 'x-immich-share-key': 'key' }, + queryParams: {}, + metadata: { adminRoute: false, sharedLinkRoute: false, uri: 'test' }, + }), + ).rejects.toBeInstanceOf(ForbiddenException); + }); + it('should not accept a key without a user', async () => { sharedLinkMock.getByKey.mockResolvedValue(sharedLinkStub.expired); userMock.get.mockResolvedValue(null); @@ -397,6 +408,17 @@ describe('AuthService', () => { expect(keyMock.getKey).toHaveBeenCalledWith('auth_token (hashed)'); }); + it('should throw an error if api key has insufficient permissions', async () => { + keyMock.getKey.mockResolvedValue({ ...keyStub.admin, permissions: [] }); + await expect( + sut.authenticate({ + headers: { 'x-api-key': 'auth_token' }, + queryParams: {}, + metadata: { adminRoute: false, sharedLinkRoute: false, uri: 'test', permission: Permission.ASSET_READ }, + }), + ).rejects.toBeInstanceOf(ForbiddenException); + }); + it('should return an auth dto', async () => { keyMock.getKey.mockResolvedValue(keyStub.admin); await expect( @@ -422,6 +444,20 @@ describe('AuthService', () => { }); }); + describe('authorize', () => { + it('should fail if oauth is disabled', async () => { + systemMock.get.mockResolvedValue({ oauth: { enabled: false } }); + await expect(sut.authorize({ redirectUri: 'https://demo.immich.app' })).rejects.toBeInstanceOf( + BadRequestException, + ); + }); + + it('should authorize the user', async () => { + systemMock.get.mockResolvedValue(systemConfigStub.oauthWithMobileOverride); + await sut.authorize({ redirectUri: 'https://demo.immich.app' }); + }); + }); + describe('callback', () => { it('should throw an error if OAuth is not enabled', async () => { await expect(sut.callback({ url: '' }, loginDetails)).rejects.toBeInstanceOf(BadRequestException); @@ -479,6 +515,22 @@ describe('AuthService', () => { expect(userMock.create).toHaveBeenCalledTimes(1); }); + // TODO write once oidc has been moved to a repo and can be mocked. + // it('should throw an error if user should be auto registered but the email claim does not exist', async () => { + // systemMock.get.mockResolvedValue(systemConfigStub.enabled); + // userMock.getByEmail.mockResolvedValue(null); + // userMock.getAdmin.mockResolvedValue(userStub.user1); + // userMock.create.mockResolvedValue(userStub.user1); + // sessionMock.create.mockResolvedValue(sessionStub.valid); + + // await expect(sut.callback({ url: 'http://immich/auth/login?code=abc123' }, loginDetails)).rejects.toBeInstanceOf( + // BadRequestException, + // ); + + // expect(userMock.getByEmail).toHaveBeenCalledTimes(1); + // expect(userMock.create).toHaveBeenCalledTimes(1); + // }); + for (const url of [ 'app.immich:/', 'app.immich://', diff --git a/server/src/services/auth.service.ts b/server/src/services/auth.service.ts index ba1d599885a10..d16c7af09a37c 100644 --- a/server/src/services/auth.service.ts +++ b/server/src/services/auth.service.ts @@ -192,10 +192,6 @@ export class AuthService extends BaseService { async authorize(dto: OAuthConfigDto): Promise { const config = await this.getConfig({ withCache: false }); - if (!config.oauth.enabled) { - throw new BadRequestException('OAuth is not enabled'); - } - const client = await this.getOAuthClient(config); const url = client.authorizationUrl({ redirect_uri: this.normalize(config, dto.redirectUri),