allow to revoke host tokens from web ui (#511)

* allow to revoke / restore host access from web ui

* refector to what is expected

* remove core.admin check on HostViewPage.tsx

* update core.host.revoke_token description
This commit is contained in:
Luciole authored and GitHub committed 2023-09-29 19:50:14 +02:00
1 parent 838170a9ff
commit e2dea35e02
11 files changed
+120 -10

No files matched your search

@@ -87,6 +87,7 @@ export default class ControlConnection extends BaseConnection {
this.handle(lib.ControllerConfigGetRequest, this.handleControllerConfigGetRequest.bind(this));
this.handle(lib.ControllerConfigSetFieldRequest, this.handleControllerConfigSetFieldRequest.bind(this));
this.handle(lib.ControllerConfigSetPropRequest, this.handleControllerConfigSetPropRequest.bind(this));
this.handle(lib.HostRevokeTokensRequest, this.handleHostRevokeTokensRequest.bind(this));
this.handle(lib.HostListRequest, this.handleHostListRequest.bind(this));
this.handle(lib.HostSetSubscriptionsRequest, this.handleHostSetSubscriptionsRequest.bind(this));
this.handle(lib.HostGenerateTokenRequest, this.handleHostGenerateTokenRequest.bind(this));
@@ -201,6 +202,22 @@ export default class ControlConnection extends BaseConnection {
this._controller.config.setProp(field, prop, value, "control");
}
async handleHostRevokeTokensRequest(request: lib.HostRevokeTokensRequest) {
const host = this._controller.hosts?.get(request.hostId);
if (!host) {
throw new Error(`Unknown host id (${request.hostId})`);
}
host.token_valid_after = Math.floor(Date.now() / 1000);
const hostConnection = this._controller.wsServer.hostConnections.get(request.hostId);
if (hostConnection) {
hostConnection.connector.terminate();
}
this._controller.hostUpdated(host as HostInfo);
}
async handleHostListRequest(): Promise<lib.HostDetails[]> {
let list = [];
for (let host of this._controller.hosts!.values()) {
@@ -211,6 +228,7 @@ export default class ControlConnection extends BaseConnection {
host.id,
this._controller.wsServer.hostConnections.has(host.id),
host.public_address,
host.token_valid_after,
));
}
return list;
+1
View File
@@ -573,6 +573,7 @@ export default class Controller {
host.id,
this.wsServer.hostConnections.has(host.id),
host.public_address === null ? undefined : host.public_address,
host.token_valid_after,
);
for (let controlConnection of this.wsServer.controlConnections.values()) {
@@ -15,6 +15,7 @@ export interface HostInfo {
version: string;
plugins: [number, any][];
public_address: string | undefined;
token_valid_after?: number;
}
/**
@@ -45,6 +46,8 @@ export default class HostConnection extends BaseConnection {
this.plugins = new Map(Object.entries(registerData.plugins));
this._checkPluginVersions();
let currentHostInfo = this._controller.hosts!.get(this._id)
this._controller.hosts!.set(this._id, {
agent: this._agent,
id: this._id,
@@ -52,6 +55,7 @@ export default class HostConnection extends BaseConnection {
version: this._version,
public_address: registerData.publicAddress,
plugins: registerData.plugins,
token_valid_after: currentHostInfo?.token_valid_after,
});
for (let event of ["connect", "drop", "resume", "close"] as const) {
+5
View File
@@ -240,6 +240,11 @@ ${err.stack}`
if ((tokenPayload.host !== undefined ? tokenPayload.host : tokenPayload.slave) !== data.id) {
throw new Error("missmatched host id");
}
let host = this.controller.hosts!.get(data.id);
if (!tokenPayload.iat || tokenPayload.iat < (host?.token_valid_after??0)) {
throw new Error("invalid token");
}
} catch (err: any) {
logger.verbose(`WsServer | authentication failed for ${req.socket.remoteAddress}`);
wsRejectedConnectionsCounter.inc();
+11 -1
View File
@@ -147,12 +147,22 @@ function validateHostToken(req: Request, res: Response, next: any) {
}
try {
jwt.verify(
const tokenPayload = jwt.verify(
token,
Buffer.from(req.app.locals.controller.config.get("controller.auth_secret"), "base64"),
{ audience: "host" }
);
if (typeof tokenPayload === "string") {
throw new Error("unexpected JsonWebToken type");
}
let host = (req.app.locals.controller as Controller).hosts!.get(tokenPayload.host);
if (!host) {
throw new Error("invalid host");
}
if (!tokenPayload.iat || tokenPayload.iat < (host.token_valid_after??0)) {
throw new Error("invalid token");
}
} catch (err) {
res.sendStatus(401);
return;