2024-02-14 15:06:55 +07:00
|
|
|
import * as express from "express";
|
|
|
|
|
import { createDecoder, createVerifier } from "fast-jwt";
|
|
|
|
|
|
|
|
|
|
import HttpError from "../interfaces/http-error";
|
|
|
|
|
import HttpStatus from "../interfaces/http-status";
|
2024-08-22 14:23:50 +07:00
|
|
|
import { addLogSequence } from "../interfaces/utils";
|
|
|
|
|
import { RequestWithUser } from "./user";
|
2024-02-14 15:06:55 +07:00
|
|
|
|
|
|
|
|
if (!process.env.AUTH_PUBLIC_KEY && !process.env.AUTH_REALM_URL) {
|
|
|
|
|
throw new Error("Require keycloak AUTH_PUBLIC_KEY or AUTH_REALM_URL.");
|
|
|
|
|
}
|
2024-08-22 14:23:50 +07:00
|
|
|
if (process.env.AUTH_PUBLIC_KEY && process.env.AUTH_REALM_URL && !process.env.AUTH_PREFERRED_MODE) {
|
2024-02-14 15:06:55 +07:00
|
|
|
throw new Error(
|
|
|
|
|
"AUTH_PREFFERRED must be specified if AUTH_PUBLIC_KEY and AUTH_REALM_URL is provided.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const jwtVerify = createVerifier({
|
|
|
|
|
key: async () => {
|
|
|
|
|
return `-----BEGIN PUBLIC KEY-----\n${process.env.AUTH_PUBLIC_KEY}\n-----END PUBLIC KEY-----`;
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const jwtDecode = createDecoder();
|
|
|
|
|
|
|
|
|
|
export async function expressAuthentication(
|
2024-08-22 14:23:50 +07:00
|
|
|
request: RequestWithUser,
|
2024-02-14 15:06:55 +07:00
|
|
|
securityName: string,
|
|
|
|
|
_scopes?: string[],
|
|
|
|
|
) {
|
|
|
|
|
if (process.env.NODE_ENV !== "production" && process.env.AUTH_BYPASS) {
|
|
|
|
|
return { preferred_username: "bypassed" };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (securityName !== "bearerAuth") throw new Error("ไม่ทราบวิธีการยืนยันตัวตน");
|
|
|
|
|
|
|
|
|
|
const token = request.headers["authorization"]?.includes("Bearer ")
|
|
|
|
|
? request.headers["authorization"].split(" ")[1]
|
|
|
|
|
: request.headers["authorization"];
|
|
|
|
|
|
|
|
|
|
if (!token) throw new HttpError(HttpStatus.UNAUTHORIZED, "ไม่พบข้อมูลสำหรับยืนยันตัวตน");
|
|
|
|
|
|
|
|
|
|
let payload: Record<string, any> = {};
|
|
|
|
|
|
|
|
|
|
switch (process.env.AUTH_PREFERRED_MODE) {
|
|
|
|
|
case "online":
|
|
|
|
|
payload = await verifyOnline(token);
|
|
|
|
|
break;
|
|
|
|
|
case "offline":
|
|
|
|
|
payload = await verifyOffline(token);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (process.env.AUTH_REALM_URL) payload = await verifyOnline(token);
|
|
|
|
|
if (process.env.AUTH_PUBLIC_KEY) payload = await verifyOffline(token);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-08-22 14:23:50 +07:00
|
|
|
if (!request.app.locals.logData) {
|
|
|
|
|
request.app.locals.logData = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// addLogSequence(request, {
|
|
|
|
|
// action: "database",
|
|
|
|
|
// status: "success",
|
|
|
|
|
// description: "Query Data.",
|
|
|
|
|
// });
|
|
|
|
|
request.app.locals.logData.userId = payload.sub;
|
|
|
|
|
request.app.locals.logData.userName = payload.name;
|
|
|
|
|
request.app.locals.logData.user = payload.preferred_username;
|
2024-02-14 15:06:55 +07:00
|
|
|
|
2026-03-23 09:36:27 +07:00
|
|
|
// เก็บค่า profileId และ orgRootDnaId จาก token (ใช้ค่าว่างถ้าไม่มี)
|
|
|
|
|
request.app.locals.logData.profileId = payload.profileId ?? "";
|
|
|
|
|
request.app.locals.logData.orgRootDnaId = payload.orgRootDnaId ?? "";
|
|
|
|
|
request.app.locals.logData.orgChild1DnaId = payload.orgChild1DnaId ?? "";
|
|
|
|
|
request.app.locals.logData.orgChild2DnaId = payload.orgChild2DnaId ?? "";
|
|
|
|
|
request.app.locals.logData.orgChild3DnaId = payload.orgChild3DnaId ?? "";
|
|
|
|
|
request.app.locals.logData.orgChild4DnaId = payload.orgChild4DnaId ?? "";
|
|
|
|
|
request.app.locals.logData.empType = payload.empType ?? "";
|
|
|
|
|
request.app.locals.logData.prefix = payload.prefix ?? "";
|
|
|
|
|
|
2024-02-14 15:06:55 +07:00
|
|
|
return payload;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function verifyOffline(token: string) {
|
|
|
|
|
const payload = await jwtVerify(token).catch((_) => null);
|
|
|
|
|
if (!payload) throw new HttpError(HttpStatus.UNAUTHORIZED, "ไม่สามารถยืนยันตัวตนได้");
|
|
|
|
|
return payload;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function verifyOnline(token: string) {
|
|
|
|
|
const res = await fetch(`${process.env.AUTH_REALM_URL}/protocol/openid-connect/userinfo`, {
|
|
|
|
|
headers: { authorization: `Bearer ${token}` },
|
|
|
|
|
}).catch((e) => console.error(e));
|
|
|
|
|
|
|
|
|
|
if (!res) throw new Error("ไม่สามารถเข้าถึงระบบยืนยันตัวตน");
|
|
|
|
|
if (!res.ok) throw new HttpError(HttpStatus.UNAUTHORIZED, "ไม่สามารถยืนยันตัวตนได้");
|
|
|
|
|
|
|
|
|
|
return await jwtDecode(token);
|
|
|
|
|
}
|