feat: RBAC (#8922)

Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
Co-authored-by: Val <68596159+valya@users.noreply.github.com>
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
Co-authored-by: Valya Bullions <valya@n8n.io>
Co-authored-by: Danny Martini <danny@n8n.io>
Co-authored-by: Danny Martini <despair.blue@gmail.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
Co-authored-by: oleg <me@olegivaniv.com>
Co-authored-by: Michael Kret <michael.k@radency.com>
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
Co-authored-by: Elias Meire <elias@meire.dev>
Co-authored-by: Giulio Andreini <andreini@netseven.it>
Co-authored-by: Giulio Andreini <g.andreini@gmail.com>
Co-authored-by: Ayato Hayashi <go12limchangyong@gmail.com>
This commit is contained in:
Csaba Tuncsik
2024-05-17 10:53:15 +02:00
committed by GitHub
parent b1f977ebd0
commit 596c472ecc
292 changed files with 14129 additions and 3989 deletions

View File

@@ -30,15 +30,15 @@ import { ICredentialsHelper, NodeHelpers, Workflow, ApplicationError } from 'n8n
import type { ICredentialsDb } from '@/Interfaces';
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
import { NodeTypes } from '@/NodeTypes';
import { CredentialTypes } from '@/CredentialTypes';
import { CredentialsOverwrites } from '@/CredentialsOverwrites';
import { RESPONSE_ERROR_MESSAGES } from './constants';
import { Logger } from '@/Logger';
import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import { CredentialNotFoundError } from './errors/credential-not-found.error';
import { In } from '@n8n/typeorm';
import { CacheService } from './services/cache/cache.service';
const mockNode = {
name: '',
@@ -77,12 +77,11 @@ const mockNodeTypes: INodeTypes = {
@Service()
export class CredentialsHelper extends ICredentialsHelper {
constructor(
private readonly logger: Logger,
private readonly credentialTypes: CredentialTypes,
private readonly nodeTypes: NodeTypes,
private readonly credentialsOverwrites: CredentialsOverwrites,
private readonly credentialsRepository: CredentialsRepository,
private readonly sharedCredentialsRepository: SharedCredentialsRepository,
private readonly cacheService: CacheService,
) {
super();
}
@@ -245,7 +244,6 @@ export class CredentialsHelper extends ICredentialsHelper {
async getCredentials(
nodeCredential: INodeCredentialsDetails,
type: string,
userId?: string,
): Promise<Credentials> {
if (!nodeCredential.id) {
throw new ApplicationError('Found credential with no ID.', {
@@ -257,14 +255,10 @@ export class CredentialsHelper extends ICredentialsHelper {
let credential: CredentialsEntity;
try {
credential = userId
? await this.sharedCredentialsRepository
.findOneOrFail({
relations: ['credentials'],
where: { credentials: { id: nodeCredential.id, type }, userId },
})
.then((shared) => shared.credentials)
: await this.credentialsRepository.findOneByOrFail({ id: nodeCredential.id, type });
credential = await this.credentialsRepository.findOneByOrFail({
id: nodeCredential.id,
type,
});
} catch (error) {
throw new CredentialNotFoundError(nodeCredential.id, type);
}
@@ -338,7 +332,7 @@ export class CredentialsHelper extends ICredentialsHelper {
await additionalData?.secretsHelpers?.waitForInit();
const canUseSecrets = await this.credentialOwnedByOwner(nodeCredentials);
const canUseSecrets = await this.credentialCanUseExternalSecrets(nodeCredentials);
return this.applyDefaultsAndOverwrites(
additionalData,
@@ -457,28 +451,39 @@ export class CredentialsHelper extends ICredentialsHelper {
await this.credentialsRepository.update(findQuery, newCredentialsData);
}
async credentialOwnedByOwner(nodeCredential: INodeCredentialsDetails): Promise<boolean> {
async credentialCanUseExternalSecrets(nodeCredential: INodeCredentialsDetails): Promise<boolean> {
if (!nodeCredential.id) {
return false;
}
const credential = await this.sharedCredentialsRepository.findOne({
where: {
role: 'credential:owner',
user: {
role: 'global:owner',
},
credentials: {
id: nodeCredential.id,
},
},
});
return (
(await this.cacheService.get(`credential-can-use-secrets:${nodeCredential.id}`, {
refreshFn: async () => {
const credential = await this.sharedCredentialsRepository.findOne({
where: {
role: 'credential:owner',
project: {
projectRelations: {
role: In(['project:personalOwner', 'project:admin']),
user: {
role: In(['global:owner', 'global:admin']),
},
},
},
credentials: {
id: nodeCredential.id!,
},
},
});
if (!credential) {
return false;
}
if (!credential) {
return false;
}
return true;
return true;
},
})) ?? false
);
}
}