From 23ad2361468c3f704d73a690529d58ce291a6770 Mon Sep 17 00:00:00 2001
From: Damjan Murn <damjan.murn@xlab.si>
Date: Sat, 8 Apr 2023 00:21:19 +0200
Subject: [PATCH] Keycloak integration

---
 .env.development           |  3 ++-
 .env.production            |  1 +
 entrypoint.sh              |  1 +
 package.json               |  3 ++-
 src/main.js                | 50 ++++++++++++++++++++++++++++++++------
 src/services/ApiService.js | 24 ++++++++++--------
 6 files changed, 62 insertions(+), 20 deletions(-)

diff --git a/.env.development b/.env.development
index 544f6c74..4cb25fde 100644
--- a/.env.development
+++ b/.env.development
@@ -1 +1,2 @@
-VUE_APP_API="http://localhost:8080"
\ No newline at end of file
+VUE_APP_API="http://localhost:8080"
+VUE_APP_KEYCLOAK_URL="https://catalogue-keycloak-dev.k8s.medina.esilab.org/auth"
\ No newline at end of file
diff --git a/.env.production b/.env.production
index 58fe7e1d..9cc681bc 100644
--- a/.env.production
+++ b/.env.production
@@ -1 +1,2 @@
 VUE_APP_API="<<CCE_API_URL>>"
+VUE_APP_KEYCLOAK_URL="<<KEYCLOAK_URL>>"
diff --git a/entrypoint.sh b/entrypoint.sh
index 7c3eb90e..d884d569 100644
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -1,5 +1,6 @@
 URL="${CCE_API_URL:-https://cce-api-dev.k8s.medina.esilab.org}"
 
 sed -i "s|<<CCE_API_URL>>|${CCE_API_URL}|g" /usr/share/nginx/html/js/app.*.js
+sed -i "s|<<KEYCLOAK_URL>>|${KEYCLOAK_URL}|g" /usr/share/nginx/html/js/app.*.js
 
 nginx -g 'daemon off;'
diff --git a/package.json b/package.json
index f915868b..07be703a 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,8 @@
     "vue": "^3.2.47",
     "vue-axios": "^3.5.2",
     "vue-router": "^4.1.6",
-    "vuex": "^4.1.0"
+    "vuex": "^4.1.0",
+    "keycloak-js": "^21.0.2"
   },
   "devDependencies": {
     "@babel/eslint-parser": "^7.21.3",
diff --git a/src/main.js b/src/main.js
index 44dab70d..82fcb860 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,21 +1,55 @@
-import { createApp } from "vue";
+import {createApp} from "vue";
 import App from "./App.vue";
 import router from "./router";
 import store from "@/store";
 import axios from "axios";
 import VueAxios from "vue-axios";
+import Keycloak from "keycloak-js";
 
 import BootstrapVueNext from "bootstrap-vue-next";
 import "bootstrap/dist/css/bootstrap.css";
 import "bootstrap-vue-next/dist/bootstrap-vue-next.css";
 
-import { dom } from "@fortawesome/fontawesome-svg-core";
+import {dom} from "@fortawesome/fontawesome-svg-core";
 dom.watch();
 import "@fortawesome/fontawesome-free/css/all.css";
 
-const app = createApp(App);
-app.use(router);
-app.use(store);
-app.use(VueAxios, axios);
-app.use(BootstrapVueNext);
-app.mount("#app");
+let initOptions = {
+    url: process.env.VUE_APP_KEYCLOAK_URL,
+    realm: 'medina',
+    clientId: 'cce-frontend',
+    onLoad: 'login-required'
+}
+
+let keycloak = new Keycloak(initOptions);
+
+keycloak.init({onLoad: initOptions.onLoad}).then((auth) => {
+    if (!auth) {
+        window.location.reload();
+    } else {
+        axios.defaults.headers.common = {
+            'Authorization': 'Bearer ' + keycloak.token
+        };
+
+        const app = createApp(App);
+        app.use(router);
+        app.use(store);
+        app.use(VueAxios, axios);
+        app.use(BootstrapVueNext);
+        app.mount("#app");
+    }
+
+    setInterval(() => {
+        keycloak.updateToken(300).then((refreshed) => {
+            if (!refreshed) {
+                console.warn('Token not refreshed, valid for '
+                    + Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds');
+            }
+        }).catch(() => {
+            console.error('Failed to refresh token')
+        });
+    }, 300 * 1000)
+
+}).catch(() => {
+    console.error("Keycloak authentication failed");
+});
diff --git a/src/services/ApiService.js b/src/services/ApiService.js
index bfad5be9..6c141487 100644
--- a/src/services/ApiService.js
+++ b/src/services/ApiService.js
@@ -1,13 +1,17 @@
-import api from "@/client/client";
+import axios from "axios";
+
+const headers = {
+    "Content-Type": "application/json"
+};
 
 export const ApiService = {
-  getToeList() {
-    return api.get("/toeList");
-  },
-  getToeHistory(toeId) {
-    return api.get("/toes/" + toeId + "/listHistory");
-  },
-  getTreeByStateId(stateId) {
-    return api.get("/history/" + stateId);
-  },
+    getToeList() {
+        return axios.get(process.env.VUE_APP_API + "/toeList", {headers});
+    },
+    getToeHistory(toeId) {
+        return axios.get(process.env.VUE_APP_API + "/toes/" + toeId + "/listHistory", {headers});
+    },
+    getTreeByStateId(stateId) {
+        return axios.get(process.env.VUE_APP_API + "/history/" + stateId, {headers});
+    },
 };
-- 
GitLab