Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BC-6522 - Move auth guards and decorator to seperate module #5175

Merged
merged 42 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
5194c2d
Move guards and decorator to auth guard module
bischofmax Aug 8, 2024
ccf6543
Merge branch 'main' into BC-6522
bischofmax Aug 8, 2024
ea6964f
Fix imports
bischofmax Aug 9, 2024
cd42ab5
Adjust tests
bischofmax Aug 12, 2024
a689c54
Merge branch 'main' into BC-6522
bischofmax Aug 12, 2024
5fafc32
Add authguardmodule to tldrawmodule
bischofmax Aug 12, 2024
bcea2ad
Refactor auth config mapper
bischofmax Aug 14, 2024
2f21c63
Add JwtValidationAdapter test to JwtWhitelistAdapter test
bischofmax Aug 14, 2024
ce00945
Use enum for strategy string
bischofmax Aug 14, 2024
b95c198
Add private method for login
bischofmax Aug 14, 2024
68211f3
Fix imports
bischofmax Aug 14, 2024
f753d41
Remove authenticationmodule from other modules
bischofmax Aug 14, 2024
bb8f5f4
Merge branch 'main' into BC-6522
bischofmax Aug 14, 2024
560f082
Fix strategy tests
bischofmax Aug 14, 2024
0df46c4
Add AuthGuardModule to self deployed modules
bischofmax Aug 15, 2024
8771877
Add AuthGuardModule to AdminApiServerTestModule
bischofmax Aug 15, 2024
5a70712
Fix test description for auth decorator
bischofmax Aug 15, 2024
3a91669
Fix jwt auth decorator comments
bischofmax Aug 15, 2024
f0fdcc8
Move comment in auth guard index file
bischofmax Aug 15, 2024
8736753
Merge imports
bischofmax Aug 15, 2024
79e3394
Merge imports
bischofmax Aug 15, 2024
49f633e
Merge imports
bischofmax Aug 15, 2024
99768de
Remove comment in tldraw api modul
bischofmax Aug 16, 2024
305be91
Fix import in user login migration module
bischofmax Aug 16, 2024
9a08a06
Merge imports
bischofmax Aug 16, 2024
f4b1fdc
Merge imports
bischofmax Aug 16, 2024
af3e515
Fix imports and descriptrions
bischofmax Aug 16, 2024
fc651d7
Fix basefactory imports
bischofmax Aug 16, 2024
5fbdacd
Renaming and import fix
bischofmax Aug 16, 2024
f95dfcb
Merge branch 'main' into BC-6522
bischofmax Aug 16, 2024
b5757f1
Move private method login in file
bischofmax Aug 19, 2024
6d9ecd6
Remove auth guard module from common cartridge modul
bischofmax Aug 19, 2024
fef259e
Use ApiKeyGuard
bischofmax Aug 19, 2024
706ab70
Use AuthGuardModule in single place
bischofmax Aug 19, 2024
7544266
Merge branch 'main' into BC-6522
bischofmax Aug 19, 2024
72f91da
Merge branch 'BC-6522' of github.com:hpi-schul-cloud/schulcloud-serve…
bischofmax Aug 19, 2024
91bb7fd
use apikeyguard for override
bischofmax Aug 19, 2024
716fe99
Override apikeyguard
bischofmax Aug 19, 2024
477492b
Merge branch 'main' into BC-6522
bischofmax Aug 20, 2024
d5768bb
Merge branch 'main' into BC-6522
bischofmax Aug 20, 2024
ff15911
Merge branch 'main' into BC-6522
bischofmax Aug 20, 2024
d7791ee
Merge branch 'main' into BC-6522
bischofmax Aug 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/server/src/imports-from-feathers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable import/extensions */
export { BruteForcePrevention } from '../../../src/errors/index.js';
export { authConfig } from '../../../src/services/authentication/configuration';
export {
addTokenToWhitelist,
createRedisIdentifierFromJwtData,
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/infra/auth-guard/adapter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { JwtValidationAdapter } from './jwt-validation.adapter';
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// isWhitelisted method is currently tested in authentication modul JwtWhitelistAdapter. Test should be moved here after feathers migration and adding of redis adapter in nest
it('just to have one test', () => {});
15 changes: 15 additions & 0 deletions apps/server/src/infra/auth-guard/adapter/jwt-validation.adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Injectable } from '@nestjs/common';
import { ensureTokenIsWhitelisted } from '@src/imports-from-feathers';

@Injectable()
export class JwtValidationAdapter {
/**
* When validating a jwt it must be added to a whitelist, here we check this.
* When the jwt is validated, the expiration time will be extended with this call.
* @param accountId users account id
* @param jti jwt id (here required to make jwt identifiers identical in redis)
*/
async isWhitelisted(accountId: string, jti: string): Promise<void> {
await ensureTokenIsWhitelisted({ accountId, jti, privateDevice: false });
}
}
11 changes: 11 additions & 0 deletions apps/server/src/infra/auth-guard/auth-guard.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtValidationAdapter } from './adapter';
import { JwtStrategy, WsJwtStrategy, XApiKeyStrategy } from './strategy';

@Module({
imports: [PassportModule],
providers: [JwtStrategy, WsJwtStrategy, JwtValidationAdapter, XApiKeyStrategy],
exports: [JwtValidationAdapter],
})
export class AuthGuardModule {}
4 changes: 4 additions & 0 deletions apps/server/src/infra/auth-guard/config/auth-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { authConfig as feathersAuthConfig } from '@src/imports-from-feathers';
import { AuthConfigMapper } from '../mapper';

export const authConfig = AuthConfigMapper.mapFeathersAuthConfigToAuthConfig(feathersAuthConfig);
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './auth-config';
export * from './x-api-key.config';
1 change: 1 addition & 0 deletions apps/server/src/infra/auth-guard/decorator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './jwt-auth.decorator';
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { ICurrentUser } from '@modules/authentication';
import { ServerTestModule } from '@modules/server/server.module';
import { Controller, ExecutionContext, ForbiddenException, Get, INestApplication } from '@nestjs/common';
import { Controller, ExecutionContext, Get, INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import request from 'supertest';
import { JwtAuthGuard } from '../guard/jwt-auth.guard';
import { Authenticate, CurrentUser, JWT } from './auth.decorator';
import { JwtAuthGuard } from '../guard';
import { ICurrentUser } from '../interface';
import { CurrentUser, JWT, JwtAuthentication } from './jwt-auth.decorator';

@Authenticate('jwt')
@JwtAuthentication()
@Controller('test_decorator_currentUser')
export class TestDecoratorCurrentUserController {
@Get('test')
Expand All @@ -16,7 +16,7 @@ export class TestDecoratorCurrentUserController {
}
}

@Authenticate('jwt')
@JwtAuthentication()
@Controller('test_decorator_JWT')
export class TestDecoratorJWTController {
@Get('test')
Expand All @@ -25,7 +25,7 @@ export class TestDecoratorJWTController {
}
}

describe('auth.decorator', () => {
describe('Jwt auth decorator', () => {
let app: INestApplication;
let currentUser: ICurrentUser;
let module: TestingModule;
Expand Down Expand Up @@ -59,7 +59,7 @@ describe('auth.decorator', () => {
await module.close();
});

describe('JWT', () => {
describe('JwtAuthentication', () => {
it('should throw with UnauthorizedException if no jwt can be extracted from request context', async () => {
const response = await request(app.getHttpServer()).get('/test_decorator_JWT/test');

Expand All @@ -86,12 +86,4 @@ describe('auth.decorator', () => {
expect(response.statusCode).toEqual(401);
});
});

describe('Authenticate', () => {
it('should throw with UnauthorizedException if no jwt user data can be extracted from request context', () => {
// @ts-expect-error Testcase
const exec = () => Authenticate('bla');
expect(exec).toThrowError(new ForbiddenException('jwt strategy required'));
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,27 @@ import {
applyDecorators,
createParamDecorator,
ExecutionContext,
ForbiddenException,
UnauthorizedException,
UseGuards,
} from '@nestjs/common';
import { ApiBearerAuth } from '@nestjs/swagger';
import { Request } from 'express';
import { extractJwtFromHeader } from '@shared/common';
import { JwtAuthGuard } from '../guard/jwt-auth.guard';
import { ICurrentUser, isICurrentUser } from '../interface/user';

const STRATEGIES = ['jwt'] as const;
type Strategies = typeof STRATEGIES;
import { Request } from 'express';
import { JwtAuthGuard } from '../guard';
import { ICurrentUser, isICurrentUser } from '../interface';

/**
* Authentication Decorator taking care of require authentication header to be present, setting up the user context and extending openAPI spec.
* @param strategies accepted strategies
* @returns
*/
export const Authenticate = (...strategies: Strategies) => {
if (strategies.includes('jwt')) {
const decorators = [
// apply jwt authentication
UseGuards(JwtAuthGuard),
// add jwt authentication to openapi spec
ApiBearerAuth(),
];
return applyDecorators(...decorators);
}
throw new ForbiddenException('jwt strategy required');
export const JwtAuthentication = () => {
const decorators = [
// apply jwt authentication
UseGuards(JwtAuthGuard),
// add jwt authentication to openapi spec
ApiBearerAuth(),
];

return applyDecorators(...decorators);
};

/**
Expand Down
3 changes: 3 additions & 0 deletions apps/server/src/infra/auth-guard/guard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './jwt-auth.guard';
export * from './ws-jwt-auth.guard';
export * from './x-api-key-auth.guard';
6 changes: 6 additions & 0 deletions apps/server/src/infra/auth-guard/guard/jwt-auth.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { StrategyType } from '../interface';

@Injectable()
export class JwtAuthGuard extends AuthGuard(StrategyType.JWT) {}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { StrategyType } from '../interface';

export class WsJwtAuthGuard extends AuthGuard('wsjwt') {
export class WsJwtAuthGuard extends AuthGuard(StrategyType.WS_JWT) {
getRequest(context: ExecutionContext) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
return context.switchToWs().getClient().handshake;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { StrategyType } from '../interface';

@Injectable()
export class ApiKeyGuard extends AuthGuard(StrategyType.API_KEY) {}
9 changes: 9 additions & 0 deletions apps/server/src/infra/auth-guard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export { JwtValidationAdapter } from './adapter';
export { AuthGuardModule } from './auth-guard.module';
export { XApiKeyConfig, authConfig } from './config';
export { CurrentUser, JWT, JwtAuthentication } from './decorator';
// JwtAuthGuard only exported because api tests still overried this guard.
// Use JwtAuthentication decorator for request validation
export { ApiKeyGuard, JwtAuthGuard, WsJwtAuthGuard } from './guard';
export { CreateJwtPayload, ICurrentUser, JwtPayload, StrategyType } from './interface';
export { CurrentUserMapper } from './mapper';
3 changes: 3 additions & 0 deletions apps/server/src/infra/auth-guard/interface/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './jwt-payload';
export * from './strategy-type';
export * from './user';
5 changes: 5 additions & 0 deletions apps/server/src/infra/auth-guard/interface/strategy-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum StrategyType {
JWT = 'jwt',
WS_JWT = 'wsjwt',
API_KEY = 'api-key',
}
Loading
Loading