mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-05 09:17:41 +03:00
parent
5d6b8571b0
commit
875fe29ade
@ -14,6 +14,11 @@
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
import {
|
||||
entrypoint404,
|
||||
entrypointApi,
|
||||
entrypointApp,
|
||||
} from './routes/entrypoints'
|
||||
import {
|
||||
defaultAppName,
|
||||
defaultApps,
|
||||
@ -22,36 +27,26 @@ import {
|
||||
defaultPort,
|
||||
defaultWebpackMode,
|
||||
} from './utils/constants/defaults'
|
||||
import {
|
||||
entrypoint404,
|
||||
entrypointApi,
|
||||
entrypointApp,
|
||||
} from './routes/entrypoints'
|
||||
import { getLoggerMiddleware, initLogger } from './utils/logger'
|
||||
import {
|
||||
genFireedgeKey,
|
||||
genPathResources,
|
||||
getCert,
|
||||
getKey,
|
||||
validateServerIsSecure,
|
||||
setDnsResultOrder,
|
||||
} from './utils/server'
|
||||
import { getLoggerMiddleware, initLogger } from './utils/logger'
|
||||
|
||||
import compression from 'compression'
|
||||
import cors from 'cors'
|
||||
import { env } from 'process'
|
||||
import express from 'express'
|
||||
import { getFireedgeConfig } from './utils/yml'
|
||||
import guacamole from './routes/websockets/guacamole'
|
||||
import helmet from 'helmet'
|
||||
import http from 'http'
|
||||
import https from 'https'
|
||||
import { messageTerminal } from './utils/general'
|
||||
import opennebulaWebsockets from './routes/websockets/opennebula'
|
||||
import { readFileSync } from 'fs-extra'
|
||||
import { resolve } from 'path'
|
||||
import vmrc from './routes/websockets/vmrc'
|
||||
import { env } from 'process'
|
||||
import webpack from 'webpack'
|
||||
import guacamole from './routes/websockets/guacamole'
|
||||
import opennebulaWebsockets from './routes/websockets/opennebula'
|
||||
import vmrc from './routes/websockets/vmrc'
|
||||
import { messageTerminal } from './utils/general'
|
||||
import { getFireedgeConfig } from './utils/yml'
|
||||
|
||||
setDnsResultOrder()
|
||||
|
||||
@ -66,10 +61,6 @@ genFireedgeKey()
|
||||
// set logger
|
||||
initLogger(appConfig.debug_level, appConfig.truncate_max_length)
|
||||
|
||||
// destructure imports
|
||||
const unsecureServer = http.createServer
|
||||
const secureServer = https.createServer
|
||||
|
||||
const app = express()
|
||||
const basename = defaultAppName ? `/${defaultAppName}` : ''
|
||||
|
||||
@ -137,15 +128,7 @@ app.get('/*', (_, res) => res.redirect(`/${defaultAppName}/sunstone`))
|
||||
// 404 - public
|
||||
app.get('*', entrypoint404)
|
||||
|
||||
const appServer = validateServerIsSecure()
|
||||
? secureServer(
|
||||
{
|
||||
key: readFileSync(getKey(), 'utf8'),
|
||||
cert: readFileSync(getCert(), 'utf8'),
|
||||
},
|
||||
app
|
||||
)
|
||||
: unsecureServer(app)
|
||||
const appServer = http.createServer(app)
|
||||
|
||||
const websockets = opennebulaWebsockets(appServer) || []
|
||||
|
||||
|
@ -28,6 +28,7 @@ const {
|
||||
connectOpennebula,
|
||||
updaterResponse,
|
||||
remoteLogin,
|
||||
x509Login,
|
||||
} = require('server/routes/api/auth/utils')
|
||||
|
||||
const { defaults, httpCodes } = require('server/utils/constants')
|
||||
@ -135,22 +136,35 @@ const coreAuth = (
|
||||
* @param {object} res - http response
|
||||
* @param {Function} next - express stepper
|
||||
* @param {object} params - params of http request
|
||||
* @param {object} userData - user of http request
|
||||
* @param {object} _ - user of http request
|
||||
* @param {Function} oneConnection - function of xmlrpc
|
||||
* @param {string} typeAuth - auth type
|
||||
*/
|
||||
const remoteAuth = (
|
||||
res = {},
|
||||
next = defaultEmptyFunction,
|
||||
params = {},
|
||||
userData = {},
|
||||
oneConnection = defaultEmptyFunction
|
||||
_,
|
||||
oneConnection = defaultEmptyFunction,
|
||||
typeAuth
|
||||
) => {
|
||||
const { user } = params
|
||||
setRes(res)
|
||||
setNext(next)
|
||||
setNodeConnect(oneConnection)
|
||||
updaterResponse(new Map(internalServerError).toObject())
|
||||
user ? remoteLogin(user) : next()
|
||||
if (user) {
|
||||
switch (typeAuth) {
|
||||
case 'x509':
|
||||
x509Login(user)
|
||||
break
|
||||
default:
|
||||
remoteLogin(user)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,12 +186,14 @@ const selectTypeAuth = (
|
||||
oneConnection = defaultEmptyFunction
|
||||
) => {
|
||||
const appConfig = getFireedgeConfig()
|
||||
switch (appConfig?.auth) {
|
||||
case 'remote':
|
||||
return remoteAuth(res, next, params, userData, oneConnection)
|
||||
default:
|
||||
return coreAuth(res, next, params, userData, oneConnection)
|
||||
const typeAuth = {
|
||||
remote: () => remoteAuth(res, next, params, userData, oneConnection),
|
||||
x509: () => remoteAuth(res, next, params, userData, oneConnection, 'x509'),
|
||||
opennebula: () => coreAuth(res, next, params, userData, oneConnection),
|
||||
}
|
||||
const auth = typeAuth[appConfig?.auth] || typeAuth.opennebula
|
||||
|
||||
return auth()
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
@ -566,6 +566,44 @@ const remoteLogin = (userData = '') => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* X.509 login route function.
|
||||
*
|
||||
* @param {string} userData - user remote data /DC=es/O=one/CN=user|/DC=us/O=two/CN=user
|
||||
*/
|
||||
const x509Login = (userData = '') => {
|
||||
const serverAdminData = getServerAdmin()
|
||||
const { username, token } = serverAdminData
|
||||
if (username && token && userData) {
|
||||
const reverseStringFields = (str) =>
|
||||
/,/.test(str) ? str.split(',').reverse().join('/') : str
|
||||
const parsedUserData = reverseStringFields(userData)
|
||||
|
||||
const oneConnect = connectOpennebula(`${username}:${username}`, token.token)
|
||||
oneConnect({
|
||||
action: USER_POOL_INFO,
|
||||
parameters: getDefaultParamsOfOpennebulaCommand(USER_POOL_INFO, GET),
|
||||
callback: (_, value) => {
|
||||
const users = value?.USER_POOL?.USER || []
|
||||
if (users.length) {
|
||||
const userFound = users.find(
|
||||
(data) =>
|
||||
data.PASSWORD.includes(parsedUserData) &&
|
||||
data.AUTH_DRIVER === 'x509'
|
||||
)
|
||||
if (userFound) {
|
||||
setZones()
|
||||
getServerAdminAndWrapUser(userFound)
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
}
|
||||
},
|
||||
fillHookResource: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Login route function.
|
||||
*
|
||||
@ -613,5 +651,6 @@ module.exports = {
|
||||
getCreatedTokenOpennebula,
|
||||
createTokenServerAdmin,
|
||||
remoteLogin,
|
||||
x509Login,
|
||||
getServerAdmin,
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ const thunk = require('redux-thunk').default
|
||||
const { ServerStyleSheets } = require('@mui/styles')
|
||||
const { request: axios } = require('axios')
|
||||
const { writeInLogger } = require('server/utils/logger')
|
||||
const { MissingRemoteHeaderError } = require('server/utils/errors')
|
||||
const { MissingHeaderError } = require('server/utils/errors')
|
||||
|
||||
// server
|
||||
const {
|
||||
@ -37,7 +37,12 @@ const {
|
||||
defaultApps,
|
||||
defaultAppName,
|
||||
defaultHeaderRemote,
|
||||
defaultHeaderx509,
|
||||
defaultApiTimeout,
|
||||
defaultProtocol,
|
||||
defaultIP,
|
||||
defaultPort,
|
||||
httpMethod,
|
||||
} = require('server/utils/constants/defaults')
|
||||
|
||||
// client
|
||||
@ -60,6 +65,7 @@ const router = Router()
|
||||
const defaultConfig = {
|
||||
currentTimeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
}
|
||||
const { POST } = httpMethod
|
||||
|
||||
router.get('*', async (req, res) => {
|
||||
const remoteJWT = {}
|
||||
@ -77,29 +83,45 @@ router.get('*', async (req, res) => {
|
||||
const encodedFavIcon = await getEncodedFavicon()
|
||||
|
||||
const appConfig = getFireedgeConfig()
|
||||
if (appConfig?.auth === 'remote') {
|
||||
const authType = appConfig?.auth
|
||||
const validAuthTypes = ['remote', 'x509']
|
||||
|
||||
if (validAuthTypes.includes(authType)) {
|
||||
remoteJWT.remote = true
|
||||
remoteJWT.remoteRedirect = appConfig?.auth_redirect ?? '.'
|
||||
|
||||
const finderHeader = () => {
|
||||
const headers = Object.keys(req.headers)
|
||||
|
||||
return headers.find((header) => defaultHeaderRemote.includes(header))
|
||||
switch (authType) {
|
||||
case validAuthTypes[1]:
|
||||
return headers.find((header) => defaultHeaderx509.includes(header))
|
||||
default:
|
||||
return headers.find((header) => defaultHeaderRemote.includes(header))
|
||||
}
|
||||
}
|
||||
|
||||
const findHeader = finderHeader()
|
||||
try {
|
||||
if (!findHeader) {
|
||||
throw new MissingRemoteHeaderError(JSON.stringify(req.headers))
|
||||
throw new MissingHeaderError(JSON.stringify(req.headers))
|
||||
}
|
||||
|
||||
const remoteUser = req.get(findHeader)
|
||||
const jwt = await axios({
|
||||
method: 'POST',
|
||||
url: `${req.protocol}://${req.get('host')}/${defaultAppName}/api/auth`,
|
||||
|
||||
const paramsAxios = {
|
||||
method: POST,
|
||||
url: `${defaultProtocol}://${defaultIP}:${
|
||||
appConfig.port || defaultPort
|
||||
}/${defaultAppName}/api/auth`,
|
||||
data: {
|
||||
user: req.get(findHeader),
|
||||
user: remoteUser,
|
||||
},
|
||||
validateStatus: (status) => status >= 200 && status <= 400,
|
||||
})
|
||||
}
|
||||
|
||||
const jwt = await axios(paramsAxios)
|
||||
|
||||
if (!global.remoteUsers) {
|
||||
global.remoteUsers = {}
|
||||
}
|
||||
|
@ -18,12 +18,13 @@
|
||||
const { parse } = require('url')
|
||||
const { createProxyMiddleware } = require('http-proxy-middleware')
|
||||
const { getFireedgeConfig } = require('server/utils/yml')
|
||||
const {
|
||||
genPathResources,
|
||||
validateServerIsSecure,
|
||||
} = require('server/utils/server')
|
||||
const { genPathResources } = require('server/utils/server')
|
||||
const { writeInLogger } = require('server/utils/logger')
|
||||
const { endpointVmrc, defaultPort } = require('server/utils/constants/defaults')
|
||||
const {
|
||||
endpointVmrc,
|
||||
defaultPort,
|
||||
defaultProtocol,
|
||||
} = require('server/utils/constants/defaults')
|
||||
|
||||
genPathResources()
|
||||
|
||||
@ -35,7 +36,7 @@ const logger = (message = '', format = '%s') =>
|
||||
|
||||
const appConfig = getFireedgeConfig()
|
||||
const port = appConfig.port || defaultPort
|
||||
const protocol = validateServerIsSecure() ? 'https' : 'http'
|
||||
const protocol = defaultProtocol
|
||||
const url = `${protocol}://localhost:${port}`
|
||||
const vmrcProxy = createProxyMiddleware(endpointVmrc, {
|
||||
target: url,
|
||||
|
@ -57,6 +57,7 @@ const defaults = {
|
||||
defaultSizeRotate: '100k',
|
||||
defaultAppName: appName,
|
||||
defaultHeaderRemote: ['http_x_auth_username', 'x_auth_username'],
|
||||
defaultHeaderx509: ['x-client-dn'],
|
||||
defaultConfigErrorMessage: {
|
||||
color: 'red',
|
||||
message: 'file not found: %s',
|
||||
@ -150,6 +151,7 @@ const defaults = {
|
||||
default2FAOpennebulaTmpVar: `TMP_${default2FAOpennebulaVar}`,
|
||||
defaultMessageProblemOpennebula: 'Problem with connection or xml parser',
|
||||
defaultIP: defaultIp,
|
||||
defaultProtocol: protocol,
|
||||
defaultSeverities: [
|
||||
`${severityPrepend}1`,
|
||||
`${severityPrepend}2`,
|
||||
|
@ -35,13 +35,13 @@ class JWTError extends OpenNebulaError {
|
||||
}
|
||||
}
|
||||
|
||||
class MissingRemoteHeaderError extends OpenNebulaError {
|
||||
class MissingHeaderError extends OpenNebulaError {
|
||||
/**
|
||||
* @param {string} headers - error message description.
|
||||
*/
|
||||
constructor(headers = '') {
|
||||
super(`missing header: ${defaultHeaderRemote.join()} in ${headers}`)
|
||||
this.name = 'MissingRemoteHeaderError'
|
||||
super(`Missing Header: ${defaultHeaderRemote.join()} in ${headers}`)
|
||||
this.name = 'MissingHeaderError'
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,9 +55,20 @@ class MissingFireEdgeKeyError extends OpenNebulaError {
|
||||
}
|
||||
}
|
||||
|
||||
class InternalLoginError extends OpenNebulaError {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
super('Internal Login Error')
|
||||
this.name = 'InternalLoginError'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
JWTError,
|
||||
MissingFireEdgeKeyError,
|
||||
OpenNebulaError,
|
||||
MissingRemoteHeaderError,
|
||||
MissingHeaderError,
|
||||
InternalLoginError,
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ const {
|
||||
createHash,
|
||||
} = require('crypto')
|
||||
const {
|
||||
existsSync,
|
||||
readFileSync,
|
||||
createWriteStream,
|
||||
readdirSync,
|
||||
@ -79,9 +78,6 @@ const {
|
||||
const { internalServerError } = httpCodes
|
||||
const { POST } = httpMethod
|
||||
|
||||
let cert = ''
|
||||
let key = ''
|
||||
|
||||
/**
|
||||
* Sets the default DNS lookup order to prefer IPv4 addresses first
|
||||
* if the Node.js version is 16.0.0 or higher.
|
||||
@ -97,37 +93,6 @@ const setDnsResultOrder = () => {
|
||||
|
||||
setDnsResultOrder()
|
||||
|
||||
/**
|
||||
* Validate if server app have certs.
|
||||
*
|
||||
* @returns {boolean} file certs
|
||||
*/
|
||||
const validateServerIsSecure = () => {
|
||||
const folder = 'cert/'
|
||||
const dirCerts =
|
||||
env && env.NODE_ENV === defaultWebpackMode
|
||||
? ['../', '../', '../', folder]
|
||||
: ['../', folder]
|
||||
const pathfile = resolve(__dirname, ...dirCerts)
|
||||
cert = `${pathfile}/cert.pem`
|
||||
key = `${pathfile}/key.pem`
|
||||
|
||||
return existsSync && key && cert && existsSync(key) && existsSync(cert)
|
||||
}
|
||||
/**
|
||||
* Get certificate SSL.
|
||||
*
|
||||
* @returns {string} ssl path
|
||||
*/
|
||||
const getCert = () => cert
|
||||
|
||||
/**
|
||||
* Get key of certificate SSL.
|
||||
*
|
||||
* @returns {string} key ssl path
|
||||
*/
|
||||
const getKey = () => key
|
||||
|
||||
/**
|
||||
* Validate the route http method.
|
||||
*
|
||||
@ -1045,11 +1010,8 @@ module.exports = {
|
||||
replaceEscapeSequence,
|
||||
createFile,
|
||||
httpResponse,
|
||||
validateServerIsSecure,
|
||||
genPathResources,
|
||||
genFireedgeKey,
|
||||
getCert,
|
||||
getKey,
|
||||
parsePostData,
|
||||
getRequestFiles,
|
||||
getRequestParameters,
|
||||
|
Loading…
Reference in New Issue
Block a user