oauth working, but cycling sometimes

This commit is contained in:
Jan Prochazka
2022-11-17 12:43:38 +01:00
parent f42d78b2fb
commit 37a8783751
10 changed files with 132 additions and 54 deletions

View File

@@ -1,4 +1,5 @@
DEVMODE=1
OAUTH=http://auth.metrostav.vychozi.cz/auth/realms/metrostav/protocol/openid-connect
OAUTH_AUTH=http://auth.metrostav.vychozi.cz/auth/realms/metrostav/protocol/openid-connect/auth
OAUTH_TOKEN=http://auth.metrostav.vychozi.cz/auth/realms/metrostav/protocol/openid-connect/token
OAUTH_CLIENT_ID=dbgate
OAUTH_CLIENT_SECRET=ffd5634b-b60a-4c3a-bbec-b4144c73ea2a

View File

@@ -42,6 +42,7 @@
"is-electron": "^2.2.1",
"js-yaml": "^4.1.0",
"json-stable-stringify": "^1.0.1",
"jsonwebtoken": "^8.5.1",
"line-reader": "^0.4.0",
"lodash": "^4.17.21",
"ncp": "^2.0.0",

View File

@@ -1,4 +1,39 @@
const axios = require('axios');
const jwt = require('jsonwebtoken');
const getExpressPath = require('../utility/getExpressPath');
const uuidv1 = require('uuid/v1');
const tokenSecret = uuidv1();
function shouldAuthorizeApi() {
return !!process.env.OAUTH_AUTH;
}
function authMiddleware(req, res, next) {
const SKIP_AUTH_PATHS = ['/config/get', '/auth/oauth-token', '/stream'];
if (!shouldAuthorizeApi()) {
return next();
}
if (SKIP_AUTH_PATHS.find(x => req.path == getExpressPath(x))) {
return next();
}
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.send(401, 'missing authorization header');
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, tokenSecret);
req.user = decoded;
return next();
} catch (err) {
console.log('&&&&&&&&&&&&&&&&&&&&&& IUNVALID TOKEN');
console.log(token);
console.log(err);
return res.sendStatus(401).send('Invalid Token');
}
}
module.exports = {
oauthToken_meta: true,
@@ -6,12 +41,25 @@ module.exports = {
const { redirectUri, code } = params;
const resp = await axios.default.post(
`${process.env.OAUTH}/token`,
`${process.env.OAUTH_TOKEN}`,
`grant_type=authorization_code&code=${encodeURIComponent(code)}&redirect_uri=${encodeURIComponent(
redirectUri
)}&client_id=${process.env.OAUTH_CLIENT_ID}&client_secret=${process.env.OAUTH_CLIENT_SECRET}`
);
return resp.data;
const { access_token, refresh_token } = resp.data;
const payload = jwt.decode(access_token);
if (access_token) {
return {
accessToken: jwt.sign({ user: 'oauth' }, tokenSecret, { expiresIn: '1m' }),
};
}
return { error: 'Token not found' };
},
authMiddleware,
shouldAuthorizeApi,
};

View File

@@ -40,7 +40,7 @@ module.exports = {
isDocker: platformInfo.isDocker,
permissions,
login,
oauth: process.env.OAUTH,
oauth: process.env.OAUTH_AUTH,
...currentVersion,
};
},

View File

@@ -54,6 +54,10 @@ function start() {
app.use(cors());
if (auth.shouldAuthorizeApi()) {
app.use(auth.authMiddleware);
}
app.get(getExpressPath('/stream'), async function (req, res) {
res.set({
'Cache-Control': 'no-cache',

View File

@@ -20,38 +20,11 @@
import getElectron from './utility/getElectron';
import AppStartInfo from './widgets/AppStartInfo.svelte';
import SettingsListener from './utility/SettingsListener.svelte';
import { handleAuthOnStartup } from './clientAuth';
let loadedApi = false;
let loadedPlugins = false;
async function handleAuth(config) {
if (config.oauth) {
const params = new URLSearchParams(location.search);
const sentCode = params.get('code');
const sentState = params.get('state');
if (
sentCode &&
sentState &&
sentState.startsWith('dbg-oauth:') &&
sentState == sessionStorage.getItem('oauthState')
) {
const accessToken = await apiCall('auth/oauth-token', {
code: sentCode,
redirectUri: location.origin,
});
console.log('TOKEN', accessToken);
} else {
const state = `dbg-oauth:${Math.random().toString().substr(2)}`;
sessionStorage.setItem('oauthState', state);
location.replace(
`${config.oauth}/auth?client_id=dbgate&response_type=code&redirect_uri=${encodeURIComponent(
location.origin
)}&state=${encodeURIComponent(state)}`
);
}
}
}
async function loadApi() {
// if (shouldWaitForElectronInitialize()) {
// setTimeout(loadApi, 100);
@@ -61,10 +34,11 @@
try {
// console.log('************** LOADING API');
const config = await getConfig();
await handleAuthOnStartup(config);
const connections = await apiCall('connections/list');
const settings = await getSettings();
const config = await getConfig();
handleAuth(config);
const apps = await getUsedApps();
loadedApi = settings && connections && config && apps;

View File

@@ -0,0 +1,46 @@
import { apiCall } from './utility/api';
import { getConfig } from './utility/metadataLoaders';
export async function handleAuthOnStartup(config) {
console.log('********************* handleAuthOnStartup');
if (config.oauth) {
const params = new URLSearchParams(location.search);
const sentCode = params.get('code');
const sentState = params.get('state');
if (
sentCode &&
sentState &&
sentState.startsWith('dbg-oauth:') &&
sentState == sessionStorage.getItem('oauthState')
) {
const authResp = await apiCall('auth/oauth-token', {
code: sentCode,
redirectUri: location.origin,
});
const { accessToken } = authResp;
console.log('Got new access token:', accessToken);
localStorage.setItem('accessToken', accessToken);
location.replace('/');
} else {
if (localStorage.getItem('accessToken')) {
return;
}
redirectToLogin(config);
}
}
}
export async function redirectToLogin(config = null) {
if (!config) config = await getConfig();
const state = `dbg-oauth:${Math.random().toString().substr(2)}`;
sessionStorage.setItem('oauthState', state);
console.log('Redirecting to OAUTH provider');
location.replace(
`${config.oauth}?client_id=dbgate&response_type=code&redirect_uri=${encodeURIComponent(
location.origin
)}&state=${encodeURIComponent(state)}`
);
}

View File

@@ -4,22 +4,6 @@ import './utility/changeCurrentDbByTab';
import './commands/stdCommands';
import localStorageGarbageCollector from './utility/localStorageGarbageCollector';
const params = new URLSearchParams(location.search);
console.log('CODE', params.get('code'));
// console.log(
// `http://auth.metrostav.vychozi.cz/auth/realms/metrostav/protocol/openid-connect/auth?client_id=dbgate&response_type=code&redirect_uri=${encodeURIComponent(
// 'http://localhost:5001/oauth-redirect'
// )}&state=1234`
// );
console.log(location);
// location.replace(
// `http://auth.metrostav.vychozi.cz/auth/realms/metrostav/protocol/openid-connect/auth?client_id=dbgate&response_type=code&redirect_uri=${encodeURIComponent(
// 'http://localhost:5001/'
// )}&state=1234`
// );
localStorageGarbageCollector();
const app = new App({

View File

@@ -4,10 +4,16 @@ import { writable } from 'svelte/store';
import getElectron from './getElectron';
// import socket from './socket';
import { showSnackbarError } from '../utility/snackbar';
import { redirectToLogin } from '../clientAuth';
let eventSource;
let apiLogging = false;
// let cacheCleanerRegistered;
// let apiDisabled = false;
// export function disableApi() {
// apiDisabled = true;
// }
function wantEventSource() {
if (!eventSource) {
@@ -17,9 +23,9 @@ function wantEventSource() {
}
function processApiResponse(route, args, resp) {
if (apiLogging) {
console.log('<<< API RESPONSE', route, args, resp);
}
// if (apiLogging) {
// console.log('<<< API RESPONSE', route, args, resp);
// }
if (resp?.apiErrorMessage) {
showSnackbarError('API error:' + resp?.apiErrorMessage);
@@ -35,6 +41,10 @@ export async function apiCall(route: string, args: {} = undefined) {
if (apiLogging) {
console.log('>>> API CALL', route, args);
}
if (apiDisabled) {
console.log('Error, API disabled!!');
return null;
}
const electron = getElectron();
if (electron) {
@@ -51,6 +61,11 @@ export async function apiCall(route: string, args: {} = undefined) {
body: JSON.stringify(args),
});
if (resp.status == 401) {
// unauthorized
redirectToLogin();
}
const json = await resp.json();
return processApiResponse(route, args, json);
}

View File

@@ -15,5 +15,10 @@ export default function resolveApi() {
export function resolveApiHeaders() {
const electron = getElectron();
return {};
const res = {};
const accessToken = localStorage.getItem('accessToken');
if (accessToken) {
res['Authorization'] = `Bearer ${accessToken}`;
}
return res;
}