FIX: add authentication to swagger

This commit is contained in:
Gabriel Rosa
2023-02-08 15:23:49 -03:00
parent cdba41dffa
commit 8043635b1c
9 changed files with 621 additions and 45 deletions
+593 -23
View File
File diff suppressed because it is too large Load Diff
+15 -7
View File
@@ -1,7 +1,8 @@
import { Request } from 'express';
import { CustomDecorator } from '@nestjs/common';
import { applyDecorators, CustomDecorator } from '@nestjs/common';
import { PermissionsObjectPermission } from './permissions.enum';
import { RequestUser } from './user.decorator';
import { ApiSecurity } from '@nestjs/swagger';
export const AUTH_FUNCTION_KEY = '__AUTH_FUNCTION__';
@@ -10,7 +11,7 @@ export type AuthenticationFunction = (req: Request, user: any) => boolean;
// implementation copied from SetMetadata, but tweaked to get existing values
// of the metadataKey and accumulate it with the new metadataValue
function SetMultipleMetadata(metadataKey, metadataValue): CustomDecorator {
const decoratorFactory = (target, key, descriptor) => {
const decoratorFactory: CustomDecorator = (target, key?, descriptor?) => {
// .start: tweak
// descriptor?.value = function decorator; target = class decorator
const accumulatedVal =
@@ -28,13 +29,20 @@ function SetMultipleMetadata(metadataKey, metadataValue): CustomDecorator {
};
decoratorFactory.KEY = metadataKey;
return decoratorFactory as any;
return decoratorFactory;
}
function createAuthenticatedDecorator(metadataValue: AuthenticationFunction) {
return applyDecorators(
ApiSecurity('access-token'),
SetMultipleMetadata(AUTH_FUNCTION_KEY, metadataValue),
);
}
export function RequireAllPermissions(
...permissions: PermissionsObjectPermission[]
) {
return SetMultipleMetadata(AUTH_FUNCTION_KEY, (req, user: RequestUser) =>
return createAuthenticatedDecorator((req, user: RequestUser) =>
permissions.every(({ seqid }) => user.permissions.includes(seqid)),
);
}
@@ -42,15 +50,15 @@ export function RequireAllPermissions(
export function RequireSomePermission(
...permissions: PermissionsObjectPermission[]
) {
return SetMultipleMetadata(AUTH_FUNCTION_KEY, (req, user: RequestUser) =>
return createAuthenticatedDecorator((req, user: RequestUser) =>
permissions.some(({ seqid }) => user.permissions.includes(seqid)),
);
}
export function AuthenticateCondition(func: AuthenticationFunction) {
return SetMultipleMetadata(AUTH_FUNCTION_KEY, func);
return createAuthenticatedDecorator(func);
}
export function Authenticated() {
return SetMultipleMetadata(AUTH_FUNCTION_KEY, () => true);
return createAuthenticatedDecorator(() => true);
}
+2 -5
View File
@@ -54,14 +54,11 @@ export class AuthenticationGuard
>(AUTH_FUNCTION_KEY, [ctx.getClass(), ctx.getHandler()]);
const mustBeAuthenticated = authFunctions.length > 0;
if (!mustBeAuthenticated) return true;
const request = ctx.switchToHttp().getRequest();
const accessToken = this.validateToken(request, mustBeAuthenticated);
if (!mustBeAuthenticated) {
// no need to be authenticated
return true;
}
if (!accessToken) {
// couldn't load valid token
throw new ErrorBuilder(ErrorCodes.AUTH.UNAUTHORIZED);
+5 -4
View File
@@ -46,10 +46,11 @@ function configureSwagger(app: INestApplication) {
const config = new DocumentBuilder()
.setTitle(swaggerTitle)
.setDescription('Documentation for Maestro gateway')
.addBearerAuth(
{ type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
'Authorization',
)
.addSecurity('access-token', {
type: 'apiKey',
name: 'Authorization',
in: 'header',
})
.build();
const document = SwaggerModule.createDocument(app, config);
+2 -1
View File
@@ -9,7 +9,7 @@ import {
UseFilters,
Get,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { ApiSecurity, ApiTags } from '@nestjs/swagger';
import {
AuthChangePasswordRequest,
AuthResetPasswordRequest,
@@ -203,6 +203,7 @@ export class AuthController {
}
@Authenticated()
@ApiSecurity('access-token')
@Get('verify-access-token')
@HttpCode(HttpStatus.OK)
verifyAccessToken() {
@@ -6,7 +6,6 @@ import {
ForbiddenException,
Get,
Headers,
HttpException,
Inject,
NotFoundException,
Param,
@@ -11,7 +11,7 @@ import {
Query,
UseFilters,
} from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { ApiTags } from '@nestjs/swagger';
import { ConnectionClientService } from './client.service';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import {
@@ -34,7 +34,6 @@ import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filt
const connectionPermissions = PERMISSIONS_GROUPS.CONNECTION.permissions;
@UseFilters(new GrpcToHttpExceptionFilter())
@ApiTags('connections')
@ApiBearerAuth()
@Authenticated()
@Controller('connections')
export class ConnectionController {
@@ -15,7 +15,7 @@ import {
UploadedFiles,
} from '@nestjs/common';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiConsumes, ApiTags } from '@nestjs/swagger';
import { ApiConsumes, ApiTags } from '@nestjs/swagger';
import { ConnectorClientService } from './client.service';
import { AddTagDto } from './dtos/add-tag';
import { CreateConnectorDto } from './dtos/create-connector';
@@ -31,7 +31,6 @@ import {
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
@ApiTags('connectors')
@ApiBearerAuth()
@Authenticated()
@Controller('connectors')
export class ConnectorController {
@@ -1,12 +1,14 @@
import { Body, Controller, HttpException, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import axios from 'axios';
import { Authenticated } from 'src/authentication/authentication.decorator';
import { User, RequestUser } from 'src/authentication/user.decorator';
import { getSecretFromSecretsManager } from 'src/utils/SecretManager';
import { INote } from './dtos';
@ApiTags('Productboard')
@Controller('productboard')
@Authenticated()
export class ProductboardController {
@Post('notes')
async sendNote(@Body() note: INote, @User() user: RequestUser) {