azure auth WIP

This commit is contained in:
Jan Prochazka
2024-08-02 14:32:28 +02:00
parent f777530b1c
commit fc448ed578
10 changed files with 91 additions and 20 deletions

View File

@@ -16,6 +16,7 @@ const { safeJsonParse, getLogger } = require('dbgate-tools');
const platformInfo = require('../utility/platformInfo'); const platformInfo = require('../utility/platformInfo');
const { connectionHasPermission, testConnectionPermission } = require('../utility/hasPermission'); const { connectionHasPermission, testConnectionPermission } = require('../utility/hasPermission');
const pipeForkLogs = require('../utility/pipeForkLogs'); const pipeForkLogs = require('../utility/pipeForkLogs');
const requireEngineDriver = require('../utility/requireEngineDriver');
const logger = getLogger('connections'); const logger = getLogger('connections');
@@ -379,4 +380,16 @@ module.exports = {
}); });
return res; return res;
}, },
dblogin_meta: {
raw: true,
method: 'get',
},
async dblogin(req, res) {
const { conid } = req.query;
const connection = await this.getCore({ conid });
const driver = requireEngineDriver(connection);
const authUrl = driver.getRedirectAuthUrl(connection);
res.redirect(authUrl);
},
}; };

View File

@@ -89,6 +89,9 @@ module.exports = {
if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') { if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') {
throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode }); throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode });
} }
if (connection.useRedirectDbLogin) {
throw new MissingCredentialsError({ conid, redirectToDbLogin: true });
}
const subprocess = fork( const subprocess = fork(
global['API_PACKAGE'] || process.argv[1], global['API_PACKAGE'] || process.argv[1],
[ [

View File

@@ -149,6 +149,7 @@ export interface EngineDriver {
summaryCommand(pool, command, row): Promise<void>; summaryCommand(pool, command, row): Promise<void>;
startProfiler(pool, options): Promise<any>; startProfiler(pool, options): Promise<any>;
stopProfiler(pool, profiler): Promise<void>; stopProfiler(pool, profiler): Promise<void>;
getRedirectAuthUrl(connection): Promise<string>;
analyserClass?: any; analyserClass?: any;
dumperClass?: any; dumperClass?: any;

View File

@@ -31,7 +31,8 @@
$: showConnectionFieldArgs = { config: $config }; $: showConnectionFieldArgs = { config: $config };
$: showUser = driver?.showConnectionField('user', $values, showConnectionFieldArgs) && $values.passwordMode != 'askUser'; $: showUser =
driver?.showConnectionField('user', $values, showConnectionFieldArgs) && $values.passwordMode != 'askUser';
$: showPassword = $: showPassword =
driver?.showConnectionField('password', $values, showConnectionFieldArgs) && driver?.showConnectionField('password', $values, showConnectionFieldArgs) &&
$values.passwordMode != 'askPassword' && $values.passwordMode != 'askPassword' &&
@@ -83,6 +84,7 @@
{/if} {/if}
{#if $authTypes && driver?.showConnectionField('authType', $values, showConnectionFieldArgs)} {#if $authTypes && driver?.showConnectionField('authType', $values, showConnectionFieldArgs)}
{#key $authTypes}
<FormSelectField <FormSelectField
label={driver?.authTypeLabel ?? 'Authentication'} label={driver?.authTypeLabel ?? 'Authentication'}
name="authType" name="authType"
@@ -94,6 +96,7 @@
label: auth.title, label: auth.title,
}))} }))}
/> />
{/key}
{/if} {/if}
{#if driver?.showConnectionField('clientLibraryPath', $values, showConnectionFieldArgs)} {#if driver?.showConnectionField('clientLibraryPath', $values, showConnectionFieldArgs)}

View File

@@ -9,6 +9,7 @@ import { showModal } from '../modals/modalTools';
import DatabaseLoginModal, { isDatabaseLoginVisible } from '../modals/DatabaseLoginModal.svelte'; import DatabaseLoginModal, { isDatabaseLoginVisible } from '../modals/DatabaseLoginModal.svelte';
import _ from 'lodash'; import _ from 'lodash';
import uuidv1 from 'uuid/v1'; import uuidv1 from 'uuid/v1';
import { openWebLink } from './exportFileTools';
export const strmid = uuidv1(); export const strmid = uuidv1();
@@ -63,7 +64,9 @@ function processApiResponse(route, args, resp) {
// } // }
if (resp?.missingCredentials) { if (resp?.missingCredentials) {
if (!isDatabaseLoginVisible()) { if (resp.detail.redirectToDbLogin) {
openWebLink('connections/dblogin');
} else if (!isDatabaseLoginVisible()) {
showModal(DatabaseLoginModal, resp.detail); showModal(DatabaseLoginModal, resp.detail);
} }
return null; return null;

View File

@@ -31,12 +31,13 @@
"plugout": "dbgate-plugout dbgate-plugin-mssql" "plugout": "dbgate-plugout dbgate-plugin-mssql"
}, },
"devDependencies": { "devDependencies": {
"async-lock": "^1.2.6",
"@azure/msal-node": "^2.12.0",
"dbgate-plugin-tools": "^1.0.7", "dbgate-plugin-tools": "^1.0.7",
"dbgate-query-splitter": "^4.10.1", "dbgate-query-splitter": "^4.10.1",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4",
"dbgate-tools": "^5.0.0-alpha.1", "dbgate-tools": "^5.0.0-alpha.1",
"tedious": "^18.2.0", "tedious": "^18.2.0",
"async-lock": "^1.2.6" "webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
} }
} }

View File

@@ -0,0 +1,12 @@
function getAzureAuthTypes(platformInfo) {
return null;
}
async function azureGetRedirectAuthUrl(connection) {
return null;
}
module.exports = {
getAzureAuthTypes,
azureGetRedirectAuthUrl,
};

View File

@@ -8,8 +8,11 @@ const AsyncLock = require('async-lock');
const nativeDriver = require('./nativeDriver'); const nativeDriver = require('./nativeDriver');
const lock = new AsyncLock(); const lock = new AsyncLock();
const { tediousConnect, tediousQueryCore, tediousReadQuery, tediousStream } = require('./tediousDriver'); const { tediousConnect, tediousQueryCore, tediousReadQuery, tediousStream } = require('./tediousDriver');
const { getAzureAuthTypes } = require('./azureAuth');
const { nativeConnect, nativeQueryCore, nativeReadQuery, nativeStream } = nativeDriver; const { nativeConnect, nativeQueryCore, nativeReadQuery, nativeStream } = nativeDriver;
let requireMsnodesqlv8; let requireMsnodesqlv8;
let platformInfo;
const versionQuery = ` const versionQuery = `
SELECT SELECT
@@ -52,7 +55,14 @@ const driver = {
analyserClass: MsSqlAnalyser, analyserClass: MsSqlAnalyser,
getAuthTypes() { getAuthTypes() {
return requireMsnodesqlv8 ? windowsAuthTypes : null; const res = [];
if (requireMsnodesqlv8) res.push(...windowsAuthTypes);
const azureAuthTypes = getAzureAuthTypes(platformInfo);
if (azureAuthTypes) res.push(...azureAuthTypes);
if (res.length > 0) {
return _.uniqBy(res, 'name');
}
return null;
}, },
async connect(conn) { async connect(conn) {
@@ -115,12 +125,16 @@ const driver = {
const { rows } = await this.query(pool, 'SELECT name FROM sys.databases order by name'); const { rows } = await this.query(pool, 'SELECT name FROM sys.databases order by name');
return rows; return rows;
}, },
getRedirectAuthUrl(connection) {
return azureGetRedirectAuthUrl(connection);
}
}; };
driver.initialize = dbgateEnv => { driver.initialize = dbgateEnv => {
if (dbgateEnv.nativeModules && dbgateEnv.nativeModules.msnodesqlv8) { if (dbgateEnv.nativeModules && dbgateEnv.nativeModules.msnodesqlv8) {
requireMsnodesqlv8 = dbgateEnv.nativeModules.msnodesqlv8; requireMsnodesqlv8 = dbgateEnv.nativeModules.msnodesqlv8;
} }
platformInfo = dbgateEnv.platformInfo;
nativeDriver.initialize(dbgateEnv); nativeDriver.initialize(dbgateEnv);
}; };

View File

@@ -130,7 +130,7 @@ const driver = {
field field
) || ) ||
(field == 'trustServerCertificate' && values.authType != 'sql' && values.authType != 'sspi') || (field == 'trustServerCertificate' && values.authType != 'sql' && values.authType != 'sspi') ||
(field == 'windowsDomain' && values.authType != 'sql' && values.authType != 'sspi'), (field == 'windowsDomain' && values.authType != 'sql' && values.authType != 'sspi' && values.authType != 'msentra'),
// (field == 'useDatabaseUrl' && values.authType != 'sql' && values.authType != 'sspi') // (field == 'useDatabaseUrl' && values.authType != 'sql' && values.authType != 'sspi')
getQuerySplitterOptions: usage => getQuerySplitterOptions: usage =>
usage == 'editor' usage == 'editor'
@@ -154,6 +154,13 @@ const driver = {
}, },
]; ];
}, },
beforeConnectionSave: connection => {
return {
...connection,
useRedirectDbLogin: connection.authType == 'msentra' ? 1 : 0,
};
},
}; };
module.exports = driver; module.exports = driver;

View File

@@ -164,6 +164,20 @@
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-14.10.0.tgz#215449726717b53d549953db77562cad6cb8421c" resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-14.10.0.tgz#215449726717b53d549953db77562cad6cb8421c"
integrity sha512-Zk6DPDz7e1wPgLoLgAp0349Yay9RvcjPM5We/ehuenDNsz/t9QEFI7tRoHpp/e47I4p20XE3FiDlhKwAo3utDA== integrity sha512-Zk6DPDz7e1wPgLoLgAp0349Yay9RvcjPM5We/ehuenDNsz/t9QEFI7tRoHpp/e47I4p20XE3FiDlhKwAo3utDA==
"@azure/msal-common@14.14.0":
version "14.14.0"
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-14.14.0.tgz#31a015070d5864ebcf9ebb988fcbc5c5536f22d1"
integrity sha512-OxcOk9H1/1fktHh6//VCORgSNJc2dCQObTm6JNmL824Z6iZSO6eFo/Bttxe0hETn9B+cr7gDouTQtsRq3YPuSQ==
"@azure/msal-node@^2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-2.12.0.tgz#57ee6b6011a320046d72dc0828fec46278f2ab2c"
integrity sha512-jmk5Im5KujRA2AcyCb0awA3buV8niSrwXZs+NBJWIvxOz76RvNlusGIqi43A0h45BPUy93Qb+CPdpJn82NFTIg==
dependencies:
"@azure/msal-common" "14.14.0"
jsonwebtoken "^9.0.0"
uuid "^8.3.0"
"@azure/msal-node@^2.5.1": "@azure/msal-node@^2.5.1":
version "2.8.0" version "2.8.0"
resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-2.8.0.tgz#ef6e4a76bcd0851f7b1240d94b00fe1f9a52d559" resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-2.8.0.tgz#ef6e4a76bcd0851f7b1240d94b00fe1f9a52d559"