mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-21 04:56:40 +02:00
Be able to pull users from the proxy
This commit is contained in:
@@ -28,6 +28,7 @@ export * from "./verifyApiKeyAccess";
|
|||||||
export * from "./verifySiteProvisioningKeyAccess";
|
export * from "./verifySiteProvisioningKeyAccess";
|
||||||
export * from "./verifyDomainAccess";
|
export * from "./verifyDomainAccess";
|
||||||
export * from "./verifyUserIsOrgOwner";
|
export * from "./verifyUserIsOrgOwner";
|
||||||
|
export * from "./verifyUserFromSessionOrHeaders";
|
||||||
export * from "./verifySiteResourceAccess";
|
export * from "./verifySiteResourceAccess";
|
||||||
export * from "./logActionAudit";
|
export * from "./logActionAudit";
|
||||||
export * from "./verifyOlmAccess";
|
export * from "./verifyOlmAccess";
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import { Response, NextFunction } from "express";
|
||||||
|
import { db } from "@server/db";
|
||||||
|
import { users } from "@server/db";
|
||||||
|
import { eq, or } from "drizzle-orm";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
import { verifySession } from "@server/auth/sessions/verifySession";
|
||||||
|
import { getUserOrgRoleIds } from "@server/lib/userOrgRoles";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Middleware that populates req.user from either:
|
||||||
|
* 1. A valid session cookie (normal authenticated flow), or
|
||||||
|
* 2. Badger-injected headers: Remote-User-Id, Remote-User (username), Remote-Email
|
||||||
|
*
|
||||||
|
* If an orgId is present in req.params, req.userOrgRoleIds is also populated.
|
||||||
|
*
|
||||||
|
* If neither source yields a user, returns 401.
|
||||||
|
* If header-based lookup matches more than one user, returns 400.
|
||||||
|
*/
|
||||||
|
export const verifyUserFromSessionOrHeadersMiddleware = async (
|
||||||
|
req: any,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) => {
|
||||||
|
// 1. Try session-based auth first
|
||||||
|
if (!req.user) {
|
||||||
|
try {
|
||||||
|
const { session, user } = await verifySession(req);
|
||||||
|
if (session && user) {
|
||||||
|
const rows = await db
|
||||||
|
.select()
|
||||||
|
.from(users)
|
||||||
|
.where(eq(users.userId, user.userId));
|
||||||
|
|
||||||
|
if (rows[0]) {
|
||||||
|
req.user = rows[0];
|
||||||
|
req.session = session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// session lookup failure is not fatal; fall through to header auth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Fall back to Badger-injected headers
|
||||||
|
if (!req.user) {
|
||||||
|
const userId = req.headers["remote-user-id"] as string | undefined;
|
||||||
|
const username = req.headers["remote-user"] as string | undefined;
|
||||||
|
const email = req.headers["remote-email"] as string | undefined;
|
||||||
|
|
||||||
|
if (!userId && !username && !email) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let foundUsers;
|
||||||
|
|
||||||
|
if (userId) {
|
||||||
|
// Most reliable: look up directly by ID
|
||||||
|
foundUsers = await db
|
||||||
|
.select()
|
||||||
|
.from(users)
|
||||||
|
.where(eq(users.userId, userId));
|
||||||
|
} else {
|
||||||
|
// Fall back to username / email (may be absent depending on badger version)
|
||||||
|
const conditions = [];
|
||||||
|
if (username) conditions.push(eq(users.username, username));
|
||||||
|
if (email) conditions.push(eq(users.email, email));
|
||||||
|
|
||||||
|
foundUsers = await db
|
||||||
|
.select()
|
||||||
|
.from(users)
|
||||||
|
.where(or(...conditions));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundUsers || foundUsers.length === 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.UNAUTHORIZED, "User not found")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundUsers.length > 1) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
"Multiple users found matching the provided credentials"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
req.user = foundUsers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Populate userOrgRoleIds if an orgId is available in route params
|
||||||
|
if (req.user && req.params?.orgId && !req.userOrgRoleIds) {
|
||||||
|
req.userOrgRoleIds = await getUserOrgRoleIds(
|
||||||
|
req.user.userId,
|
||||||
|
req.params.orgId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
@@ -18,8 +18,12 @@ import * as billing from "#private/routers/billing";
|
|||||||
import * as license from "#private/routers/license";
|
import * as license from "#private/routers/license";
|
||||||
import * as resource from "#private/routers/resource";
|
import * as resource from "#private/routers/resource";
|
||||||
import * as browserTarget from "#private/routers/browserGatewayTarget";
|
import * as browserTarget from "#private/routers/browserGatewayTarget";
|
||||||
|
import * as ssh from "#private/routers/ssh";
|
||||||
|
|
||||||
import { verifySessionUserMiddleware } from "@server/middlewares";
|
import {
|
||||||
|
verifySessionUserMiddleware,
|
||||||
|
verifyUserFromSessionOrHeadersMiddleware
|
||||||
|
} from "@server/middlewares";
|
||||||
|
|
||||||
import { internalRouter as ir } from "@server/routers/internal";
|
import { internalRouter as ir } from "@server/routers/internal";
|
||||||
|
|
||||||
@@ -42,6 +46,10 @@ internalRouter.get(`/license/status`, license.getLicenseStatus);
|
|||||||
|
|
||||||
internalRouter.get("/maintenance/info", resource.getMaintenanceInfo);
|
internalRouter.get("/maintenance/info", resource.getMaintenanceInfo);
|
||||||
|
|
||||||
internalRouter.post("/org/:orgId/ssh/sign-key", ssh.signSshKey);
|
internalRouter.post(
|
||||||
|
"/org/:orgId/ssh/sign-key",
|
||||||
|
verifyUserFromSessionOrHeadersMiddleware,
|
||||||
|
ssh.signSshKey
|
||||||
|
);
|
||||||
|
|
||||||
internalRouter.get("/resource/browser-target", browserTarget.getBrowserTarget);
|
internalRouter.get("/resource/browser-target", browserTarget.getBrowserTarget);
|
||||||
|
|||||||
+17
-12
@@ -64,18 +64,23 @@ export default async function SshPage() {
|
|||||||
target = res.data.data;
|
target = res.data.data;
|
||||||
|
|
||||||
if (target.pamMode === "push") {
|
if (target.pamMode === "push") {
|
||||||
const { privateKeyPem, publicKeyOpenSSH } =
|
try {
|
||||||
generateEphemeralKeyPair();
|
const { privateKeyPem, publicKeyOpenSSH } =
|
||||||
privateKey = privateKeyPem;
|
generateEphemeralKeyPair();
|
||||||
const res = await priv.post<AxiosResponse<SignSshKeyResponse>>(
|
privateKey = privateKeyPem;
|
||||||
`/org/${target.orgId}/ssh/sign-key`,
|
const res = await priv.post<AxiosResponse<SignSshKeyResponse>>(
|
||||||
{
|
`/org/${target.orgId}/ssh/sign-key`,
|
||||||
publicKey: publicKeyOpenSSH,
|
{
|
||||||
resource: target.niceId
|
publicKey: publicKeyOpenSSH,
|
||||||
}
|
resource: target.niceId
|
||||||
);
|
}
|
||||||
signedKeyData = res.data.data;
|
);
|
||||||
console.log("Received signed SSH key:", signedKeyData);
|
signedKeyData = res.data.data;
|
||||||
|
console.log("Received signed SSH key:", signedKeyData);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error signing SSH key:", err);
|
||||||
|
error = "Failed to sign SSH key for PAM push authentication.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching browser target:", error);
|
console.error("Error fetching browser target:", error);
|
||||||
|
|||||||
Reference in New Issue
Block a user