diff --git a/core/src/commands/logout.ts b/core/src/commands/logout.ts index bf24512d82..a18ded7095 100644 --- a/core/src/commands/logout.ts +++ b/core/src/commands/logout.ts @@ -9,6 +9,7 @@ import { Command, CommandParams, CommandResult } from "./base" import { printHeader } from "../logger/util" import dedent = require("dedent") +import { logout } from "../enterprise/auth" export class LogOutCommand extends Command { name = "logout" @@ -32,7 +33,7 @@ export class LogOutCommand extends Command { log.debug({ msg: `Logging out of ${garden.enterpriseApi?.getDomain()}` }) log.info({ msg: `Logging out of Garden Enterprise.` }) try { - await garden.enterpriseApi.logout() + await logout(garden.enterpriseApi, log) log.info({ msg: `Succesfully logged out from Garden Enterprise.` }) } catch (error) { log.error(error) diff --git a/core/src/enterprise/api.ts b/core/src/enterprise/api.ts index 1243c531cf..a1549f148e 100644 --- a/core/src/enterprise/api.ts +++ b/core/src/enterprise/api.ts @@ -70,19 +70,38 @@ export class EnterpriseApi { return } this.enterpriseDomain = enterpriseDomain + + // Retrieve an authentication token const authToken = await this.readAuthToken() if (authToken && commandAllowed) { - this.log.debug({ msg: `Refreshing auth token and starting refresh interval.` }) + // Verify a valid token is present + this.log.debug({ msg: `Refreshing auth token and trying to start refresh interval.` }) const tokenIsValid = await this.checkClientAuthToken(this.log) + if (!tokenIsValid) { - await this.refreshToken() + // If the token is an Access Token and it's invalid we return. + if (gardenEnv.GARDEN_AUTH_TOKEN) { + this.log.error({ + msg: + "The provided access token is expired or revoked, please create a new one from the Garden Enterprise UI.", + }) + return + } else { + // Try to refresh an expired JWT + // This will throw if it fails to refresh + await this.refreshToken() + } } // At this point we can be sure the user is logged in because we have // a valid token or refreshing the token did not go through. // TODO: Refactor to make a bit more robust (cc @emanuele and @thsig, you // know what I'm talking about.) this.isUserLoggedIn = true - this.startInterval() + // Start refresh interval if using JWT + if (!gardenEnv.GARDEN_AUTH_TOKEN) { + this.log.debug({ msg: `Starting refresh interval.` }) + this.startInterval() + } } } @@ -90,7 +109,8 @@ export class EnterpriseApi { this.log.debug({ msg: `Will run refresh function every ${this.intervalMsec} ms.` }) this.intervalId = setInterval(() => { this.refreshToken().catch((err) => { - this.log.debug(err) + this.log.debug({ msg: "Something went wrong while trying to refresh the authentication token." }) + this.log.debug({ msg: err.message }) }) }, this.intervalMsec) } @@ -106,9 +126,11 @@ export class EnterpriseApi { const invalidCredentialsErrorMsg = "Your Garden Enteprise credentials have expired. Please login again." const token = await ClientAuthToken.findOne() - if (!token) { - throw new RuntimeError(invalidCredentialsErrorMsg, {}) + if (!token || gardenEnv.GARDEN_AUTH_TOKEN) { + this.log.debug({ msg: "Nothing to refresh, returning." }) + return } + if (isAfter(new Date(), sub(token.validity, { seconds: refreshThreshold }))) { try { const res = await this.get(this.log, "token/refresh", { @@ -207,26 +229,6 @@ export class EnterpriseApi { return token } - async logout() { - const token = await ClientAuthToken.findOne() - if (!token) { - // Noop when the user is not logged in - return - } - try { - await this.post(this.log, "token/logout", { - headers: { - Cookie: `rt=${token?.refreshToken}`, - }, - }) - - await this.clearAuthToken() - } catch (error) { - this.log.error({ msg: "An error occurred while logging out." }) - this.log.debug({ msg: JSON.stringify(error, null, 2) }) - } - } - /** * If a persisted client auth token exists, deletes it. */ diff --git a/core/src/enterprise/auth.ts b/core/src/enterprise/auth.ts index 42911a3dc4..2f7e276cc1 100644 --- a/core/src/enterprise/auth.ts +++ b/core/src/enterprise/auth.ts @@ -16,6 +16,8 @@ import getPort = require("get-port") import { LogEntry } from "../logger/log-entry" import { InternalError } from "../exceptions" import { EnterpriseApi, AuthTokenResponse } from "./api" +import { ClientAuthToken } from "../db/entities/client-auth-token" +import { gardenEnv } from "../constants" /** * Logs in to Garden Enterprise if needed, and returns a valid client auth token. @@ -55,13 +57,22 @@ export async function login(enterpriseApi: EnterpriseApi, log: LogEntry): Promis } export async function logout(enterpriseApi: EnterpriseApi, log: LogEntry): Promise { - const savedToken = await enterpriseApi.readAuthToken() - // Ping platform with saved token (if it exists) - if (savedToken) { - log.debug("Local client auth token found, verifying it with platform...") - if (await enterpriseApi.checkClientAuthToken(log)) { - log.debug("Local client token is valid, no need for login.") - } + const token = await ClientAuthToken.findOne() + if (!token || gardenEnv.GARDEN_AUTH_TOKEN) { + // Noop when the user is not logged in or an access token is in use + return + } + try { + await enterpriseApi.post(log, "token/logout", { + headers: { + Cookie: `rt=${token?.refreshToken}`, + }, + }) + + await enterpriseApi.clearAuthToken() + } catch (error) { + log.error({ msg: "An error occurred while logging out." }) + log.debug({ msg: JSON.stringify(error, null, 2) }) } }