diff --git a/packages/api/package.json b/packages/api/package.json index f9f11f2f..5f31f454 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -17,6 +17,7 @@ "dbgate" ], "dependencies": { + "@azure/msal-node": "^2.12.0", "activedirectory2": "^2.1.0", "async-lock": "^1.2.4", "axios": "^0.21.1", diff --git a/packages/api/src/shell/requirePlugin.js b/packages/api/src/shell/requirePlugin.js index 6db3714d..b112cafe 100644 --- a/packages/api/src/shell/requirePlugin.js +++ b/packages/api/src/shell/requirePlugin.js @@ -3,6 +3,7 @@ const fs = require('fs'); const { pluginsdir, packagedPluginsDir, getPluginBackendPath } = require('../utility/directories'); const nativeModules = require('../nativeModules'); const platformInfo = require('../utility/platformInfo'); +const azureAuth = require('../utility/azureAuth'); const { getLogger } = require('dbgate-tools'); const logger = getLogger('requirePlugin'); @@ -12,6 +13,7 @@ const dbgateEnv = { dbgateApi: null, nativeModules, platformInfo, + azureAuth, }; function requirePlugin(packageName, requiredPlugin = null) { if (!packageName) throw new Error('Missing packageName in plugin'); diff --git a/packages/api/src/utility/azureAuth.js b/packages/api/src/utility/azureAuth.js new file mode 100644 index 00000000..f98cd4a7 --- /dev/null +++ b/packages/api/src/utility/azureAuth.js @@ -0,0 +1,17 @@ +function isAzureAuthSupported() { + return false; +} + +async function azureGetRedirectAuthUrl(options) { + return null; +} + +async function azureGetAuthTokenFromCode(options) { + return null; +} + +module.exports = { + isAzureAuthSupported, + azureGetRedirectAuthUrl, + azureGetAuthTokenFromCode, +}; diff --git a/plugins/dbgate-plugin-mssql/package.json b/plugins/dbgate-plugin-mssql/package.json index 47925b83..22e7f1ce 100644 --- a/plugins/dbgate-plugin-mssql/package.json +++ b/plugins/dbgate-plugin-mssql/package.json @@ -32,7 +32,6 @@ }, "devDependencies": { "async-lock": "^1.2.6", - "@azure/msal-node": "^2.12.0", "dbgate-plugin-tools": "^1.0.7", "dbgate-query-splitter": "^4.10.1", "dbgate-tools": "^5.0.0-alpha.1", diff --git a/plugins/dbgate-plugin-mssql/src/backend/azureAuth.js b/plugins/dbgate-plugin-mssql/src/backend/azureAuth.js deleted file mode 100644 index 5ebca70d..00000000 --- a/plugins/dbgate-plugin-mssql/src/backend/azureAuth.js +++ /dev/null @@ -1,22 +0,0 @@ -function getAzureAuthTypes(platformInfo) { - return null; -} - -async function azureGetRedirectAuthUrl(connection) { - return null; -} - -async function azureGetAuthTokenFromCode(connection, code) { - return null; -} - -function getAzureAuthOptions(connection) { - return null; -} - -module.exports = { - getAzureAuthTypes, - azureGetRedirectAuthUrl, - azureGetAuthTokenFromCode, - getAzureAuthOptions, -}; diff --git a/plugins/dbgate-plugin-mssql/src/backend/driver.js b/plugins/dbgate-plugin-mssql/src/backend/driver.js index 1e688254..055890d3 100644 --- a/plugins/dbgate-plugin-mssql/src/backend/driver.js +++ b/plugins/dbgate-plugin-mssql/src/backend/driver.js @@ -8,11 +8,11 @@ const AsyncLock = require('async-lock'); const nativeDriver = require('./nativeDriver'); const lock = new AsyncLock(); const { tediousConnect, tediousQueryCore, tediousReadQuery, tediousStream } = require('./tediousDriver'); -const { getAzureAuthTypes, azureGetRedirectAuthUrl, azureGetAuthTokenFromCode } = require('./azureAuth'); const { nativeConnect, nativeQueryCore, nativeReadQuery, nativeStream } = nativeDriver; let requireMsnodesqlv8; let platformInfo; +let azureAuth; const versionQuery = ` SELECT @@ -57,8 +57,20 @@ const driver = { getAuthTypes() { const res = []; if (requireMsnodesqlv8) res.push(...windowsAuthTypes); - const azureAuthTypes = getAzureAuthTypes(platformInfo); - if (azureAuthTypes) res.push(...azureAuthTypes); + + if (azureAuth.isAzureAuthSupported()) { + res.push( + { + title: 'NodeJs portable driver (tedious) - recomended', + name: 'tedious', + }, + { + title: 'Microsoft Entra ID (with MFA support)', + name: 'msentra', + disabledFields: ['user', 'password'], + } + ); + } if (res.length > 0) { return _.uniqBy(res, 'name'); } @@ -126,10 +138,11 @@ const driver = { return rows; }, getRedirectAuthUrl(connection, options) { - return azureGetRedirectAuthUrl(connection, options); + if (connection.authType != 'msentra') return null; + return azureAuth.azureGetRedirectAuthUrl(options); }, getAuthTokenFromCode(connection, options) { - return azureGetAuthTokenFromCode(connection, options); + return azureAuth.azureGetAuthTokenFromCode(options); }, }; @@ -138,6 +151,7 @@ driver.initialize = dbgateEnv => { requireMsnodesqlv8 = dbgateEnv.nativeModules.msnodesqlv8; } platformInfo = dbgateEnv.platformInfo; + azureAuth = dbgateEnv.azureAuth; nativeDriver.initialize(dbgateEnv); }; diff --git a/plugins/dbgate-plugin-mssql/src/backend/tediousDriver.js b/plugins/dbgate-plugin-mssql/src/backend/tediousDriver.js index 91bf1fda..aff9291f 100644 --- a/plugins/dbgate-plugin-mssql/src/backend/tediousDriver.js +++ b/plugins/dbgate-plugin-mssql/src/backend/tediousDriver.js @@ -2,7 +2,6 @@ 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 => { @@ -24,7 +23,8 @@ function extractTediousColumns(columns, addDriverNativeColumn = false) { } async function tediousConnect(storedConnection) { - const { server, port, user, password, database, ssl, trustServerCertificate, windowsDomain, authType } = storedConnection; + const { server, port, user, password, database, ssl, trustServerCertificate, windowsDomain, authType, accessToken } = + storedConnection; return new Promise((resolve, reject) => { const connectionOptions = { encrypt: !!ssl || authType == 'msentra', @@ -44,7 +44,12 @@ async function tediousConnect(storedConnection) { const authentication = authType == 'msentra' - ? getAzureAuthOptions(storedConnection) + ? { + type: 'azure-active-directory-access-token', + options: { + token: accessToken, + }, + } : { type: windowsDomain ? 'ntlm' : 'default', options: {