mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 07:28:21 +00:00
Add permissions and audit logging to service tokens v3
This commit is contained in:
@@ -4,9 +4,23 @@ import {
|
||||
ServiceTokenDataV3,
|
||||
ServiceTokenDataV3Key
|
||||
} from "../../models";
|
||||
import {
|
||||
Scope
|
||||
} from "../../models/serviceTokenDataV3";
|
||||
import {
|
||||
EventType
|
||||
} from "../../ee/models";
|
||||
import { validateRequest } from "../../helpers/validation";
|
||||
import * as reqValidator from "../../validation/serviceTokenV3";
|
||||
import { createToken } from "../../helpers/auth";
|
||||
import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub,
|
||||
getUserProjectPermissions
|
||||
} from "../../ee/services/ProjectRoleService";
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
import { BadRequestError, ResourceNotFoundError } from "../../utils/errors";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
|
||||
/**
|
||||
* Create service token data
|
||||
@@ -26,6 +40,11 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
|
||||
nonce // for ServiceTokenDataV3Key
|
||||
}
|
||||
} = await validateRequest(reqValidator.CreateServiceTokenV3, req);
|
||||
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Create,
|
||||
ProjectPermissionSub.ServiceTokens
|
||||
);
|
||||
|
||||
let expiresAt;
|
||||
if (expiresIn) {
|
||||
@@ -33,12 +52,13 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
|
||||
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
|
||||
}
|
||||
|
||||
const isActive = false;
|
||||
const serviceTokenData = await new ServiceTokenDataV3({
|
||||
name,
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
publicKey,
|
||||
scopes,
|
||||
isActive: false,
|
||||
isActive,
|
||||
expiresAt
|
||||
}).save();
|
||||
|
||||
@@ -58,6 +78,22 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
|
||||
secret: "hello" // TODO: replace with real secret
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.CREATE_SERVICE_TOKEN_V3,
|
||||
metadata: {
|
||||
name,
|
||||
isActive,
|
||||
scopes: scopes as Array<Scope>,
|
||||
expiresAt
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: new Types.ObjectId(workspaceId)
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
serviceTokenData,
|
||||
serviceToken: `proj_token.${token}`
|
||||
@@ -81,13 +117,29 @@ export const updateServiceTokenData = async (req: Request, res: Response) => {
|
||||
}
|
||||
} = await validateRequest(reqValidator.UpdateServiceTokenV3, req);
|
||||
|
||||
let serviceTokenData = await ServiceTokenDataV3.findById(serviceTokenDataId);
|
||||
|
||||
if (!serviceTokenData) throw ResourceNotFoundError({
|
||||
message: "Service token not found"
|
||||
});
|
||||
|
||||
const { permission } = await getUserProjectPermissions(
|
||||
req.user._id,
|
||||
serviceTokenData.workspace.toString()
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Edit,
|
||||
ProjectPermissionSub.ServiceTokens
|
||||
);
|
||||
|
||||
let expiresAt;
|
||||
if (expiresIn) {
|
||||
expiresAt = new Date();
|
||||
expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn);
|
||||
}
|
||||
|
||||
const serviceTokenData = await ServiceTokenDataV3.findByIdAndUpdate(
|
||||
serviceTokenData = await ServiceTokenDataV3.findByIdAndUpdate(
|
||||
serviceTokenDataId,
|
||||
{
|
||||
name,
|
||||
@@ -99,6 +151,26 @@ export const updateServiceTokenData = async (req: Request, res: Response) => {
|
||||
new: true
|
||||
}
|
||||
);
|
||||
|
||||
if (!serviceTokenData) throw BadRequestError({
|
||||
message: "Failed to update service token"
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.UPDATE_SERVICE_TOKEN_V3,
|
||||
metadata: {
|
||||
name,
|
||||
isActive,
|
||||
scopes: scopes as Array<Scope>,
|
||||
expiresAt
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: serviceTokenData.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
serviceTokenData
|
||||
@@ -116,13 +188,42 @@ export const deleteServiceTokenData = async (req: Request, res: Response) => {
|
||||
params: { serviceTokenDataId }
|
||||
} = await validateRequest(reqValidator.DeleteServiceTokenV3, req);
|
||||
|
||||
const serviceTokenData = await ServiceTokenDataV3.findByIdAndDelete(serviceTokenDataId);
|
||||
let serviceTokenData = await ServiceTokenDataV3.findById(serviceTokenDataId);
|
||||
if (!serviceTokenData) throw ResourceNotFoundError({
|
||||
message: "Service token not found"
|
||||
});
|
||||
|
||||
if (serviceTokenData) {
|
||||
await ServiceTokenDataV3Key.findOneAndDelete({
|
||||
serviceTokenData: serviceTokenData._id
|
||||
});
|
||||
}
|
||||
const { permission } = await getUserProjectPermissions(
|
||||
req.user._id,
|
||||
serviceTokenData.workspace.toString()
|
||||
);
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Delete,
|
||||
ProjectPermissionSub.ServiceTokens
|
||||
);
|
||||
|
||||
serviceTokenData = await ServiceTokenDataV3.findByIdAndDelete(serviceTokenDataId);
|
||||
|
||||
if (!serviceTokenData) throw BadRequestError({
|
||||
message: "Failed to delete service token"
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
req.authData,
|
||||
{
|
||||
type: EventType.DELETE_SERVICE_TOKEN_V3,
|
||||
metadata: {
|
||||
name: serviceTokenData.name,
|
||||
isActive: serviceTokenData.isActive,
|
||||
scopes: serviceTokenData.scopes as Array<Scope>,
|
||||
expiresAt: serviceTokenData.expiresAt
|
||||
}
|
||||
},
|
||||
{
|
||||
workspaceId: serviceTokenData.workspace
|
||||
}
|
||||
);
|
||||
|
||||
return res.status(200).send({
|
||||
serviceTokenData
|
||||
|
||||
@@ -26,8 +26,11 @@ export enum EventType {
|
||||
ADD_TRUSTED_IP = "add-trusted-ip",
|
||||
UPDATE_TRUSTED_IP = "update-trusted-ip",
|
||||
DELETE_TRUSTED_IP = "delete-trusted-ip",
|
||||
CREATE_SERVICE_TOKEN = "create-service-token",
|
||||
DELETE_SERVICE_TOKEN = "delete-service-token",
|
||||
CREATE_SERVICE_TOKEN = "create-service-token", // v2
|
||||
DELETE_SERVICE_TOKEN = "delete-service-token", // v2
|
||||
CREATE_SERVICE_TOKEN_V3 = "create-service-token-v3", // v3
|
||||
UPDATE_SERVICE_TOKEN_V3 = "update-service-token-v3", // v3
|
||||
DELETE_SERVICE_TOKEN_V3 = "delete-service-token-v3", // v3
|
||||
CREATE_ENVIRONMENT = "create-environment",
|
||||
UPDATE_ENVIRONMENT = "update-environment",
|
||||
DELETE_ENVIRONMENT = "delete-environment",
|
||||
|
||||
@@ -2,6 +2,9 @@ import {
|
||||
ActorType,
|
||||
EventType
|
||||
} from "./enums";
|
||||
import {
|
||||
Scope
|
||||
} from "../../../models/serviceTokenDataV3";
|
||||
|
||||
interface UserActorMetadata {
|
||||
userId: string;
|
||||
@@ -194,6 +197,36 @@ interface DeleteServiceTokenEvent {
|
||||
}
|
||||
}
|
||||
|
||||
interface CreateServiceTokenV3Event {
|
||||
type: EventType.CREATE_SERVICE_TOKEN_V3;
|
||||
metadata: {
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
scopes: Array<Scope>;
|
||||
expiresAt?: Date;
|
||||
}
|
||||
}
|
||||
|
||||
interface UpdateServiceTokenV3Event {
|
||||
type: EventType.UPDATE_SERVICE_TOKEN_V3;
|
||||
metadata: {
|
||||
name?: string;
|
||||
isActive?: boolean;
|
||||
scopes?: Array<Scope>;
|
||||
expiresAt?: Date;
|
||||
}
|
||||
}
|
||||
|
||||
interface DeleteServiceTokenV3Event {
|
||||
type: EventType.DELETE_SERVICE_TOKEN_V3;
|
||||
metadata: {
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
scopes: Array<Scope>;
|
||||
expiresAt?: Date;
|
||||
}
|
||||
}
|
||||
|
||||
interface CreateEnvironmentEvent {
|
||||
type: EventType.CREATE_ENVIRONMENT;
|
||||
metadata: {
|
||||
@@ -390,6 +423,9 @@ export type Event =
|
||||
| DeleteTrustedIPEvent
|
||||
| CreateServiceTokenEvent
|
||||
| DeleteServiceTokenEvent
|
||||
| CreateServiceTokenV3Event
|
||||
| UpdateServiceTokenV3Event
|
||||
| DeleteServiceTokenV3Event
|
||||
| CreateEnvironmentEvent
|
||||
| UpdateEnvironmentEvent
|
||||
| DeleteEnvironmentEvent
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from "../../models";
|
||||
import {
|
||||
ServiceActor,
|
||||
ServiceActorV3,
|
||||
UserActor,
|
||||
UserAgentType
|
||||
} from "../../ee/models";
|
||||
@@ -23,7 +24,7 @@ export interface UserAuthData extends BaseAuthData {
|
||||
}
|
||||
|
||||
export interface ServiceTokenV3AuthData extends BaseAuthData {
|
||||
actor: ServiceActor;
|
||||
actor: ServiceActorV3;
|
||||
authPayload: IServiceTokenDataV3;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ enum Permission {
|
||||
READ_WRITE = "readWrite"
|
||||
}
|
||||
|
||||
interface Scope {
|
||||
export interface Scope {
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
permission: Permission;
|
||||
|
||||
@@ -58,6 +58,10 @@ export const validateClientForIntegration = async ({
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for integration"
|
||||
});
|
||||
case ActorType.SERVICE_V3:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for integration"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -58,6 +58,10 @@ const validateClientForIntegrationAuth = async ({
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for integration authorization"
|
||||
});
|
||||
case ActorType.SERVICE_V3:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for integration authorization"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -46,6 +46,10 @@ export const validateClientForOrganization = async ({
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for organization"
|
||||
});
|
||||
case ActorType.SERVICE_V3:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for organization"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { WorkspaceNotFoundError } from "../utils/errors";
|
||||
import { AuthData } from "../interfaces/middleware";
|
||||
import { z } from "zod";
|
||||
import { EventType, UserAgentType } from "../ee/models";
|
||||
import { UnauthorizedRequestError } from "../utils/errors";
|
||||
|
||||
/**
|
||||
* Validate authenticated clients for workspace with id [workspaceId] based
|
||||
@@ -56,8 +57,11 @@ export const validateClientForWorkspace = async ({
|
||||
environment,
|
||||
requiredPermissions
|
||||
});
|
||||
|
||||
return {};
|
||||
break;
|
||||
case ActorType.SERVICE_V3:
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed service token authorization for organization"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user