Skip to content

Commit

Permalink
Clear identity cache when a user re-authenticates with p0 (#126)
Browse files Browse the repository at this point in the history
This PR clears the identity cache on reauth, this helps prevent stale
identities from being assumed. This typically causes problems when
requesting access because the new user is granted access while the old
user identity is used to make the SSH connection which fails.
  • Loading branch information
GGonryun authored Oct 3, 2024
1 parent fe72810 commit a18fac0
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 4 deletions.
23 changes: 22 additions & 1 deletion src/commands/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ This file is part of @p0security/cli
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
**/
import { IDENTITY_FILE_PATH, authenticate } from "../drivers/auth";
import {
IDENTITY_CACHE_PATH,
IDENTITY_FILE_PATH,
authenticate,
loadCredentials,
} from "../drivers/auth";
import { doc, guard } from "../drivers/firestore";
import { print2 } from "../drivers/stdio";
import { pluginLoginMap } from "../plugins/login";
Expand Down Expand Up @@ -40,6 +45,12 @@ export const login = async (
if (!loginFn) throw "Unsupported login for your organization";

const tokenResponse = await loginFn(orgWithSlug);
// if the user changed their org, clear any cached identities this prevents
// commands like `aws assume role` from using the old identities
const currentIdentity = await loadCredentials().catch(() => undefined);
if (currentIdentity?.org.slug !== args.org) {
await clearIdentityCache();
}
await writeIdentity(orgWithSlug, tokenResponse);

// validate auth
Expand Down Expand Up @@ -69,6 +80,16 @@ const writeIdentity = async (org: OrgData, credential: TokenResponse) => {
);
};

const clearIdentityCache = async () => {
try {
// check to see if the directory exists before trying to remove it
await fs.access(IDENTITY_CACHE_PATH);
await fs.rm(IDENTITY_CACHE_PATH, { recursive: true });
} catch {
return;
}
};

export const loginCommand = (yargs: yargs.Argv) =>
yargs.command<{ org: string }>(
"login <org>",
Expand Down
9 changes: 6 additions & 3 deletions src/drivers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,21 @@ import * as fs from "fs/promises";
import * as path from "path";

export const IDENTITY_FILE_PATH = path.join(P0_PATH, "identity.json");
export const IDENTITY_CACHE_PATH = path.join(
path.dirname(IDENTITY_FILE_PATH),
"cache"
);

export const cached = async <T>(
name: string,
loader: () => Promise<T>,
options: { duration: number },
hasExpired?: (data: T) => boolean
): Promise<T> => {
const cachePath = path.join(path.dirname(IDENTITY_FILE_PATH), "cache");
// Following lines sanitize input
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
const loc = path.resolve(path.join(cachePath, `${name}.json`));
if (!loc.startsWith(cachePath)) {
const loc = path.resolve(path.join(IDENTITY_CACHE_PATH, `${name}.json`));
if (!loc.startsWith(IDENTITY_CACHE_PATH)) {
throw new Error("Illegal path traversal");
}

Expand Down

0 comments on commit a18fac0

Please sign in to comment.