more robust oauth

This commit is contained in:
Jan Prochazka
2022-11-27 10:43:25 +01:00
parent b1ae7d53b9
commit d84adcca5d
5 changed files with 51 additions and 10 deletions

View File

@@ -28,11 +28,13 @@ function authMiddleware(req, res, next) {
if (!shouldAuthorizeApi()) { if (!shouldAuthorizeApi()) {
return next(); return next();
} }
if (SKIP_AUTH_PATHS.find(x => req.path == getExpressPath(x))) { let skipAuth = !!SKIP_AUTH_PATHS.find(x => req.path == getExpressPath(x));
return next();
}
const authHeader = req.headers.authorization; const authHeader = req.headers.authorization;
if (!authHeader) { if (!authHeader) {
if (skipAuth) {
return next();
}
return unauthorizedResponse(req, res, 'missing authorization header'); return unauthorizedResponse(req, res, 'missing authorization header');
} }
const token = authHeader.split(' ')[1]; const token = authHeader.split(' ')[1];
@@ -41,6 +43,12 @@ function authMiddleware(req, res, next) {
req.user = decoded; req.user = decoded;
return next(); return next();
} catch (err) { } catch (err) {
if (skipAuth) {
return next();
}
console.log('Sending invalid token error', err.message);
return unauthorizedResponse(req, res, 'invalid token'); 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'; 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) { if (access_token) {
return { return {
accessToken: jwt.sign({ login }, tokenSecret, { expiresIn: '1m' }), accessToken: jwt.sign({ login }, tokenSecret, { expiresIn: '1m' }),

View File

@@ -28,7 +28,7 @@ module.exports = {
get_meta: true, get_meta: true,
async get(_params, req) { async get(_params, req) {
const logins = getLogins(); 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; const permissions = login ? login.permissions : process.env.PERMISSIONS;
return { return {
@@ -41,6 +41,7 @@ module.exports = {
permissions, permissions,
login, login,
oauth: process.env.OAUTH_AUTH, oauth: process.env.OAUTH_AUTH,
oauthLogout: process.env.OAUTH_LOGOUT,
isLoginForm: !!process.env.AD_URL || (!!logins && !process.env.BASIC_AUTH), isLoginForm: !!process.env.AD_URL || (!!logins && !process.env.BASIC_AUTH),
...currentVersion, ...currentVersion,
}; };

View File

@@ -21,9 +21,16 @@ export function handleOauthCallback() {
code: sentCode, code: sentCode,
redirectUri: location.origin + location.pathname, redirectUri: location.origin + location.pathname,
}).then(authResp => { }).then(authResp => {
const { accessToken } = authResp; const { accessToken, error, errorMessage } = authResp;
if (accessToken) {
console.log('Settings access token from OAUTH');
localStorage.setItem('accessToken', accessToken); localStorage.setItem('accessToken', accessToken);
internalRedirectTo('/'); internalRedirectTo('/');
} else {
console.log('Error when processing OAUTH callback', error || errorMessage);
internalRedirectTo(`/?page=not-logged&error=${error || errorMessage}`);
}
}); });
return true; return true;

View File

@@ -36,6 +36,7 @@ import runCommand from './runCommand';
import { openWebLink } from '../utility/exportFileTools'; import { openWebLink } from '../utility/exportFileTools';
import { getSettings } from '../utility/metadataLoaders'; import { getSettings } from '../utility/metadataLoaders';
import { isMac } from '../utility/common'; import { isMac } from '../utility/common';
import { internalRedirectTo } from '../clientAuth';
// function themeCommand(theme: ThemeDefinition) { // function themeCommand(theme: ThemeDefinition) {
// return { // return {
@@ -549,7 +550,20 @@ registerCommand({
name: 'Logout', name: 'Logout',
testEnabled: () => getCurrentConfig()?.login != null, testEnabled: () => getCurrentConfig()?.login != null,
onClick: () => { onClick: () => {
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'; window.location.href = 'config/logout';
}
}, },
}); });

View File

@@ -71,11 +71,16 @@ export async function apiCall(route: string, args: {} = undefined) {
}); });
if (resp.status == 401 && !apiDisabled) { if (resp.status == 401 && !apiDisabled) {
const params = new URLSearchParams(location.search);
disableApi(); disableApi();
console.log('Disabling API', route); console.log('Disabling API', route);
if (params.get('page') != 'login' && params.get('page') != 'not-logged') {
// unauthorized // unauthorized
redirectToLogin(); redirectToLogin();
} }
return;
}
const json = await resp.json(); const json = await resp.json();
return processApiResponse(route, args, json); return processApiResponse(route, args, json);