From 97aa563fe7df7a75f6f00a60aa92f2cf21adda09 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Mon, 5 Aug 2024 12:56:43 +0200 Subject: [PATCH] azure auth --- packages/api/src/controllers/connections.js | 21 +++++++++----- .../api/src/proc/serverConnectionProcess.js | 4 +++ packages/api/src/utility/socket.js | 5 +++- packages/web/src/ErrorPage.svelte | 9 +++++- .../web/src/appobj/SubDatabaseList.svelte | 1 + packages/web/src/clientAuth.ts | 18 +++++------- packages/web/src/utility/api.ts | 11 +++++-- packages/web/src/utility/connectionsPinger.js | 3 +- .../src/backend/tediousDriver.js | 29 +++++++++++-------- 9 files changed, 64 insertions(+), 37 deletions(-) diff --git a/packages/api/src/controllers/connections.js b/packages/api/src/controllers/connections.js index 428bb3d6..5a80a972 100644 --- a/packages/api/src/controllers/connections.js +++ b/packages/api/src/controllers/connections.js @@ -252,6 +252,7 @@ module.exports = { accessToken, passwordMode: undefined, unsaved: true, + useRedirectDbLogin: false, }; if (old.passwordMode == 'askUser') { res.user = user; @@ -395,12 +396,18 @@ module.exports = { }, dbloginToken_meta: true, - async dbloginToken({ code, conid, redirectUri }) { - const connection = await this.getCore({ conid }); - const driver = requireEngineDriver(connection); - const accessToken = await driver.getAuthTokenFromCode(connection, { code, redirectUri }); - const volatile = await this.saveVolatile({ conid, accessToken }); - // console.log('******************************** WE HAVE ACCESS TOKEN', accessToken); - socket.emit('got-volatile-token', { savedConId: conid, volatileConId: volatile._id }); + async dbloginToken({ code, conid, strmid, redirectUri }) { + try { + const connection = await this.getCore({ conid }); + const driver = requireEngineDriver(connection); + const accessToken = await driver.getAuthTokenFromCode(connection, { code, redirectUri }); + const volatile = await this.saveVolatile({ conid, accessToken }); + // console.log('******************************** WE HAVE ACCESS TOKEN', accessToken); + socket.emit('got-volatile-token', { strmid, savedConId: conid, volatileConId: volatile._id }); + return { success: true }; + } catch (err) { + logger.error({ err }, 'Error getting DB token'); + return { error: err.message }; + } }, }; diff --git a/packages/api/src/proc/serverConnectionProcess.js b/packages/api/src/proc/serverConnectionProcess.js index 98f88a5e..985363cc 100644 --- a/packages/api/src/proc/serverConnectionProcess.js +++ b/packages/api/src/proc/serverConnectionProcess.js @@ -19,6 +19,7 @@ async function handleRefresh() { const databases = await driver.listDatabases(systemConnection); setStatusName('ok'); const databasesString = stableStringify(databases); + console.log('************* DATABASES *************', databases); if (lastDatabases != databasesString) { process.send({ msgtype: 'databases', databases }); lastDatabases = databasesString; @@ -59,8 +60,11 @@ async function handleConnect(connection) { const driver = requireEngineDriver(storedConnection); try { + console.log('************* CONNECTING *************'); systemConnection = await connectUtility(driver, storedConnection, 'app'); + console.log('************* VERSION *************'); readVersion(); + console.log('************* REFRESH *************'); handleRefresh(); if (extractBoolSettingsValue(globalSettings, 'connection.autoRefresh', false)) { setInterval( diff --git a/packages/api/src/utility/socket.js b/packages/api/src/utility/socket.js index 00c6300b..f81da41d 100644 --- a/packages/api/src/utility/socket.js +++ b/packages/api/src/utility/socket.js @@ -31,6 +31,9 @@ module.exports = { electronSender.send(message, data == null ? null : data); } for (const strmid in sseResponses) { + if (data?.strmid && data?.strmid != strmid) { + continue; + } let skipThisStream = false; if (sseResponses[strmid].filter) { for (const key in sseResponses[strmid].filter) { @@ -47,7 +50,7 @@ module.exports = { } sseResponses[strmid].response?.write( - `event: ${message}\ndata: ${stableStringify(data == null ? null : data)}\n\n` + `event: ${message}\ndata: ${stableStringify(data == null ? null : _.omit(data, ['strmid']))}\n\n` ); } }, diff --git a/packages/web/src/ErrorPage.svelte b/packages/web/src/ErrorPage.svelte index e5e4b9d4..c82b2dfe 100644 --- a/packages/web/src/ErrorPage.svelte +++ b/packages/web/src/ErrorPage.svelte @@ -6,6 +6,9 @@ const config = useConfig(); + const params = new URLSearchParams(location.search); + const error = params.get('error'); + onMount(() => { const removed = document.getElementById('starting_dbgate_zero'); if (removed) removed.remove(); @@ -21,7 +24,11 @@
Configuration error
{#if !$config?.isLicenseValid} - + + {:else if error} + {:else}
diff --git a/packages/web/src/appobj/SubDatabaseList.svelte b/packages/web/src/appobj/SubDatabaseList.svelte index c733007c..d29956f0 100644 --- a/packages/web/src/appobj/SubDatabaseList.svelte +++ b/packages/web/src/appobj/SubDatabaseList.svelte @@ -10,6 +10,7 @@ export let passProps; $: databases = useDatabaseList({ conid: data._id }); + console.log('USED DATABASE LIST', data._id); { - const { accessToken, error, errorMessage } = authResp; - - if (accessToken) { - console.log('Settings access token from OAUTH'); - localStorage.setItem('accessToken', accessToken); - internalRedirectTo('/'); + if (authResp.success) { + window.close(); + } else if (authResp.error) { + internalRedirectTo(`?page=error&error=${encodeURIComponent(authResp)}`); } else { - console.log('Error when processing OAUTH callback', error || errorMessage); - internalRedirectTo(`?page=not-logged&error=${error || errorMessage}`); + internalRedirectTo(`?page=error`); } }); diff --git a/packages/web/src/utility/api.ts b/packages/web/src/utility/api.ts index c9082a6a..be659821 100644 --- a/packages/web/src/utility/api.ts +++ b/packages/web/src/utility/api.ts @@ -10,9 +10,10 @@ import DatabaseLoginModal, { isDatabaseLoginVisible } from '../modals/DatabaseLo import _ from 'lodash'; import uuidv1 from 'uuid/v1'; import { openWebLink } from './exportFileTools'; +import { callServerPing } from './connectionsPinger'; +import { batchDispatchCacheTriggers, dispatchCacheChange } from './cache'; export const strmid = uuidv1(); -const privateApiState = Math.random().toString().substr(2); let eventSource; let apiLogging = false; @@ -66,7 +67,7 @@ function processApiResponse(route, args, resp) { if (resp?.missingCredentials) { if (resp.detail.redirectToDbLogin) { - const state = `dbg-dblogin:${privateApiState}@${resp.detail.conid}`; + const state = `dbg-dblogin:${strmid}:${resp.detail.conid}`; localStorage.setItem('dbloginState', state); openWebLink( `connections/dblogin?conid=${resp.detail.conid}&state=${encodeURIComponent(state)}&redirectUri=${ @@ -224,8 +225,12 @@ export function getVolatileConnections() { } export function installNewVolatileConnectionListener() { - apiOn('got-volatile-token', ({ savedConId, volatileConId }) => { + apiOn('got-volatile-token', async ({ savedConId, volatileConId }) => { + console.log('************************** GOT VOLASTILE TOKEN', savedConId, volatileConId); setVolatileConnectionRemapping(savedConId, volatileConId); + await callServerPing(); + dispatchCacheChange({ key: `server-status-changed` }); + batchDispatchCacheTriggers(x => x.conid == savedConId); }); } diff --git a/packages/web/src/utility/connectionsPinger.js b/packages/web/src/utility/connectionsPinger.js index 978b5df4..ca1209d2 100644 --- a/packages/web/src/utility/connectionsPinger.js +++ b/packages/web/src/utility/connectionsPinger.js @@ -1,7 +1,6 @@ import _ from 'lodash'; -import { openedConnections, currentDatabase, openedConnectionsWithTemporary, getCurrentConfig, getOpenedConnections } from '../stores'; +import { currentDatabase, openedConnectionsWithTemporary, getCurrentConfig, getOpenedConnections } from '../stores'; import { apiCall, getVolatileConnections, strmid } from './api'; -import { getConnectionList } from './metadataLoaders'; import hasPermission from '../utility/hasPermission'; // const doServerPing = async value => { diff --git a/plugins/dbgate-plugin-mssql/src/backend/tediousDriver.js b/plugins/dbgate-plugin-mssql/src/backend/tediousDriver.js index d1efd36d..91bf1fda 100644 --- a/plugins/dbgate-plugin-mssql/src/backend/tediousDriver.js +++ b/plugins/dbgate-plugin-mssql/src/backend/tediousDriver.js @@ -2,6 +2,7 @@ const _ = require('lodash'); const stream = require('stream'); const tedious = require('tedious'); const makeUniqueColumnNames = require('./makeUniqueColumnNames'); +const { getAzureAuthOptions } = require('./azureAuth'); function extractTediousColumns(columns, addDriverNativeColumn = false) { const res = columns.map(col => { @@ -22,10 +23,11 @@ function extractTediousColumns(columns, addDriverNativeColumn = false) { return res; } -async function tediousConnect({ server, port, user, password, database, ssl, trustServerCertificate, windowsDomain }) { +async function tediousConnect(storedConnection) { + const { server, port, user, password, database, ssl, trustServerCertificate, windowsDomain, authType } = storedConnection; return new Promise((resolve, reject) => { const connectionOptions = { - encrypt: !!ssl, + encrypt: !!ssl || authType == 'msentra', cryptoCredentialsDetails: ssl ? _.pick(ssl, ['ca', 'cert', 'key']) : undefined, trustServerCertificate: ssl ? (!ssl.ca && !ssl.cert && !ssl.key ? true : ssl.rejectUnauthorized) : undefined, enableArithAbort: true, @@ -40,18 +42,21 @@ async function tediousConnect({ server, port, user, password, database, ssl, tru connectionOptions.database = database; } + const authentication = + authType == 'msentra' + ? getAzureAuthOptions(storedConnection) + : { + type: windowsDomain ? 'ntlm' : 'default', + options: { + userName: user, + password: password, + ...(windowsDomain ? { domain: windowsDomain } : {}), + }, + }; + const connection = new tedious.Connection({ server, - - authentication: { - type: windowsDomain ? 'ntlm' : 'default', - options: { - userName: user, - password: password, - ...(windowsDomain ? { domain: windowsDomain } : {}), - }, - }, - + authentication, options: connectionOptions, }); connection.on('connect', function (err) {