require("dotenv").config(); const cookieParser = require('cookie-parser'); const querystring = require("querystring"); const port = Number(process.env.SSO_PORT) || 80; const express = require("express"); const cors = require('cors'); const jwt = require("jsonwebtoken"); const fs = require("fs"); const axios = require("axios"); const CryptoJS = require("crypto-js"); const secretKey = "uuidSecretKey2025"; // ใช้เป็นคีย์สำหรับเข้ารหัส const cookieName = process.env.SSO_COOKIE_NAME || "ssotoken"; const privateKey = fs.readFileSync(`./BMA`, "utf8"); const signOptions = { issuer: "BMA corp", subject: "sso@bangkok.go.th", audience: "http://sso.bangkok.go.th", expiresIn: "12h", algorithm: "RS256", }; const urlKeycloakToken = `${process.env.KC_URL}/realms/${process.env.KC_REALMS}/protocol/openid-connect/token`; const app = express(); // ตั้งค่าการป้องกัน Origin const allowedOrigins = ['https://hrms.bangkok.go.th', 'https://hrms.chin.in.th', 'https://hrmsbkk.case-collection.com', 'http://localhost:3002']; // อนุญาตเฉพาะ domain ที่กำหนด //http://localhost:3002 app.use(cors({ // origin: function (origin, callback) { // if (allowedOrigins.includes(origin)) { // callback(null, true); // อนุญาต // } else { // callback(new Error('Origin not allowed by CORS')); // ปฏิเสธ // } // }, methods: ['GET', 'POST'], // จำกัดเฉพาะ method ที่อนุญาต credentials: true, })); app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.use(cookieParser()); app.get("/api/v1/sso", async (req, res) => { res.status(200).send("HRMS API SSO"); }); app.post("/api/v1/sso/signin", async (req, res) => { const origin = req.headers.origin; if (allowedOrigins.includes(origin)) { try { const login_user = req.body; const formdata = new URLSearchParams(); formdata.append("grant_type", "password"); formdata.append("client_id", process.env.VITE_CLIENTID_KEYCLOAK); formdata.append("username", login_user.username); formdata.append("password", login_user.password); await axios.post(urlKeycloakToken, formdata, { headers: { "Content-Type": "application/x-www-form-urlencoded", }, }).then(async () => { const payload = { username: login_user.username }; let token = jwt.sign(payload, privateKey, signOptions); res.cookie(cookieName, token, { maxAge: 1000 * 60 * 60 * 24, // กำหนด timeout หน่วยเป็น millisecond path: "/", httpOnly: true, }); const uid = await CryptoJS.AES.encrypt(login_user.username, secretKey).toString(); res.status(200).send({ uid }); }).catch((err) => { if (err.status) { res.status(401).send("Incorrect user or password"); } else res.status(err.status).send(error); }); } catch (error) { res.status(500).send(error); } } else { res.status(403).json({ error: 'Forbidden: Origin not allowed' }); } }); app.post("/api/v1/sso/kcauth", async (req, res) => { const origin = req.headers.origin; if (allowedOrigins.includes(origin)) { try { // kcauth // const useBMA = Boolean(process.env.USE_BMA) || false; // const publicKeyLanding = fs.readFileSync(`./BMA.pub.pem`, "utf8"); const clientSecret = process.env.KC_CLIENT_SECRET; const clientId = process.env.KC_CLIENT_ID; // const cookies = req.cookies; // const tokenSSO = cookies[cookieName]; //if (tokenSSO) { // let decodedToken = ""; // if (useBMA) { // decodedToken = jwt.decode(tokenSSO); // } else { // decodedToken = jwt.verify(tokenSSO, publicKeyLanding); // } // let d = JSON.parse(JSON.stringify(decodedToken)); // console.log("==== username from cookies ====", d); // username = d.username; // } // send uid from client const uid = req.body.uid; if (!uid) { res.status(401).send("Unauthorized"); return; } let username = ""; const bytes = CryptoJS.AES.decrypt(uid, secretKey); const decrypted = bytes.toString(CryptoJS.enc.Utf8); username = decrypted; // create body for admin token let body = { client_id: clientId, client_secret: clientSecret, grant_type: "client_credentials", }; const postData = querystring.stringify(body); // get admin token const response = await axios.post(urlKeycloakToken, postData, { headers: { "Content-Type": "application/x-www-form-urlencoded", }, }); // console.log("==== admin token ===="); const adminToken = response.data.access_token; // console.log(adminToken); // create body for user token let body2 = { client_id: clientId, client_secret: clientSecret, grant_type: "urn:ietf:params:oauth:grant-type:token-exchange", subject_token: adminToken, requested_token_type: "urn:ietf:params:oauth:token-type:refresh_token", audience: clientId, requested_subject: username, }; const postData2 = querystring.stringify(body2); // get token for user const tokenResponse = await axios.post(urlKeycloakToken, postData2, { headers: { "Content-Type": "application/x-www-form-urlencoded", }, }); // console.log("==== user token ===="); // console.log(tokenResponse.data); // await postLog('เข้าสู่ระบบ', tokenResponse.data.access_token); // res.cookie('oldssotoken', tokenSSO, { // maxAge: 1000 * 60 * 60 * 24, // กำหนด timeout หน่วยเป็น millisecond // path: "/", // httpOnly: true, // }); res.status(200).send(tokenResponse.data); } catch (error) { res.status(500).send(error); } } else { res.status(403).json({ error: 'Forbidden: Origin not allowed' }); } }) console.log("Start BMA SSO Simulator at port " + port); app.listen(port);