use OIDC without admin api, option to disable anonymous login

This commit is contained in:
Lurkars 2021-10-21 16:28:57 +02:00
parent 14a31d81ea
commit 6832fe4990
9 changed files with 59 additions and 22 deletions

View File

@ -22,6 +22,7 @@ MAX_USERNAME_LENGTH=8
OPID_CLIENT_ID= OPID_CLIENT_ID=
OPID_CLIENT_SECRET= OPID_CLIENT_SECRET=
OPID_CLIENT_ISSUER= 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 # 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= CONTACT_URL=

View File

@ -70,6 +70,7 @@ services:
OPID_CLIENT_ID: $OPID_CLIENT_ID OPID_CLIENT_ID: $OPID_CLIENT_ID
OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET
OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER
DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS
volumes: volumes:
- ./pusher:/usr/src/app - ./pusher:/usr/src/app
labels: labels:

View File

@ -70,6 +70,7 @@ services:
OPID_CLIENT_ID: $OPID_CLIENT_ID OPID_CLIENT_ID: $OPID_CLIENT_ID
OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET
OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER
DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS
volumes: volumes:
- ./pusher:/usr/src/app - ./pusher:/usr/src/app
labels: labels:

View File

@ -42,11 +42,22 @@ class ConnectionManager {
localUserStore.setAuthToken(null); localUserStore.setAuthToken(null);
//TODO fix me to redirect this URL by pusher //TODO fix me to redirect this URL by pusher
if (!this._currentRoom || !this._currentRoom.iframeAuthentication) { if (!this._currentRoom) {
loginSceneVisibleIframeStore.set(false); loginSceneVisibleIframeStore.set(false);
return null; 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("state", state);
redirectUrl.searchParams.append("nonce", nonce); redirectUrl.searchParams.append("nonce", nonce);
redirectUrl.searchParams.append("playUri", this._currentRoom.key); redirectUrl.searchParams.append("playUri", this._currentRoom.key);
@ -204,13 +215,18 @@ class ConnectionManager {
} }
public async anonymousLogin(isBenchmark: boolean = false): Promise<void> { public async anonymousLogin(isBenchmark: boolean = false): Promise<void> {
const data = await Axios.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data); try {
this.localUser = new LocalUser(data.userUuid, []); const data = await Axios.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data);
this.authToken = data.authToken; this.localUser = new LocalUser(data.userUuid, []);
if (!isBenchmark) { this.authToken = data.authToken;
// In benchmark, we don't have a local storage. if (!isBenchmark) {
localUserStore.saveUser(this.localUser); // In benchmark, we don't have a local storage.
localUserStore.setAuthToken(this.authToken); localUserStore.saveUser(this.localUser);
localUserStore.setAuthToken(this.authToken);
}
} catch (error) {
// anonymous login failed (through 403 DISABLE_ANONYMOUS)
this.loadOpenIDScreen();
} }
} }

View File

@ -5,6 +5,7 @@ import { adminApi } from "../Services/AdminApi";
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager"; import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
import { parse } from "query-string"; import { parse } from "query-string";
import { openIDClient } from "../Services/OpenIDClient"; import { openIDClient } from "../Services/OpenIDClient";
import { DISABLE_ANONYMOUS } from "../Enum/EnvironmentVariable";
export interface TokenInterface { export interface TokenInterface {
userUuid: string; userUuid: string;
@ -175,16 +176,21 @@ export class AuthenticateController extends BaseController {
console.warn("Login request was aborted"); console.warn("Login request was aborted");
}); });
const userUuid = v4(); if (DISABLE_ANONYMOUS) {
const authToken = jwtTokenManager.createAuthToken(userUuid); res.writeStatus("403 FORBIDDEN");
res.writeStatus("200 OK"); res.end();
this.addCorsHeaders(res); } else {
res.end( const userUuid = v4();
JSON.stringify({ const authToken = jwtTokenManager.createAuthToken(userUuid);
authToken, res.writeStatus("200 OK");
userUuid, this.addCorsHeaders(res);
}) res.end(
); JSON.stringify({
authToken,
userUuid,
})
);
}
}); });
} }

View File

@ -26,7 +26,7 @@ import { jwtTokenManager, tokenInvalidException } from "../Services/JWTTokenMana
import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi"; import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi";
import { SocketManager, socketManager } from "../Services/SocketManager"; import { SocketManager, socketManager } from "../Services/SocketManager";
import { emitInBatch } from "../Services/IoSocketHelpers"; 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 { Zone } from "_Model/Zone";
import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface"; import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface";
import { v4 } from "uuid"; import { v4 } from "uuid";
@ -175,6 +175,11 @@ export class IoSocketController {
const tokenData = const tokenData =
token && typeof token === "string" ? jwtTokenManager.verifyJWTToken(token) : null; token && typeof token === "string" ? jwtTokenManager.verifyJWTToken(token) : null;
if (DISABLE_ANONYMOUS && !tokenData) {
throw new Error("Expecting token");
}
const userIdentifier = tokenData ? tokenData.identifier : ""; const userIdentifier = tokenData ? tokenData.identifier : "";
let memberTags: string[] = []; let memberTags: string[] = [];

View File

@ -2,9 +2,9 @@ import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js";
import { BaseController } from "./BaseController"; import { BaseController } from "./BaseController";
import { parse } from "query-string"; import { parse } from "query-string";
import { adminApi } from "../Services/AdminApi"; 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 { GameRoomPolicyTypes } from "../Model/PusherRoom";
import { MapDetailsData } from "../Services/AdminApi/MapDetailsData"; import { isMapDetailsData, MapDetailsData } from "../Services/AdminApi/MapDetailsData";
import { socketManager } from "../Services/SocketManager"; import { socketManager } from "../Services/SocketManager";
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager"; import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
import { v4 } from "uuid"; import { v4 } from "uuid";
@ -64,6 +64,7 @@ export class MapController extends BaseController {
tags: [], tags: [],
textures: [], textures: [],
contactPage: undefined, contactPage: undefined,
authenticationMandatory: DISABLE_ANONYMOUS,
} as MapDetailsData) } as MapDetailsData)
); );
@ -87,6 +88,10 @@ export class MapController extends BaseController {
} }
const mapDetails = await adminApi.fetchMapDetails(query.playUri as string, userId); const mapDetails = await adminApi.fetchMapDetails(query.playUri as string, userId);
if (isMapDetailsData(mapDetails) && DISABLE_ANONYMOUS) {
(mapDetails as MapDetailsData).authenticationMandatory = true;
}
res.writeStatus("200 OK"); res.writeStatus("200 OK");
this.addCorsHeaders(res); this.addCorsHeaders(res);
res.end(JSON.stringify(mapDetails)); res.end(JSON.stringify(mapDetails));

View File

@ -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_ID = process.env.OPID_CLIENT_ID || "";
export const OPID_CLIENT_SECRET = process.env.OPID_CLIENT_SECRET || ""; export const OPID_CLIENT_SECRET = process.env.OPID_CLIENT_SECRET || "";
export const OPID_CLIENT_ISSUER = process.env.OPID_CLIENT_ISSUER || ""; 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 { export {
SECRET_KEY, SECRET_KEY,

View File

@ -16,6 +16,7 @@ export const isMapDetailsData = new tg.IsInterface()
tags: tg.isArray(tg.isString), tags: tg.isArray(tg.isString),
textures: tg.isArray(isCharacterTexture), textures: tg.isArray(isCharacterTexture),
contactPage: tg.isUnion(tg.isString, tg.isUndefined), contactPage: tg.isUnion(tg.isString, tg.isUndefined),
authenticationMandatory: tg.isUnion(tg.isBoolean, tg.isUndefined),
}) })
.get(); .get();