Update sso.js

This commit is contained in:
Warunee Tamkoo 2025-09-12 10:40:48 +07:00
parent 4ab953a07b
commit f3d6e6eb66

180
sso.js
View file

@ -1,6 +1,3 @@
//simulate BMA SSO behavior Authenticator and reverse proxy
//cookie with token is the final product of SSO
require("dotenv").config(); require("dotenv").config();
const cookieParser = require('cookie-parser'); const cookieParser = require('cookie-parser');
const querystring = require("querystring"); const querystring = require("querystring");
@ -11,6 +8,8 @@ const cors = require('cors');
const jwt = require("jsonwebtoken"); const jwt = require("jsonwebtoken");
const fs = require("fs"); const fs = require("fs");
const axios = require("axios"); const axios = require("axios");
const CryptoJS = require("crypto-js");
const secretKey = "uuidSecretKey2025"; // ใช้เป็นคีย์สำหรับเข้ารหัส
const cookieName = process.env.SSO_COOKIE_NAME || "ssotoken"; const cookieName = process.env.SSO_COOKIE_NAME || "ssotoken";
const privateKey = fs.readFileSync(`./BMA`, "utf8"); const privateKey = fs.readFileSync(`./BMA`, "utf8");
@ -26,85 +25,107 @@ const urlKeycloakToken = `${process.env.KC_URL}/realms/${process.env.KC_REALMS}/
const app = express(); const app = express();
// Allow a specific origin and enable credentials // ตั้งค่าการป้องกัน Origin
const corsOptions = { const allowedOrigins = ['http://localhost:3002', 'https://hrmsbkk.case-collection.com']; // อนุญาตเฉพาะ domain ที่กำหนด //http://localhost:3002
origin: 'http://localhost:3002', // Replace with your Vue app's URL
methods: 'GET,POST,PUT,DELETE',
credentials: true, // Enable cookies or Authorization headers
};
app.use(cors(corsOptions)); 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.urlencoded({ extended: true }));
app.use(express.json()); app.use(express.json());
app.use(cookieParser()); 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) => { app.post("/api/v1/sso/signin", async (req, res) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
try {
const login_user = req.body;
try { const formdata = new URLSearchParams();
const login_user = req.body; 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);
const formdata = new URLSearchParams(); await axios.post(urlKeycloakToken, formdata, {
formdata.append("grant_type", "password"); headers: {
formdata.append("client_id", process.env.VITE_CLIENTID_KEYCLOAK); "Content-Type": "application/x-www-form-urlencoded",
formdata.append("username", login_user.username); },
formdata.append("password", login_user.password); }).then(async () => {
const payload = { username: login_user.username };
let token = jwt.sign(payload, privateKey, signOptions);
await axios.post(urlKeycloakToken, formdata, { res.cookie(cookieName, token, {
headers: { maxAge: 1000 * 60 * 60 * 24, // กำหนด timeout หน่วยเป็น millisecond
"Content-Type": "application/x-www-form-urlencoded", path: "/",
}, httpOnly: true,
}).then(() => { });
const payload = { username: login_user.username };
let token = jwt.sign(payload, privateKey, signOptions);
res.cookie(cookieName, token, { const uid = await CryptoJS.AES.encrypt(login_user.username, secretKey).toString();
maxAge: 1000 * 60 * 60 * 24, // กำหนด timeout หน่วยเป็น millisecond res.status(200).send({ uid });
path: "/",
httpOnly: true, }).catch((err) => {
if (err.status) {
res.status(401).send("Incorrect user or password");
} else
res.status(err.status).send(error);
}); });
} catch (error) {
res.sendStatus(200); res.status(500).send(error);
}).catch((err) => { }
if (err.status) { } else {
res.status(401).send("Incorrect user or password"); res.status(403).json({ error: 'Forbidden: Origin not allowed' });
} else
res.status(err.status).send(error);
});
} catch (error) {
res.status(500).send(error);
} }
}); });
app.post("/api/v1/sso/kcauth", async (req, res) => { app.post("/api/v1/sso/kcauth", async (req, res) => {
try { const origin = req.headers.origin;
// kcauth if (allowedOrigins.includes(origin)) {
const useBMA = Boolean(process.env.USE_BMA) || false; try {
const publicKeyLanding = fs.readFileSync(`./BMA.pub.pem`, "utf8"); // kcauth
const clientSecret = process.env.KC_CLIENT_SECRET; // const useBMA = Boolean(process.env.USE_BMA) || false;
const clientId = process.env.KC_CLIENT_ID; // 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 cookies = req.cookies;
const tokenSSO = cookies[cookieName]; // 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;
// }
if (!tokenSSO) { // send uid from client
res.status(401).send("Unauthorized"); const uid = req.body.uid;
return; if (!uid) {
} res.status(401).send("Unauthorized");
return;
const oldssotoken = cookies['oldssotoken'];
if (tokenSSO !== oldssotoken) {
let decodedToken = "";
if (useBMA) {
decodedToken = jwt.decode(tokenSSO);
} else {
decodedToken = jwt.verify(tokenSSO, publicKeyLanding);
} }
let d = JSON.parse(JSON.stringify(decodedToken)); let username = "";
// console.log("==== username from cookies ====", d); const bytes = CryptoJS.AES.decrypt(uid, secretKey);
const username = d.username; const decrypted = bytes.toString(CryptoJS.enc.Utf8);
username = decrypted;
// create body for admin token // create body for admin token
let body = { let body = {
@ -121,6 +142,7 @@ app.post("/api/v1/sso/kcauth", async (req, res) => {
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": "application/x-www-form-urlencoded",
}, },
}); });
// console.log("==== admin token ===="); // console.log("==== admin token ====");
const adminToken = response.data.access_token; const adminToken = response.data.access_token;
// console.log(adminToken); // console.log(adminToken);
@ -137,10 +159,8 @@ app.post("/api/v1/sso/kcauth", async (req, res) => {
}; };
const postData2 = querystring.stringify(body2); const postData2 = querystring.stringify(body2);
// console.log("==== postData2 ====");
// console.log(body2);
// get admin token // get token for user
const tokenResponse = await axios.post(urlKeycloakToken, postData2, { const tokenResponse = await axios.post(urlKeycloakToken, postData2, {
headers: { headers: {
"Content-Type": "application/x-www-form-urlencoded", "Content-Type": "application/x-www-form-urlencoded",
@ -150,29 +170,21 @@ app.post("/api/v1/sso/kcauth", async (req, res) => {
// console.log("==== user token ===="); // console.log("==== user token ====");
// console.log(tokenResponse.data); // console.log(tokenResponse.data);
// await postLog('เข้าสู่ระบบ', tokenResponse.data.access_token); // await postLog('เข้าสู่ระบบ', tokenResponse.data.access_token);
res.cookie('oldssotoken', tokenSSO, { // res.cookie('oldssotoken', tokenSSO, {
maxAge: 1000 * 60 * 60 * 24, // กำหนด timeout หน่วยเป็น millisecond // maxAge: 1000 * 60 * 60 * 24, // กำหนด timeout หน่วยเป็น millisecond
path: "/", // path: "/",
httpOnly: true, // httpOnly: true,
}); // });
res.status(200).send(tokenResponse.data); res.status(200).send(tokenResponse.data);
} else {
res.status(200).send({ isLogin: true }); } catch (error) {
res.status(500).send(error);
} }
} else {
} catch (error) { res.status(403).json({ error: 'Forbidden: Origin not allowed' });
// console.log("error===>", error);
res.status(500).send(error);
} }
}) })
// app.use(express.static(path.join(__dirname, "public-sso")));
// app.get("/", (_req, res) => {
// res.sendFile(`${process.cwd()}/sso.js`);
// });
console.log("Start BMA SSO Simulator at port " + port); console.log("Start BMA SSO Simulator at port " + port);
app.listen(port); app.listen(port);