mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-03 16:23:58 +00:00
multiauth WIP
This commit is contained in:
@@ -9,6 +9,8 @@ const jwt = require('jsonwebtoken');
|
|||||||
const logger = getLogger('authProvider');
|
const logger = getLogger('authProvider');
|
||||||
|
|
||||||
class AuthProviderBase {
|
class AuthProviderBase {
|
||||||
|
amoid = 'none';
|
||||||
|
|
||||||
async login(login, password, options = undefined) {
|
async login(login, password, options = undefined) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -51,9 +53,17 @@ class AuthProviderBase {
|
|||||||
getSingleConnectionId(req) {
|
getSingleConnectionId(req) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toJson() {
|
||||||
|
return {
|
||||||
|
amoid: this.amoid,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OAuthProvider extends AuthProviderBase {
|
class OAuthProvider extends AuthProviderBase {
|
||||||
|
amoid = 'oauth';
|
||||||
|
|
||||||
shouldAuthorizeApi() {
|
shouldAuthorizeApi() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -120,6 +130,8 @@ class OAuthProvider extends AuthProviderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ADProvider extends AuthProviderBase {
|
class ADProvider extends AuthProviderBase {
|
||||||
|
amoid = 'ad';
|
||||||
|
|
||||||
async login(login, password) {
|
async login(login, password) {
|
||||||
const adConfig = {
|
const adConfig = {
|
||||||
url: process.env.AD_URL,
|
url: process.env.AD_URL,
|
||||||
@@ -157,6 +169,8 @@ class ADProvider extends AuthProviderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class LoginsProvider extends AuthProviderBase {
|
class LoginsProvider extends AuthProviderBase {
|
||||||
|
amoid = 'logins';
|
||||||
|
|
||||||
async login(login, password) {
|
async login(login, password) {
|
||||||
if (password == process.env[`LOGIN_PASSWORD_${login}`]) {
|
if (password == process.env[`LOGIN_PASSWORD_${login}`]) {
|
||||||
return {
|
return {
|
||||||
@@ -176,6 +190,8 @@ class LoginsProvider extends AuthProviderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DenyAllProvider extends AuthProviderBase {
|
class DenyAllProvider extends AuthProviderBase {
|
||||||
|
amoid = 'deny';
|
||||||
|
|
||||||
shouldAuthorizeApi() {
|
shouldAuthorizeApi() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -233,19 +249,37 @@ function createEnvAuthProvider() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let authProvider = createEnvAuthProvider();
|
let defaultAuthProvider = createEnvAuthProvider();
|
||||||
|
let authProviders = [defaultAuthProvider];
|
||||||
|
|
||||||
function getAuthProvider() {
|
function getAuthProviders() {
|
||||||
return authProvider;
|
return authProviders;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setAuthProvider(value) {
|
function getAuthProviderById(amoid) {
|
||||||
authProvider = value;
|
return authProviders.find(x => x.amoid == amoid);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultAuthProvider() {
|
||||||
|
return defaultAuthProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAuthProviderFromReq(req) {
|
||||||
|
const authProviderId = req?.auth?.amoid || req?.user?.amoid;
|
||||||
|
return getAuthProviderById(authProviderId) ?? getDefaultAuthProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAuthProviders(value, defaultProvider = null) {
|
||||||
|
authProviders = value;
|
||||||
|
defaultAuthProvider = defaultProvider || value[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
AuthProviderBase,
|
AuthProviderBase,
|
||||||
detectEnvAuthProvider,
|
detectEnvAuthProvider,
|
||||||
getAuthProvider,
|
getAuthProviders,
|
||||||
setAuthProvider,
|
getDefaultAuthProvider,
|
||||||
|
setAuthProviders,
|
||||||
|
getAuthProviderById,
|
||||||
|
getAuthProviderFromReq,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const { getLogger } = require('dbgate-tools');
|
|||||||
const AD = require('activedirectory2').promiseWrapper;
|
const AD = require('activedirectory2').promiseWrapper;
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const { getTokenSecret, getTokenLifetime } = require('../auth/authCommon');
|
const { getTokenSecret, getTokenLifetime } = require('../auth/authCommon');
|
||||||
const { getAuthProvider } = require('../auth/authProvider');
|
const { getAuthProviderFromReq, getAuthProviders, getDefaultAuthProvider, getAuthProviderById } = require('../auth/authProvider');
|
||||||
const storage = require('./storage');
|
const storage = require('./storage');
|
||||||
|
|
||||||
const logger = getLogger('auth');
|
const logger = getLogger('auth');
|
||||||
@@ -28,6 +28,7 @@ function authMiddleware(req, res, next) {
|
|||||||
'/auth/login',
|
'/auth/login',
|
||||||
'/stream',
|
'/stream',
|
||||||
'storage/get-connections-for-login-page',
|
'storage/get-connections-for-login-page',
|
||||||
|
'auth/get-providers',
|
||||||
'/connections/dblogin',
|
'/connections/dblogin',
|
||||||
'/connections/dblogin-auth',
|
'/connections/dblogin-auth',
|
||||||
'/connections/dblogin-auth-token',
|
'/connections/dblogin-auth-token',
|
||||||
@@ -37,7 +38,7 @@ function authMiddleware(req, res, next) {
|
|||||||
|
|
||||||
const isAdminPage = req.headers['x-is-admin-page'] == 'true';
|
const isAdminPage = req.headers['x-is-admin-page'] == 'true';
|
||||||
|
|
||||||
if (!isAdminPage && !getAuthProvider().shouldAuthorizeApi()) {
|
if (!isAdminPage && !getAuthProviderFromReq(req).shouldAuthorizeApi()) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
let skipAuth = !!SKIP_AUTH_PATHS.find(x => req.path == getExpressPath(x));
|
let skipAuth = !!SKIP_AUTH_PATHS.find(x => req.path == getExpressPath(x));
|
||||||
@@ -68,11 +69,11 @@ function authMiddleware(req, res, next) {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
oauthToken_meta: true,
|
oauthToken_meta: true,
|
||||||
async oauthToken(params) {
|
async oauthToken(params) {
|
||||||
return getAuthProvider().oauthToken(params);
|
return getDefaultAuthProvider().oauthToken(params);
|
||||||
},
|
},
|
||||||
login_meta: true,
|
login_meta: true,
|
||||||
async login(params) {
|
async login(params) {
|
||||||
const { login, password, isAdminPage } = params;
|
const { amoid, login, password, isAdminPage } = params;
|
||||||
|
|
||||||
if (isAdminPage) {
|
if (isAdminPage) {
|
||||||
if (process.env.ADMIN_PASSWORD && process.env.ADMIN_PASSWORD == password) {
|
if (process.env.ADMIN_PASSWORD && process.env.ADMIN_PASSWORD == password) {
|
||||||
@@ -94,7 +95,15 @@ module.exports = {
|
|||||||
return { error: 'Login failed' };
|
return { error: 'Login failed' };
|
||||||
}
|
}
|
||||||
|
|
||||||
return getAuthProvider().login(login, password);
|
return getAuthProviderById(amoid).login(login, password);
|
||||||
|
},
|
||||||
|
|
||||||
|
getProviders_meta: true,
|
||||||
|
getProviders() {
|
||||||
|
return {
|
||||||
|
providers: getAuthProviders().map(x => x.toJson()),
|
||||||
|
default: getDefaultAuthProvider()?.amoid,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
authMiddleware,
|
authMiddleware,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const AsyncLock = require('async-lock');
|
|||||||
const currentVersion = require('../currentVersion');
|
const currentVersion = require('../currentVersion');
|
||||||
const platformInfo = require('../utility/platformInfo');
|
const platformInfo = require('../utility/platformInfo');
|
||||||
const connections = require('../controllers/connections');
|
const connections = require('../controllers/connections');
|
||||||
const { getAuthProvider } = require('../auth/authProvider');
|
const { getAuthProviderFromReq } = require('../auth/authProvider');
|
||||||
|
|
||||||
const lock = new AsyncLock();
|
const lock = new AsyncLock();
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ module.exports = {
|
|||||||
|
|
||||||
get_meta: true,
|
get_meta: true,
|
||||||
async get(_params, req) {
|
async get(_params, req) {
|
||||||
const authProvider = getAuthProvider();
|
const authProvider = getAuthProviderFromReq(req);
|
||||||
const login = authProvider.getCurrentLogin(req);
|
const login = authProvider.getCurrentLogin(req);
|
||||||
const permissions = authProvider.getCurrentPermissions(req);
|
const permissions = authProvider.getCurrentPermissions(req);
|
||||||
const isLoginForm = authProvider.isLoginForm();
|
const isLoginForm = authProvider.isLoginForm();
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const platformInfo = require('./utility/platformInfo');
|
|||||||
const getExpressPath = require('./utility/getExpressPath');
|
const getExpressPath = require('./utility/getExpressPath');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const { getLogger } = require('dbgate-tools');
|
const { getLogger } = require('dbgate-tools');
|
||||||
const { getAuthProvider } = require('./auth/authProvider');
|
const { getDefaultAuthProvider } = require('./auth/authProvider');
|
||||||
|
|
||||||
const logger = getLogger('main');
|
const logger = getLogger('main');
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ function start() {
|
|||||||
if (process.env.BASIC_AUTH) {
|
if (process.env.BASIC_AUTH) {
|
||||||
async function authorizer(username, password, cb) {
|
async function authorizer(username, password, cb) {
|
||||||
try {
|
try {
|
||||||
const resp = await getAuthProvider().login(username, password);
|
const resp = await getDefaultAuthProvider().login(username, password);
|
||||||
if (resp.accessToken) {
|
if (resp.accessToken) {
|
||||||
cb(null, true);
|
cb(null, true);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const { compilePermissions, testPermission } = require('dbgate-tools');
|
const { compilePermissions, testPermission } = require('dbgate-tools');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const { getAuthProvider } = require('../auth/authProvider');
|
const { getAuthProviderFromReq } = require('../auth/authProvider');
|
||||||
|
|
||||||
const cachedPermissions = {};
|
const cachedPermissions = {};
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ function hasPermission(tested, req) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const permissions = getAuthProvider().getCurrentPermissions(req);
|
const permissions = getAuthProviderFromReq(req).getCurrentPermissions(req);
|
||||||
|
|
||||||
if (!cachedPermissions[permissions]) {
|
if (!cachedPermissions[permissions]) {
|
||||||
cachedPermissions[permissions] = compilePermissions(permissions);
|
cachedPermissions[permissions] = compilePermissions(permissions);
|
||||||
|
|||||||
@@ -19,29 +19,47 @@
|
|||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
|
|
||||||
let availableConnections = null;
|
let availableConnections = null;
|
||||||
|
let availableProviders = [];
|
||||||
let isTesting = false;
|
let isTesting = false;
|
||||||
const testIdRef = createRef(0);
|
const testIdRef = createRef(0);
|
||||||
let sqlConnectResult;
|
let sqlConnectResult;
|
||||||
|
|
||||||
const values = writable({ databaseServer: null });
|
let serversLoadedForAmoId = null;
|
||||||
|
|
||||||
|
const values = writable({ amoid: null, databaseServer: null });
|
||||||
|
|
||||||
$: selectedConnection = availableConnections?.find(x => x.conid == $values.databaseServer);
|
$: selectedConnection = availableConnections?.find(x => x.conid == $values.databaseServer);
|
||||||
|
|
||||||
async function loadAvailableServers() {
|
async function loadAvailableServers(amoid) {
|
||||||
availableConnections = await apiCall('storage/get-connections-for-login-page');
|
if (amoid) {
|
||||||
if (availableConnections?.length > 0) {
|
availableConnections = await apiCall('storage/get-connections-for-login-page', { amoid });
|
||||||
values.set({ databaseServer: availableConnections[0].conid });
|
if (availableConnections?.length > 0) {
|
||||||
|
values.update(x => ({ ...x, databaseServer: availableConnections[0].conid }));
|
||||||
|
}
|
||||||
|
serversLoadedForAmoId = amoid;
|
||||||
|
} else {
|
||||||
|
availableConnections = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadAvailableAuthProviders() {
|
||||||
|
const resp = await apiCall('auth/get-providers');
|
||||||
|
availableProviders = resp.providers;
|
||||||
|
values.update(x => ({ ...x, amoid: resp.default }));
|
||||||
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const removed = document.getElementById('starting_dbgate_zero');
|
const removed = document.getElementById('starting_dbgate_zero');
|
||||||
if (removed) removed.remove();
|
if (removed) removed.remove();
|
||||||
|
|
||||||
if (!isAdminPage) {
|
if (!isAdminPage) {
|
||||||
loadAvailableServers();
|
loadAvailableAuthProviders();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$: if ($values.amoid != serversLoadedForAmoId) {
|
||||||
|
loadAvailableServers($values.amoid);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root theme-light theme-type-light">
|
<div class="root theme-light theme-type-light">
|
||||||
@@ -53,6 +71,15 @@
|
|||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="heading">Log In</div>
|
<div class="heading">Log In</div>
|
||||||
<FormProviderCore {values}>
|
<FormProviderCore {values}>
|
||||||
|
{#if !isAdminPage}
|
||||||
|
<FormSelectField
|
||||||
|
label="Authentization method"
|
||||||
|
name="amoid"
|
||||||
|
isNative
|
||||||
|
options={availableProviders.map(mtd => ({ value: mtd.amoid, label: mtd.name }))}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if !isAdminPage && availableConnections}
|
{#if !isAdminPage && availableConnections}
|
||||||
<FormSelectField
|
<FormSelectField
|
||||||
label="Database server"
|
label="Database server"
|
||||||
@@ -150,6 +177,7 @@
|
|||||||
on:click={async e => {
|
on:click={async e => {
|
||||||
enableApi();
|
enableApi();
|
||||||
const resp = await apiCall('auth/login', {
|
const resp = await apiCall('auth/login', {
|
||||||
|
amoid: $values.amoid,
|
||||||
isAdminPage,
|
isAdminPage,
|
||||||
...e.detail,
|
...e.detail,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user