From 6832fe49901ce28b3413000337a142cc9dae445c Mon Sep 17 00:00:00 2001 From: Lurkars Date: Thu, 21 Oct 2021 16:28:57 +0200 Subject: [PATCH] use OIDC without admin api, option to disable anonymous login --- .env.template | 1 + docker-compose.single-domain.yaml | 1 + docker-compose.yaml | 1 + front/src/Connexion/ConnectionManager.ts | 34 ++++++++++++++----- .../src/Controller/AuthenticateController.ts | 26 ++++++++------ pusher/src/Controller/IoSocketController.ts | 7 +++- pusher/src/Controller/MapController.ts | 9 +++-- pusher/src/Enum/EnvironmentVariable.ts | 1 + .../src/Services/AdminApi/MapDetailsData.ts | 1 + 9 files changed, 59 insertions(+), 22 deletions(-) diff --git a/.env.template b/.env.template index 715ebeec..f511b398 100644 --- a/.env.template +++ b/.env.template @@ -22,6 +22,7 @@ MAX_USERNAME_LENGTH=8 OPID_CLIENT_ID= OPID_CLIENT_SECRET= OPID_CLIENT_ISSUER= +DISABLE_ANONYMOUS= # If you want to have a contact page in your menu, you MUST set CONTACT_URL to the URL of the page that you want CONTACT_URL= \ No newline at end of file diff --git a/docker-compose.single-domain.yaml b/docker-compose.single-domain.yaml index 4e85d702..2e2cab7d 100644 --- a/docker-compose.single-domain.yaml +++ b/docker-compose.single-domain.yaml @@ -70,6 +70,7 @@ services: OPID_CLIENT_ID: $OPID_CLIENT_ID OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER + DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS volumes: - ./pusher:/usr/src/app labels: diff --git a/docker-compose.yaml b/docker-compose.yaml index 4b3904dd..65dcc61f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -70,6 +70,7 @@ services: OPID_CLIENT_ID: $OPID_CLIENT_ID OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER + DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS volumes: - ./pusher:/usr/src/app labels: diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index b346f450..c91e4590 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -42,11 +42,22 @@ class ConnectionManager { localUserStore.setAuthToken(null); //TODO fix me to redirect this URL by pusher - if (!this._currentRoom || !this._currentRoom.iframeAuthentication) { + if (!this._currentRoom) { loginSceneVisibleIframeStore.set(false); return null; } - const redirectUrl = new URL(`${this._currentRoom.iframeAuthentication}`); + + // also allow OIDC login without admin API by using pusher + let redirectUrl: URL; + if (this._currentRoom.iframeAuthentication) { + redirectUrl = new URL(`${this._currentRoom.iframeAuthentication}`); + } else { + // need origin if PUSHER_URL is relative (in Single-Domain-Deployment) + redirectUrl = new URL( + `${PUSHER_URL}/login-screen`, + !PUSHER_URL.startsWith("http:") || !PUSHER_URL.startsWith("https:") ? window.location.origin : undefined + ); + } redirectUrl.searchParams.append("state", state); redirectUrl.searchParams.append("nonce", nonce); redirectUrl.searchParams.append("playUri", this._currentRoom.key); @@ -204,13 +215,18 @@ class ConnectionManager { } public async anonymousLogin(isBenchmark: boolean = false): Promise { - const data = await Axios.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data); - this.localUser = new LocalUser(data.userUuid, []); - this.authToken = data.authToken; - if (!isBenchmark) { - // In benchmark, we don't have a local storage. - localUserStore.saveUser(this.localUser); - localUserStore.setAuthToken(this.authToken); + try { + const data = await Axios.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data); + this.localUser = new LocalUser(data.userUuid, []); + this.authToken = data.authToken; + if (!isBenchmark) { + // In benchmark, we don't have a local storage. + localUserStore.saveUser(this.localUser); + localUserStore.setAuthToken(this.authToken); + } + } catch (error) { + // anonymous login failed (through 403 DISABLE_ANONYMOUS) + this.loadOpenIDScreen(); } } diff --git a/pusher/src/Controller/AuthenticateController.ts b/pusher/src/Controller/AuthenticateController.ts index 972cc102..2dafe065 100644 --- a/pusher/src/Controller/AuthenticateController.ts +++ b/pusher/src/Controller/AuthenticateController.ts @@ -5,6 +5,7 @@ import { adminApi } from "../Services/AdminApi"; import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager"; import { parse } from "query-string"; import { openIDClient } from "../Services/OpenIDClient"; +import { DISABLE_ANONYMOUS } from "../Enum/EnvironmentVariable"; export interface TokenInterface { userUuid: string; @@ -175,16 +176,21 @@ export class AuthenticateController extends BaseController { console.warn("Login request was aborted"); }); - const userUuid = v4(); - const authToken = jwtTokenManager.createAuthToken(userUuid); - res.writeStatus("200 OK"); - this.addCorsHeaders(res); - res.end( - JSON.stringify({ - authToken, - userUuid, - }) - ); + if (DISABLE_ANONYMOUS) { + res.writeStatus("403 FORBIDDEN"); + res.end(); + } else { + const userUuid = v4(); + const authToken = jwtTokenManager.createAuthToken(userUuid); + res.writeStatus("200 OK"); + this.addCorsHeaders(res); + res.end( + JSON.stringify({ + authToken, + userUuid, + }) + ); + } }); } diff --git a/pusher/src/Controller/IoSocketController.ts b/pusher/src/Controller/IoSocketController.ts index 0466100c..500f4142 100644 --- a/pusher/src/Controller/IoSocketController.ts +++ b/pusher/src/Controller/IoSocketController.ts @@ -26,7 +26,7 @@ import { jwtTokenManager, tokenInvalidException } from "../Services/JWTTokenMana import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi"; import { SocketManager, socketManager } from "../Services/SocketManager"; import { emitInBatch } from "../Services/IoSocketHelpers"; -import { ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable"; +import { ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER, DISABLE_ANONYMOUS } from "../Enum/EnvironmentVariable"; import { Zone } from "_Model/Zone"; import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface"; import { v4 } from "uuid"; @@ -175,6 +175,11 @@ export class IoSocketController { const tokenData = token && typeof token === "string" ? jwtTokenManager.verifyJWTToken(token) : null; + + if (DISABLE_ANONYMOUS && !tokenData) { + throw new Error("Expecting token"); + } + const userIdentifier = tokenData ? tokenData.identifier : ""; let memberTags: string[] = []; diff --git a/pusher/src/Controller/MapController.ts b/pusher/src/Controller/MapController.ts index f775b50c..437bac6a 100644 --- a/pusher/src/Controller/MapController.ts +++ b/pusher/src/Controller/MapController.ts @@ -2,9 +2,9 @@ import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js"; import { BaseController } from "./BaseController"; import { parse } from "query-string"; import { adminApi } from "../Services/AdminApi"; -import { ADMIN_API_URL } from "../Enum/EnvironmentVariable"; +import { ADMIN_API_URL, DISABLE_ANONYMOUS } from "../Enum/EnvironmentVariable"; import { GameRoomPolicyTypes } from "../Model/PusherRoom"; -import { MapDetailsData } from "../Services/AdminApi/MapDetailsData"; +import { isMapDetailsData, MapDetailsData } from "../Services/AdminApi/MapDetailsData"; import { socketManager } from "../Services/SocketManager"; import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager"; import { v4 } from "uuid"; @@ -64,6 +64,7 @@ export class MapController extends BaseController { tags: [], textures: [], contactPage: undefined, + authenticationMandatory: DISABLE_ANONYMOUS, } as MapDetailsData) ); @@ -87,6 +88,10 @@ export class MapController extends BaseController { } const mapDetails = await adminApi.fetchMapDetails(query.playUri as string, userId); + if (isMapDetailsData(mapDetails) && DISABLE_ANONYMOUS) { + (mapDetails as MapDetailsData).authenticationMandatory = true; + } + res.writeStatus("200 OK"); this.addCorsHeaders(res); res.end(JSON.stringify(mapDetails)); diff --git a/pusher/src/Enum/EnvironmentVariable.ts b/pusher/src/Enum/EnvironmentVariable.ts index ab1ce110..be81871d 100644 --- a/pusher/src/Enum/EnvironmentVariable.ts +++ b/pusher/src/Enum/EnvironmentVariable.ts @@ -15,6 +15,7 @@ export const FRONT_URL = process.env.FRONT_URL || "http://localhost"; export const OPID_CLIENT_ID = process.env.OPID_CLIENT_ID || ""; export const OPID_CLIENT_SECRET = process.env.OPID_CLIENT_SECRET || ""; export const OPID_CLIENT_ISSUER = process.env.OPID_CLIENT_ISSUER || ""; +export const DISABLE_ANONYMOUS = process.env.DISABLE_ANONYMOUS ? process.env.DISABLE_ANONYMOUS == "true" : false; export { SECRET_KEY, diff --git a/pusher/src/Services/AdminApi/MapDetailsData.ts b/pusher/src/Services/AdminApi/MapDetailsData.ts index 278b81bb..7a1f57ff 100644 --- a/pusher/src/Services/AdminApi/MapDetailsData.ts +++ b/pusher/src/Services/AdminApi/MapDetailsData.ts @@ -16,6 +16,7 @@ export const isMapDetailsData = new tg.IsInterface() tags: tg.isArray(tg.isString), textures: tg.isArray(isCharacterTexture), contactPage: tg.isUnion(tg.isString, tg.isUndefined), + authenticationMandatory: tg.isUnion(tg.isBoolean, tg.isUndefined), }) .get();