Skip to content

Commit

Permalink
Merge pull request #34 from fractal-analytics-platform/fix-user-folde…
Browse files Browse the repository at this point in the history
…rs-auth

Fix broken AUTHORIZATION_SCHEME=user-folders
  • Loading branch information
zonia3000 authored Sep 30, 2024
2 parents 43cf609 + 3e1a948 commit 2945eaa
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Note: Numbers like (#123) point to closed Pull Requests on the fractal-vizarr-viewer repository.

# Unreleased

* Fix broken `AUTHORIZATION_SCHEME=user-folders` (\#34);

# 0.1.3

* Updated documentation (\#29);
Expand Down
51 changes: 43 additions & 8 deletions src/authorizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Request } from 'express';
import { caching } from 'cache-manager';
import { getConfig } from './config.js';
import { getLogger } from "./logger.js";
import { User } from "./types";
import { User, UserSettings } from "./types";

const config = getConfig();
const logger = getLogger();
Expand All @@ -14,9 +14,14 @@ const cookiesCache = await caching('memory', {
ttl: config.cacheExpirationTime * 1000 // milliseconds
});

const settingsCache = await caching('memory', {
ttl: config.cacheExpirationTime * 1000 // milliseconds
});

// Track the cookies for which we are retrieving the user info from fractal-server
// Used to avoid querying the cache while the fetch call is in progress
let loadingCookies: string[] = [];
let loadingSettings: string[] = [];

/**
* Returns the class that performs the authorization logic.
Expand Down Expand Up @@ -47,7 +52,8 @@ abstract class BaseAuthorizer {
return;
}
const user = await this.getUserFromCookie(req);
if (!this.isUserAuthorized(completePath, user)) {
const authorized = await this.isUserAuthorized(completePath, user, req.get('Cookie'));
if (!authorized) {
return undefined;
}
logger.trace("Path to load: %s", completePath);
Expand Down Expand Up @@ -76,7 +82,7 @@ abstract class BaseAuthorizer {
return result;
}

abstract isUserAuthorized(completePath: string, user: User | undefined): boolean;
abstract isUserAuthorized(completePath: string, user: User | undefined, cookie: string | undefined): Promise<boolean>;

async getUserFromCookie(req: Request): Promise<User | undefined> {
const cookie = req.get('Cookie');
Expand Down Expand Up @@ -117,7 +123,7 @@ abstract class BaseAuthorizer {
}

export class AllowedListAuthorizer extends BaseAuthorizer {
isUserAuthorized(_: string, user: User | undefined): boolean {
async isUserAuthorized(_: string, user: User | undefined): Promise<boolean> {
if (!user) {
return false;
}
Expand All @@ -130,17 +136,46 @@ export class AllowedListAuthorizer extends BaseAuthorizer {
}

export class NoneAuthorizer extends BaseAuthorizer {
isUserAuthorized(): boolean {
async isUserAuthorized(): Promise<boolean> {
return true;
}
}

export class UserFoldersAuthorizer extends BaseAuthorizer {
isUserAuthorized(completePath: string, user: User | undefined): boolean {
if (!user) {
async isUserAuthorized(completePath: string, user: User | undefined, cookie: string | undefined): Promise<boolean> {
if (!user || !cookie) {
return false;
}
const username = user.slurm_user;
while (loadingSettings.includes(cookie)) {
// a fetch call for this cookie is in progress; wait for its completion
await new Promise(r => setTimeout(r));
}
loadingSettings.push(cookie);
let settings: UserSettings | undefined = undefined;
try {
const value: string | undefined = await settingsCache.get(cookie);
if (value) {
settings = JSON.parse(value) as UserSettings;
} else {
logger.trace("Retrieving settings from cookie");
const response = await fetch(`${config.fractalServerUrl}/auth/current-user/settings/`, {
headers: {
'Cookie': cookie
}
});
if (response.ok) {
settings = await response.json() as UserSettings;
logger.trace("Retrieved settings for user %s", user.email);
settingsCache.set(cookie, JSON.stringify(settings));
} else {
logger.debug("Fractal server replied with %d while retrieving settings from cookie", response.status);
return false;
}
}
} finally {
loadingSettings = loadingSettings.filter(c => c !== cookie);
}
const username = settings.slurm_user;
if (!username) {
logger.warn('Slurm user is not defined for "%s"', user.email);
return false;
Expand Down
5 changes: 4 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ export type User = {
is_active: boolean
is_superuser: boolean
is_verified: boolean
username: string | null
}

export type UserSettings = {
slurm_user: string | null
cache_dir: string | null
username: string | null
slurm_accounts: string[]
}

0 comments on commit 2945eaa

Please sign in to comment.