Skip to content

Commit 8d91211

Browse files
committed
Log impersonation start
1 parent edaf1fb commit 8d91211

2 files changed

Lines changed: 27 additions & 4 deletions

File tree

apps/webapp/app/models/admin.server.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { redirect } from "@remix-run/server-runtime";
22
import { prisma } from "~/db.server";
3+
import { logger } from "~/services/logger.server";
34
import { SearchParams } from "~/routes/admin._index";
45
import {
56
clearImpersonationId,
@@ -8,6 +9,12 @@ import {
89
} from "~/services/impersonation.server";
910
import { requireUser } from "~/services/session.server";
1011

12+
function extractClientIp(xff: string | null): string | null {
13+
if (!xff) return null;
14+
const parts = xff.split(",").map((p) => p.trim());
15+
return parts[parts.length - 1]; // ALB appends the real client IP
16+
}
17+
1118
const pageSize = 20;
1219

1320
export async function adminGetUsers(userId: string, { page, search }: SearchParams) {
@@ -212,6 +219,22 @@ export async function redirectWithImpersonation(request: Request, userId: string
212219
throw new Error("Unauthorized");
213220
}
214221

222+
const xff = request.headers.get("x-forwarded-for");
223+
const ipAddress = extractClientIp(xff);
224+
225+
try {
226+
await prisma.impersonationAuditLog.create({
227+
data: {
228+
action: "START",
229+
adminId: user.id,
230+
targetId: userId,
231+
ipAddress,
232+
},
233+
});
234+
} catch (error) {
235+
logger.error("Failed to create impersonation audit log", { error, adminId: user.id, targetId: userId });
236+
}
237+
215238
const session = await setImpersonationId(userId, request);
216239

217240
return redirect(path, {

internal-packages/database/prisma/schema.prisma

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ model User {
6060
backupCodes MfaBackupCode[]
6161
bulkActions BulkActionGroup[]
6262
63-
impersonationsPerformed ImpersonationAuditLog[] @relation("ImpersonationActor")
63+
impersonationsPerformed ImpersonationAuditLog[] @relation("ImpersonationAdmin")
6464
impersonationsReceived ImpersonationAuditLog[] @relation("ImpersonationTarget")
6565
}
6666

@@ -2398,8 +2398,8 @@ model ImpersonationAuditLog {
23982398
action ImpersonationAuditLogAction
23992399
24002400
/// The admin user who initiated/ended the impersonation
2401-
actor User @relation("ImpersonationActor", fields: [actorId], references: [id], onDelete: Cascade, onUpdate: Cascade)
2402-
actorId String
2401+
admin User @relation("ImpersonationAdmin", fields: [adminId], references: [id], onDelete: Cascade, onUpdate: Cascade)
2402+
adminId String
24032403
24042404
/// The user being impersonated
24052405
target User @relation("ImpersonationTarget", fields: [targetId], references: [id], onDelete: Cascade, onUpdate: Cascade)
@@ -2409,7 +2409,7 @@ model ImpersonationAuditLog {
24092409
24102410
createdAt DateTime @default(now())
24112411
2412-
@@index([actorId])
2412+
@@index([adminId])
24132413
@@index([targetId])
24142414
@@index([createdAt])
24152415
}

0 commit comments

Comments
 (0)