diff --git a/packages/api/src/controllers/auth.js b/packages/api/src/controllers/auth.js index b9e6a9aff..fbd359d4d 100644 --- a/packages/api/src/controllers/auth.js +++ b/packages/api/src/controllers/auth.js @@ -28,11 +28,13 @@ function authMiddleware(req, res, next) { if (!shouldAuthorizeApi()) { return next(); } - if (SKIP_AUTH_PATHS.find(x => req.path == getExpressPath(x))) { - return next(); - } + let skipAuth = !!SKIP_AUTH_PATHS.find(x => req.path == getExpressPath(x)); + const authHeader = req.headers.authorization; if (!authHeader) { + if (skipAuth) { + return next(); + } return unauthorizedResponse(req, res, 'missing authorization header'); } const token = authHeader.split(' ')[1]; @@ -41,6 +43,12 @@ function authMiddleware(req, res, next) { req.user = decoded; return next(); } catch (err) { + if (skipAuth) { + return next(); + } + + console.log('Sending invalid token error', err.message); + return unauthorizedResponse(req, res, 'invalid token'); } } @@ -63,6 +71,12 @@ module.exports = { const login = process.env.OAUTH_LOGIN_FIELD ? payload[process.env.OAUTH_LOGIN_FIELD] : 'oauth'; + if ( + process.env.OAUTH_ALLOWED_LOGINS && + !process.env.OAUTH_ALLOWED_LOGINS.split(',').find(x => x.toLowerCase().trim() != login.toLowerCase().trim()) + ) { + return { error: `Username ${login} not allowed to log in` }; + } if (access_token) { return { accessToken: jwt.sign({ login }, tokenSecret, { expiresIn: '1m' }), diff --git a/packages/api/src/controllers/config.js b/packages/api/src/controllers/config.js index f6a3c8bd9..dbfe6ef05 100644 --- a/packages/api/src/controllers/config.js +++ b/packages/api/src/controllers/config.js @@ -28,7 +28,7 @@ module.exports = { get_meta: true, async get(_params, req) { const logins = getLogins(); - const login = logins ? logins.find(x => x.login == (req.auth && req.auth.user)) : null; + const login = req.user ? req.user.login : logins ? logins.find(x => x.login == (req.auth && req.auth.user)) : null; const permissions = login ? login.permissions : process.env.PERMISSIONS; return { @@ -41,6 +41,7 @@ module.exports = { permissions, login, oauth: process.env.OAUTH_AUTH, + oauthLogout: process.env.OAUTH_LOGOUT, isLoginForm: !!process.env.AD_URL || (!!logins && !process.env.BASIC_AUTH), ...currentVersion, }; diff --git a/packages/web/src/clientAuth.ts b/packages/web/src/clientAuth.ts index ac3e1ba3c..367c38819 100644 --- a/packages/web/src/clientAuth.ts +++ b/packages/web/src/clientAuth.ts @@ -21,9 +21,16 @@ export function handleOauthCallback() { code: sentCode, redirectUri: location.origin + location.pathname, }).then(authResp => { - const { accessToken } = authResp; - localStorage.setItem('accessToken', accessToken); - internalRedirectTo('/'); + const { accessToken, error, errorMessage } = authResp; + + if (accessToken) { + console.log('Settings access token from OAUTH'); + localStorage.setItem('accessToken', accessToken); + internalRedirectTo('/'); + } else { + console.log('Error when processing OAUTH callback', error || errorMessage); + internalRedirectTo(`/?page=not-logged&error=${error || errorMessage}`); + } }); return true; diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index b0260cce5..5beb4f8cb 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -36,6 +36,7 @@ import runCommand from './runCommand'; import { openWebLink } from '../utility/exportFileTools'; import { getSettings } from '../utility/metadataLoaders'; import { isMac } from '../utility/common'; +import { internalRedirectTo } from '../clientAuth'; // function themeCommand(theme: ThemeDefinition) { // return { @@ -549,7 +550,20 @@ registerCommand({ name: 'Logout', testEnabled: () => getCurrentConfig()?.login != null, onClick: () => { - window.location.href = 'config/logout'; + const config = getCurrentConfig(); + if (config.oauth) { + localStorage.removeItem('accessToken'); + if (config.oauthLogout) { + window.location.href = config.oauthLogout; + } else { + internalRedirectTo('/?page=not-logged'); + } + } else if (config.isLoginForm) { + localStorage.removeItem('accessToken'); + internalRedirectTo('/?page=not-logged'); + } else { + window.location.href = 'config/logout'; + } }, }); diff --git a/packages/web/src/utility/api.ts b/packages/web/src/utility/api.ts index 2ca869a00..e55c839c5 100644 --- a/packages/web/src/utility/api.ts +++ b/packages/web/src/utility/api.ts @@ -71,10 +71,15 @@ export async function apiCall(route: string, args: {} = undefined) { }); if (resp.status == 401 && !apiDisabled) { + const params = new URLSearchParams(location.search); + disableApi(); console.log('Disabling API', route); - // unauthorized - redirectToLogin(); + if (params.get('page') != 'login' && params.get('page') != 'not-logged') { + // unauthorized + redirectToLogin(); + } + return; } const json = await resp.json();