diff --git a/auth/auth.js b/auth/auth.js index f213bc6..d7437b7 100755 --- a/auth/auth.js +++ b/auth/auth.js @@ -1,42 +1,43 @@ -const express = require("express"); -const cookieParser = require("cookie-parser"); +import express from "express"; +import cookieParser from "cookie-parser"; const app = express(); app.use(express.json()); app.use(cookieParser()); -const PORT = 3000; +const USERS = { "admin":"test123" }; // mocked -// Test-User -const USER = { - username: "admin", - password: "test123" -}; - -// Login -app.post("/api/login", (req, res) => { - const { username, password } = req.body; - - if (username === USER.username && password === USER.password) { - res.cookie("session", "valid", { - httpOnly: true, - sameSite: "Lax", - path: "/" - }); - return res.json({ success: true }); - } - - res.status(401).json({ success: false }); +app.post("/api/login", (req,res)=>{ + const { user, pass } = req.body; + + console.log(`Auth-Service login attempt for ${user}`); + if(USERS[user] && USERS[user] === pass){ + // Set Session Cookie + res.cookie("SESSIONID", "dummy-session-"+user, { + httpOnly: true, + secure: false, // in production: set to true when serving over HTTPS + // domain: ".server.schooltech.ch", // removed for local dev; set in production + sameSite: "Lax", // local dev; use "None" + secure:true for iframe production + path: "/" + }); + res.status(200).send({ ok:true }); + } else { + res.status(401).send({ ok:false }); + } }); -// Auth-Check für späteres Nginx auth_request -app.get("/internal/auth", (req, res) => { - if (req.cookies.session === "valid") { - return res.sendStatus(200); - } - res.sendStatus(401); +// Event logging endpoint for frontend button presses +app.post('/api/event', (req,res)=>{ + const svc = req.body.service || req.body.action || 'unknown'; + const user = req.cookies.SESSIONID || 'anonymous'; + console.log(`Event: user=${user} service=${svc} payload=${JSON.stringify(req.body)}`); + res.status(200).send({ ok:true }); }); -app.listen(PORT, () => { - console.log(`Auth service listening on ${PORT}`); +// Optional für Nginx auth_request +app.get("/internal/auth", (req,res)=>{ + if(req.cookies.SESSIONID) return res.sendStatus(200); + return res.sendStatus(401); }); + +app.listen(3000, ()=>console.log("Auth-Service läuft auf 3000")); diff --git a/auth/package.json b/auth/package.json index 8fa58c8..13f9238 100755 --- a/auth/package.json +++ b/auth/package.json @@ -1,6 +1,7 @@ { "name": "appserver-auth", "version": "1.0.0", + "type": "module", "main": "auth.js", "dependencies": { "express": "^4.19.2", diff --git a/docker-compose.yaml b/docker-compose.yaml index e69de29..07d880a 100755 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -0,0 +1,32 @@ +services: + + + AppServerPortalUI: + image: nginx:alpine + container_name: appServer_PortalUI + volumes: + - /home/chk/Documents/AppServerPortalUI/nginx.conf:/etc/nginx/conf.d/default.conf:ro + - /home/chk/Documents/AppServerPortalUI/public:/usr/share/nginx/html:ro + ports: + - "5080:80" + networks: + - default + restart: unless-stopped + command: ["nginx", "-g", "daemon off;"] + + AppServerAuth: + image: node:18 + container_name: appServer_Auth + volumes: + - /home/chk/Documents/AppServerPortalUI/auth:/usr/src/app + working_dir: /usr/src/app + command: sh -c "npm install && node auth.js" + ports: + - "10300:3000" # optional, für Tests + networks: + - default + restart: unless-stopped + +networks: + default: + \ No newline at end of file diff --git a/nginx.conf b/nginx.conf index bb0f66b..429aace 100755 --- a/nginx.conf +++ b/nginx.conf @@ -1,11 +1,92 @@ +error_log /var/log/nginx/error.log info; + server { - listen 80; - server_name _; + listen 80 default_server; + server_name _; - root /usr/share/nginx/html; - index index.html; + root /usr/share/nginx/html; + index index.html; - location / { - try_files $uri /index.html; - } + location / { + try_files $uri $uri/ /index.html; + } + + # API calls to Auth service inside Docker network + location /api/ { + proxy_pass http://appserverauth:3000/api/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} + +server { + listen 80; + server_name abc.server.schooltech.ch; + + auth_request /nginxauth; + + location / { + proxy_pass https://thinkcentre.local:10010/; + + # WebSocket and HTTPS upstream settings + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_ssl_server_name on; + proxy_ssl_name abc.server.schooltech.ch; + proxy_ssl_verify off; + + proxy_set_header Host abc.server.schooltech.ch; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Origin $http_origin; + + # iFrame erlauben + proxy_hide_header X-Frame-Options; + add_header X-Frame-Options "ALLOWALL"; + proxy_hide_header Content-Security-Policy; + add_header Content-Security-Policy "frame-ancestors *"; + } + + location = /nginxauth { + internal; + proxy_pass http://appserverauth:3000/internal/auth; + proxy_set_header Cookie $http_cookie; + } +} + +server { + listen 80; + server_name xyz.server.schooltech.ch; + + auth_request /nginxauth; + + location / { + proxy_pass http://thinkcentre.local:8080/; + + # WebSocket support + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + proxy_set_header Host xyz.server.schooltech.ch; + proxy_set_header Origin $http_origin; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # iFrame erlauben + proxy_hide_header X-Frame-Options; + add_header X-Frame-Options "ALLOWALL"; + proxy_hide_header Content-Security-Policy; + add_header Content-Security-Policy "frame-ancestors *"; + } + + location = /nginxauth { + internal; + proxy_pass http://appserverauth:3000/internal/auth; + proxy_set_header Cookie $http_cookie; + } } \ No newline at end of file diff --git a/public/app.js b/public/app.js index 8e09ebf..3952995 100755 --- a/public/app.js +++ b/public/app.js @@ -1,35 +1,84 @@ +// ==== app.js ==== + +// Service-Liste const services = [ - { - id: "abc", - name: "Control GamePad", - url: "https://thinkcentre.local:10010/" - }, - { - id: "xyz", - name: "Guacamole", - url: "http://thinkcentre.local:8080/" - } + { id: "abc", name: "Control GamePad", url: "https://abc.server.schooltech.ch" }, + { id: "xyz", name: "Guacamole", url: "https://xyz.server.schooltech.ch" } ]; +// DOM-Elemente +const iframe = document.getElementById("service-frame"); +const loginModal = document.getElementById("login-modal"); +const loginBtn = document.getElementById("login-btn"); +const loginSubmit = document.getElementById("login-submit"); +const loginMsg = document.getElementById("login-msg"); const nav = document.getElementById("services"); -const grid = document.getElementById("service-grid"); -services.forEach(svc => { - // Header Button - const btn = document.createElement("button"); - btn.textContent = svc.name; - btn.onclick = () => go(svc); - nav.appendChild(btn); +let loggedIn = false; - // Card - const card = document.createElement("div"); - card.className = "service-card"; - card.textContent = svc.name; - card.onclick = () => go(svc); - grid.appendChild(card); -}); +// === Login Modal anzeigen === +loginBtn.onclick = () => { + loginModal.style.display = "block"; +}; -function go(service) { - localStorage.setItem("lastService", service.id); - window.location.href = service.url; +// === Login Submit === +loginSubmit.onclick = async () => { + const user = document.getElementById("username").value; + const pass = document.getElementById("password").value; + + try { + const res = await fetch("/api/login", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ user, pass }) + }); + + if (res.ok) { + loggedIn = true; + loginModal.style.display = "none"; + loginMsg.textContent = ""; + setupServiceButtons(); + } else { + loginMsg.textContent = "Login fehlgeschlagen"; + } + } catch (e) { + loginMsg.textContent = "Fehler: " + e.message; + } +}; + +// === Service Buttons dynamisch erstellen === +function setupServiceButtons() { + nav.innerHTML = ""; // clear + services.forEach(svc => { + const btn = document.createElement("button"); + btn.textContent = svc.name; + btn.onclick = async () => { + console.log('Button clicked, opening', svc.id); + try{ + await fetch('/api/event', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ event: 'open', service: svc.id, url: svc.url }) + }); + }catch(e){ console.error('Event log failed', e); } + openService(svc); + }; + nav.appendChild(btn); + }); +} + +// === Service in iFrame öffnen === +function openService(svc) { + iframe.src = svc.url; + iframe.style.display = "block"; + window.scrollTo(0,0); +} + +// Optional: Logout-Funktion +function logout() { + loggedIn = false; + iframe.src = ""; + iframe.style.display = "none"; + nav.innerHTML = ""; + loginModal.style.display = "block"; } diff --git a/public/index.html b/public/index.html index 607ddbf..595009a 100755 --- a/public/index.html +++ b/public/index.html @@ -9,19 +9,28 @@ schooltech - - - - User + + + Login + - Willkommen - Bitte wählen Sie einen Service. + Willkommen im Service Portal - + + + + + + User: + Pass: + Login + + +
Bitte wählen Sie einen Service.