//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"); 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 cookieName = process.env.SSO_COOKIE_NAME || "ssotoken"; const privateKey = fs.readFileSync(`${process.cwd()}/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(); app.use(cors({ origin: "*", credentials: true, })); app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.use(cookieParser()); app.post("/signin", async (req, res) => { 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); // console.log("formdata===>", formdata); const response = await axios.post(urlKeycloakToken, formdata, { headers: { "Content-Type": "application/x-www-form-urlencoded", }, }); if (response.data) { 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.sendStatus(200); } else { res.status(401).send("Incorrect user or password"); } } catch (error) { res.status(500).send("Incorrect user or password!"); } }); // kcauth const useBMA = Boolean(process.env.USE_BMA) || false; const publicKeyLanding = fs.readFileSync(`${process.cwd()}/BMA.pub.pem`, "utf8"); const clientSecret = process.env.KC_CLIENT_SECRET; const clientId = process.env.KC_CLIENT_ID; app.post("/kcauth", async (req, res) => { try { const cookies = req.cookies; const tokenSSO = cookies[cookieName]; 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); const username = d.username; // 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); // console.log("==== postData2 ===="); // console.log(body2); // get admin token 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.status(200).send(tokenResponse.data); } catch (error) { // console.log("error===>", error); res.status(401).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); app.listen(port);