diff --git a/sso.js b/sso.js index eca0d34..30c4fb9 100644 --- a/sso.js +++ b/sso.js @@ -1,6 +1,3 @@ -//simulate BMA SSO behavior Authenticator and reverse proxy -//cookie with token is the final product of SSO - require("dotenv").config(); const cookieParser = require('cookie-parser'); const querystring = require("querystring"); @@ -11,6 +8,8 @@ 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"); @@ -26,85 +25,107 @@ const urlKeycloakToken = `${process.env.KC_URL}/realms/${process.env.KC_REALMS}/ const app = express(); -// Allow a specific origin and enable credentials -const corsOptions = { - origin: 'http://localhost:3002', // Replace with your Vue app's URL - methods: 'GET,POST,PUT,DELETE', - credentials: true, // Enable cookies or Authorization headers -}; +// ตั้งค่าการป้องกัน Origin +const allowedOrigins = ['http://localhost:3002', 'https://hrmsbkk.case-collection.com']; // อนุญาตเฉพาะ domain ที่กำหนด //http://localhost:3002 -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.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; - 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); - 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); - await axios.post(urlKeycloakToken, formdata, { - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - }).then(() => { - 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, + }); - 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); }); - - res.sendStatus(200); - }).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); + } 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) => { - 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 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]; + // 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; + // } - if (!tokenSSO) { - 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); + // send uid from client + const uid = req.body.uid; + if (!uid) { + res.status(401).send("Unauthorized"); + return; } - let d = JSON.parse(JSON.stringify(decodedToken)); - // console.log("==== username from cookies ====", d); - const username = d.username; + 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 = { @@ -121,6 +142,7 @@ app.post("/api/v1/sso/kcauth", async (req, res) => { "Content-Type": "application/x-www-form-urlencoded", }, }); + // console.log("==== admin token ===="); const adminToken = response.data.access_token; // console.log(adminToken); @@ -137,10 +159,8 @@ app.post("/api/v1/sso/kcauth", async (req, res) => { }; 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, { headers: { "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(tokenResponse.data); // await postLog('เข้าสู่ระบบ', tokenResponse.data.access_token); - res.cookie('oldssotoken', tokenSSO, { - maxAge: 1000 * 60 * 60 * 24, // กำหนด timeout หน่วยเป็น millisecond - path: "/", - httpOnly: true, - }); + // res.cookie('oldssotoken', tokenSSO, { + // maxAge: 1000 * 60 * 60 * 24, // กำหนด timeout หน่วยเป็น millisecond + // path: "/", + // httpOnly: true, + // }); res.status(200).send(tokenResponse.data); - } else { - res.status(200).send({ isLogin: true }); + + } catch (error) { + res.status(500).send(error); } - - } catch (error) { - // console.log("error===>", error); - - res.status(500).send(error); + } else { + res.status(403).json({ error: 'Forbidden: Origin not allowed' }); } }) -// 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); app.listen(port); \ No newline at end of file