Finish preliminary v2 audit logs

This commit is contained in:
Tuan Dang
2023-08-05 16:55:06 +07:00
parent 6fbcbc4807
commit 142fcf0a01
100 changed files with 1885 additions and 1269 deletions
+67 -50
View File
@@ -1,3 +1,4 @@
import { Request } from "express";
import { Types } from "mongoose";
import jwt from "jsonwebtoken";
import bcrypt from "bcrypt";
@@ -5,7 +6,6 @@ import {
APIKeyData,
ITokenVersion,
IUser,
ServiceAccount,
ServiceTokenData,
TokenVersion,
User,
@@ -14,7 +14,6 @@ import {
APIKeyDataNotFoundError,
AccountNotFoundError,
BadRequestError,
ServiceAccountNotFoundError,
ServiceTokenDataNotFoundError,
UnauthorizedRequestError,
} from "../utils/errors";
@@ -26,11 +25,15 @@ import {
getJwtRefreshSecret,
} from "../config";
import {
AUTH_MODE_API_KEY,
AUTH_MODE_JWT,
AUTH_MODE_SERVICE_ACCOUNT,
AUTH_MODE_SERVICE_TOKEN,
AuthMode
} from "../variables";
import {
UserAuthData,
ServiceTokenAuthData
} from "../interfaces/middleware";
import { ActorType } from "../ee/models";
import { getUserAgentType } from "../utils/posthog";
/**
*
@@ -42,7 +45,7 @@ export const validateAuthMode = ({
acceptedAuthModes,
}: {
headers: { [key: string]: string | string[] | undefined },
acceptedAuthModes: string[]
acceptedAuthModes: AuthMode[]
}) => {
const apiKey = headers["x-api-key"];
const authHeader = headers["authorization"];
@@ -55,7 +58,7 @@ export const validateAuthMode = ({
if (typeof apiKey === "string") {
// case: treat request authentication type as via X-API-KEY (i.e. API Key)
authMode = AUTH_MODE_API_KEY;
authMode = AuthMode.API_KEY;
authTokenValue = apiKey;
}
@@ -71,13 +74,10 @@ export const validateAuthMode = ({
switch (tokenValue.split(".", 1)[0]) {
case "st":
authMode = AUTH_MODE_SERVICE_TOKEN;
break;
case "sa":
authMode = AUTH_MODE_SERVICE_ACCOUNT;
authMode = AuthMode.SERVICE_TOKEN;
break;
default:
authMode = AUTH_MODE_JWT;
authMode = AuthMode.JWT;
}
authTokenValue = tokenValue;
@@ -100,10 +100,12 @@ export const validateAuthMode = ({
* @returns {User} user - user corresponding to JWT token
*/
export const getAuthUserPayload = async ({
req,
authTokenValue,
}: {
req: Request,
authTokenValue: string;
}) => {
}): Promise<UserAuthData> => {
const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(authTokenValue, await getJwtAuthSecret())
);
@@ -130,11 +132,25 @@ export const getAuthUserPayload = async ({
if (decodedToken.accessVersion !== tokenVersion.accessVersion) throw UnauthorizedRequestError({
message: "Failed to validate access token",
});
return ({
user,
tokenVersionId: tokenVersion._id,
});
return {
actor: {
type: ActorType.USER,
metadata: {
userId: user._id.toString(),
email: user.email
}
},
authPayload: user,
ipAddress: req.realIP,
userAgent: req.headers["user-agent"] ?? "",
userAgentType: getUserAgentType(req.headers["user-agent"])
}
// return ({
// user,
// tokenVersionId: tokenVersion._id, // what to do with this? // move this out
// });
}
/**
@@ -144,10 +160,12 @@ export const getAuthUserPayload = async ({
* @returns {ServiceTokenData} serviceTokenData - service token data
*/
export const getAuthSTDPayload = async ({
req,
authTokenValue,
}: {
req: Request,
authTokenValue: string;
}) => {
}): Promise<ServiceTokenAuthData> => {
const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3);
const serviceTokenData = await ServiceTokenData
@@ -180,36 +198,21 @@ export const getAuthSTDPayload = async ({
if (!serviceTokenDataToReturn) throw ServiceTokenDataNotFoundError({ message: "Failed to find service token data" });
return serviceTokenDataToReturn;
}
/**
* Return service account access key payload
* @param {Object} obj
* @param {String} obj.authTokenValue - service account access token value
* @returns {ServiceAccount} serviceAccount
*/
export const getAuthSAAKPayload = async ({
authTokenValue,
}: {
authTokenValue: string;
}) => {
const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3);
const serviceAccount = await ServiceAccount.findById(
Buffer.from(TOKEN_IDENTIFIER, "base64").toString("hex")
).select("+secretHash");
if (!serviceAccount) {
throw ServiceAccountNotFoundError({ message: "Failed to find service account" });
return {
actor: {
type: ActorType.SERVICE,
metadata: {
serviceId: serviceTokenDataToReturn._id.toString(),
name: serviceTokenDataToReturn.name
}
},
authPayload: serviceTokenDataToReturn,
ipAddress: req.realIP,
userAgent: req.headers["user-agent"] ?? "",
userAgentType: getUserAgentType(req.headers["user-agent"])
}
const result = await bcrypt.compare(TOKEN_SECRET, serviceAccount.secretHash);
if (!result) throw UnauthorizedRequestError({
message: "Failed to authenticate service account access key",
});
return serviceAccount;
// return serviceTokenDataToReturn;
}
/**
@@ -219,10 +222,12 @@ export const getAuthSAAKPayload = async ({
* @returns {APIKeyData} apiKeyData - API key data
*/
export const getAuthAPIKeyPayload = async ({
req,
authTokenValue,
}: {
req: Request,
authTokenValue: string;
}) => {
}): Promise<UserAuthData> => {
const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split(".", 3);
let apiKeyData = await APIKeyData
@@ -264,7 +269,19 @@ export const getAuthAPIKeyPayload = async ({
});
}
return user;
return {
actor: {
type: ActorType.USER,
metadata: {
userId: user._id.toString(),
email: user.email
}
},
authPayload: user,
ipAddress: req.realIP,
userAgent: req.headers["user-agent"] ?? "",
userAgentType: getUserAgentType(req.headers["user-agent"])
}
}
/**
+1 -1
View File
@@ -115,5 +115,5 @@ export const updateSubscriptionOrgQuantity = async ({
);
}
await EELicenseService.refreshPlan(organizationId);
await EELicenseService.refreshPlan(new Types.ObjectId(organizationId));
};
+106 -23
View File
@@ -11,9 +11,9 @@ import {
IServiceTokenData,
Secret,
SecretBlindIndexData,
ServiceTokenData
ServiceTokenData,
} from "../models";
import { SecretVersion } from "../ee/models";
import { SecretVersion, EventType } from "../ee/models";
import {
BadRequestError,
InternalServerError,
@@ -40,7 +40,7 @@ import {
} from "../utils/crypto";
import { TelemetryService } from "../services";
import { client, getEncryptionKey, getRootEncryptionKey } from "../config";
import { EELogService, EESecretService } from "../ee/services";
import { EELogService, EESecretService, EEAuditLogService } from "../ee/services";
import { getAuthDataPayloadIdObj, getAuthDataPayloadUserObj } from "../utils/auth";
import { getFolderByPath, getFolderIdFromServiceToken } from "../services/FolderService";
import picomatch from "picomatch";
@@ -433,10 +433,27 @@ export const createSecretHelper = async ({
...getAuthDataPayloadIdObj(authData),
workspaceId,
actions: [action],
channel: authData.authChannel,
ipAddress: authData.authIP
channel: authData.userAgentType,
ipAddress: authData.ipAddress
}));
await EEAuditLogService.createAuditLog(
authData,
{
type: EventType.CREATE_SECRET,
metadata: {
environment,
secretPath,
secretId: secret._id.toString(),
secretKey: secretName,
secretVersion: secret.version
}
},
{
workspaceId
}
);
// (EE) take a secret snapshot
await EESecretService.takeSecretSnapshot({
workspaceId,
@@ -457,8 +474,8 @@ export const createSecretHelper = async ({
environment,
workspaceId,
folderId,
channel: authData.authChannel,
userAgent: authData.authUserAgent
channel: authData.userAgentType,
userAgent: authData.userAgent
}
});
}
@@ -528,9 +545,24 @@ export const getSecretsHelper = async ({
...getAuthDataPayloadIdObj(authData),
workspaceId,
actions: [action],
channel: authData.authChannel,
ipAddress: authData.authIP
channel: authData.userAgentType,
ipAddress: authData.ipAddress
}));
await EEAuditLogService.createAuditLog(
authData,
{
type: EventType.GET_SECRETS,
metadata: {
environment,
secretPath,
numberOfSecrets: secrets.length
}
},
{
workspaceId
}
);
const postHogClient = await TelemetryService.getPostHogClient();
@@ -545,8 +577,8 @@ export const getSecretsHelper = async ({
environment,
workspaceId,
folderId,
channel: authData.authChannel,
userAgent: authData.authUserAgent
channel: authData.userAgentType,
userAgent: authData.userAgent
}
});
}
@@ -622,10 +654,27 @@ export const getSecretHelper = async ({
...getAuthDataPayloadIdObj(authData),
workspaceId,
actions: [action],
channel: authData.authChannel,
ipAddress: authData.authIP
channel: authData.userAgentType,
ipAddress: authData.ipAddress
}));
await EEAuditLogService.createAuditLog(
authData,
{
type: EventType.GET_SECRET,
metadata: {
environment,
secretPath,
secretId: secret._id.toString(),
secretKey: secretName,
secretVersion: secret.version
}
},
{
workspaceId
}
);
const postHogClient = await TelemetryService.getPostHogClient();
if (postHogClient) {
@@ -639,8 +688,8 @@ export const getSecretHelper = async ({
environment,
workspaceId,
folderId,
channel: authData.authChannel,
userAgent: authData.authUserAgent
channel: authData.userAgentType,
userAgent: authData.userAgent
}
});
}
@@ -771,9 +820,26 @@ export const updateSecretHelper = async ({
...getAuthDataPayloadIdObj(authData),
workspaceId,
actions: [action],
channel: authData.authChannel,
ipAddress: authData.authIP
channel: authData.userAgentType,
ipAddress: authData.ipAddress
}));
await EEAuditLogService.createAuditLog(
authData,
{
type: EventType.UPDATE_SECRET,
metadata: {
environment,
secretPath,
secretId: secret._id.toString(),
secretKey: secretName,
secretVersion: secret.version
}
},
{
workspaceId
}
);
// (EE) take a secret snapshot
await EESecretService.takeSecretSnapshot({
@@ -795,8 +861,8 @@ export const updateSecretHelper = async ({
environment,
workspaceId,
folderId,
channel: authData.authChannel,
userAgent: authData.authUserAgent
channel: authData.userAgentType,
userAgent: authData.userAgent
}
});
}
@@ -894,10 +960,27 @@ export const deleteSecretHelper = async ({
...getAuthDataPayloadIdObj(authData),
workspaceId,
actions: [action],
channel: authData.authChannel,
ipAddress: authData.authIP
channel: authData.userAgentType,
ipAddress: authData.ipAddress
}));
await EEAuditLogService.createAuditLog(
authData,
{
type: EventType.DELETE_SECRET,
metadata: {
environment,
secretPath,
secretId: secret._id.toString(),
secretKey: secretName,
secretVersion: secret.version
}
},
{
workspaceId
}
);
// (EE) take a secret snapshot
await EESecretService.takeSecretSnapshot({
workspaceId,
@@ -918,8 +1001,8 @@ export const deleteSecretHelper = async ({
environment,
workspaceId,
folderId,
channel: authData.authChannel,
userAgent: authData.authUserAgent
channel: authData.userAgentType,
userAgent: authData.userAgent
}
});
}
+2 -1
View File
@@ -1,3 +1,4 @@
import { Types } from "mongoose";
import {
Bot,
Key,
@@ -25,7 +26,7 @@ export const createWorkspace = async ({
organizationId,
}: {
name: string;
organizationId: string;
organizationId: Types.ObjectId;
}) => {
// create workspace
const workspace = await new Workspace({