Compare commits

...
Author SHA1 Message Date
marcos-silva-rodrigues f3550255c4 FIX: validate if permission is public 2025-06-11 15:18:55 -03:00
5 changed files with 90 additions and 11 deletions
+9
View File
@@ -6022,6 +6022,9 @@
"ApiKey" "ApiKey"
], ],
"security": [ "security": [
{
"access-token": []
},
{ {
"access-token": [] "access-token": []
} }
@@ -6075,6 +6078,9 @@
"ApiKey" "ApiKey"
], ],
"security": [ "security": [
{
"access-token": []
},
{ {
"access-token": [] "access-token": []
} }
@@ -6115,6 +6121,9 @@
"ApiKey" "ApiKey"
], ],
"security": [ "security": [
{
"access-token": []
},
{ {
"access-token": [] "access-token": []
} }
+16
View File
@@ -603,6 +603,22 @@ export const PERMISSIONS_GROUPS = {
}, },
}, },
}; };
export const PUBLIC_PERMISSIONS_SEQID = [
46, // AUTH.GENERATE_TOKEN
23, 13, 29, 5, // PIPELINE
37, 38, // CONNECTION
35, // NETWORK_CONFIG
7, 19, 25, 1, // CATALOG
14, // SNOWFLAKE
11, // DATAVIZ
31, // INTELLIGENCE
34, // USERS
43, // PROCESS
47 // CUSTOMER
];
export interface DadosferaModule { export interface DadosferaModule {
name: string; name: string;
description: string; description: string;
+5 -1
View File
@@ -1,12 +1,13 @@
import { Controller, Get, Post, Body, Param, Delete, UseFilters, Inject } from '@nestjs/common'; import { Controller, Get, Post, Body, Param, Delete, UseFilters, Inject } from '@nestjs/common';
import { ApiKeyService } from './api-key.service'; import { ApiKeyService } from './api-key.service';
import { CreateApiKeyDto, CreateApiKeyResponseDto, ApiKeyBaseResponseDto } from './dto/api-key.dto'; import { CreateApiKeyDto, CreateApiKeyResponseDto, ApiKeyBaseResponseDto } from './dto/api-key.dto';
import { Authenticated } from 'src/decorators/authentication.decorator'; import { Authenticated, RequireAllPermissions } from 'src/decorators/authentication.decorator';
import { ApiHeaders, ApiTags, ApiResponse } from '@nestjs/swagger'; import { ApiHeaders, ApiTags, ApiResponse } from '@nestjs/swagger';
import { LanguageEnum } from 'src/utils/languages.enum'; import { LanguageEnum } from 'src/utils/languages.enum';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter'; import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { RequestUser, User } from 'src/decorators/user.decorator'; import { RequestUser, User } from 'src/decorators/user.decorator';
import { DadosferaLogger } from '@dadosfera/dadosfera-logs'; import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
@Controller('api-key') @Controller('api-key')
@Authenticated() @Authenticated()
@@ -26,6 +27,7 @@ export class ApiKeyController {
@Post() @Post()
@ApiResponse({ type: CreateApiKeyResponseDto }) @ApiResponse({ type: CreateApiKeyResponseDto })
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
async create(@Body() createApiKeyDto: CreateApiKeyDto, @User() user: RequestUser): Promise<CreateApiKeyResponseDto> { async create(@Body() createApiKeyDto: CreateApiKeyDto, @User() user: RequestUser): Promise<CreateApiKeyResponseDto> {
this.logger.info('POST /api-key', { this.logger.info('POST /api-key', {
permissions: createApiKeyDto.permissions, permissions: createApiKeyDto.permissions,
@@ -41,6 +43,7 @@ export class ApiKeyController {
@Get() @Get()
@ApiResponse({ type: [ApiKeyBaseResponseDto] }) @ApiResponse({ type: [ApiKeyBaseResponseDto] })
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
async findAll(@User() user: RequestUser): Promise<ApiKeyBaseResponseDto[]> { async findAll(@User() user: RequestUser): Promise<ApiKeyBaseResponseDto[]> {
this.logger.info('GET /api-key', { this.logger.info('GET /api-key', {
method: 'findAll' method: 'findAll'
@@ -54,6 +57,7 @@ export class ApiKeyController {
} }
@Delete(':id') @Delete(':id')
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
async remove(@Param('id') id: string, @User() user: RequestUser): Promise<void> { async remove(@Param('id') id: string, @User() user: RequestUser): Promise<void> {
this.logger.info('DELETE /api-key/:id', { this.logger.info('DELETE /api-key/:id', {
id, id,
+45 -10
View File
@@ -1,38 +1,73 @@
import { Injectable, Inject, OnModuleInit } from '@nestjs/common'; import {
Injectable,
Inject,
OnModuleInit,
BadRequestException,
} from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices'; import { ClientGrpc } from '@nestjs/microservices';
import { CreateApiKeyDto, CreateApiKeyResponseDto, ApiKeyBaseResponseDto } from './dto/api-key.dto'; import {
CreateApiKeyDto,
CreateApiKeyResponseDto,
ApiKeyBaseResponseDto,
} from './dto/api-key.dto';
import { RequestUser } from 'src/decorators/user.decorator'; import { RequestUser } from 'src/decorators/user.decorator';
import { DucClient } from '../duc/client.config'; import { DucClient } from '../duc/client.config';
import { PackTheMetadata } from '../../utils/ PackTheMetadata'; import { PackTheMetadata } from '../../utils/ PackTheMetadata';
import { ApiKeyWriteProtoService } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service'; import { ApiKeyWriteProtoService } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service';
import { lastValueFrom } from 'rxjs'; import { lastValueFrom } from 'rxjs';
import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc'; import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc';
import { PUBLIC_PERMISSIONS_SEQID } from 'src/authentication/permissions.enum';
@Injectable() @Injectable()
export class ApiKeyService implements OnModuleInit { export class ApiKeyService implements OnModuleInit {
private apiKeyService: ApiKeyWriteProtoService; private apiKeyService: ApiKeyWriteProtoService;
constructor( constructor(
@Inject(DucClient.name) private readonly client: ClientGrpc, @Inject(DucClient.name) private readonly client: ClientGrpc
) {} ) {}
onModuleInit() { onModuleInit() {
this.apiKeyService = this.client.getService<ApiKeyWriteProtoService>(ProtoServices.ApiKeyWriteProtoService); this.apiKeyService = this.client.getService<ApiKeyWriteProtoService>(
ProtoServices.ApiKeyWriteProtoService,
);
} }
create(createApiKeyDto: CreateApiKeyDto, user: RequestUser): Promise<CreateApiKeyResponseDto> { create(
createApiKeyDto: CreateApiKeyDto,
user: RequestUser,
): Promise<CreateApiKeyResponseDto> {
const metadata = PackTheMetadata(user); const metadata = PackTheMetadata(user);
return lastValueFrom(this.apiKeyService.CreateApiKey({ const invalidPermissions = [];
permissions: createApiKeyDto.permissions for (const permission of createApiKeyDto.permissions) {
}, metadata)); if (!PUBLIC_PERMISSIONS_SEQID.includes(permission)) {
invalidPermissions.push(permission);
}
}
if (invalidPermissions.length > 0) {
throw new BadRequestException(
`Invalid permissions: ${invalidPermissions.join(', ')}`,
);
}
return lastValueFrom(
this.apiKeyService.CreateApiKey(
{
permissions: createApiKeyDto.permissions,
},
metadata,
),
);
} }
async findAll(user: RequestUser): Promise<ApiKeyBaseResponseDto[]> { async findAll(user: RequestUser): Promise<ApiKeyBaseResponseDto[]> {
const metadata = PackTheMetadata(user); const metadata = PackTheMetadata(user);
console.log(metadata) console.log(metadata);
const data = await lastValueFrom(this.apiKeyService.ListApiKeys({}, metadata)); const data = await lastValueFrom(
this.apiKeyService.ListApiKeys({}, metadata),
);
return data.api_keys; return data.api_keys;
} }
+15
View File
@@ -20,6 +20,7 @@ import { PermissionsService } from '../permissions/permissions.service';
import { LanguageEnum } from 'src/utils/languages.enum'; import { LanguageEnum } from 'src/utils/languages.enum';
import { RequestUser } from 'src/decorators/user.decorator'; import { RequestUser } from 'src/decorators/user.decorator';
import { DucClient } from '../duc/client.config'; import { DucClient } from '../duc/client.config';
import { PUBLIC_PERMISSIONS_SEQID } from 'src/authentication/permissions.enum';
interface GetRolesPermissionsName { interface GetRolesPermissionsName {
id: string; id: string;
@@ -103,6 +104,20 @@ export class RolesService {
const meta = new Metadata(); const meta = new Metadata();
meta.add('access_token', access_token); meta.add('access_token', access_token);
const { description, name, permissionIds, userIds } = data; const { description, name, permissionIds, userIds } = data;
const invalidPermissions = [];
for (const permission of permissionIds) {
if (!PUBLIC_PERMISSIONS_SEQID.includes(permission)) {
invalidPermissions.push(permission);
}
}
if (invalidPermissions.length > 0) {
throw new BadRequestException(
`Invalid permissions: ${invalidPermissions.join(', ')}`,
);
}
const role = await lastValueFrom( const role = await lastValueFrom(
this.rolesClientService.RoleCreate( this.rolesClientService.RoleCreate(
{ {