1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-16 22:50:10 +03:00

F #5422: first steps serveradmin login

Signed-off-by: Jorge Lobo <jlobo@opennebula.io>
This commit is contained in:
Jorge Lobo 2021-06-25 11:21:47 +02:00
parent 49be6b5b59
commit 2332a1c164
No known key found for this signature in database
GPG Key ID: 9C21660F7B06905E
5 changed files with 152 additions and 12 deletions

View File

@ -41,8 +41,10 @@ class OpenNebula::ServerCipherAuth
if !srv_passwd.empty?
# truncate token to 32-bytes for Ruby >= 2.4
@key = Digest::SHA256.hexdigest(@srv_passwd)[0..31]
else
@iv = @key[0..15]
else
@key = ""
@iv = ""
end
@cipher = OpenSSL::Cipher.new(CIPHER)
@ -112,6 +114,7 @@ class OpenNebula::ServerCipherAuth
begin
# truncate token to 32-bytes for Ruby >= 2.4
@key = srv_pass[0..31]
@iv = srv_pass[0..15]
token_array = decrypt(signed_text).split(':')
@ -133,7 +136,7 @@ class OpenNebula::ServerCipherAuth
def encrypt(data)
@cipher.encrypt
@cipher.key = @key
@cipher.iv = @iv
rc = @cipher.update(data)
rc << @cipher.final
@ -143,7 +146,7 @@ class OpenNebula::ServerCipherAuth
def decrypt(data)
@cipher.decrypt
@cipher.key = @key
@cipher.iv = @iv
rc = @cipher.update(Base64::decode64(data))
rc << @cipher.final

View File

@ -23,7 +23,8 @@ const {
defaultMethodZones,
defaultMethodUserInfo,
default2FAOpennebulaVar,
defaultNamespace
defaultNamespace,
defaultServerAdminID
} = require('server/utils/constants/defaults')
const { getConfig } = require('server/utils/yml')
const {
@ -32,7 +33,7 @@ const {
accepted
} = require('server/utils/constants/http-codes')
const { createToken } = require('server/utils/jwt')
const { httpResponse } = require('server/utils/server')
const { httpResponse, encrypt } = require('server/utils/server')
const {
responseOpennebula,
checkOpennebulaCommand,
@ -46,12 +47,15 @@ const appConfig = getConfig()
const namespace = appConfig.namespace || defaultNamespace
const minimumExpirationTime = appConfig.minimun_opennebula_expiration || defaultOpennebulaMinimumExpiration
const serverAdmin = appConfig.server_admin || defaultServerAdminID
const { POST } = httpMethod
const getOpennebulaMethod = checkOpennebulaCommand(defaultMethodLogin, POST)
let user = ''
let key = ''
let iv = ''
let pass = ''
let type = ''
let tfatoken = ''
@ -67,10 +71,22 @@ let relativeTime = ''
const dataSourceWithExpirateDate = () => Map(req).toObject()
const getKey = () => key
const getIV = () => iv
const getUser = () => user
const getPass = () => pass
const getRelativeTime = () => relativeTime
const setKey = newKey => {
key = newKey
return key
}
const setIV = newIV => {
iv = newIV
return iv
}
const setUser = newUser => {
user = newUser
return user
@ -143,6 +159,10 @@ const validate2faAuthentication = informationUser => {
informationUser.TEMPLATE.SUNSTONE &&
informationUser.TEMPLATE.SUNSTONE[default2FAOpennebulaVar]
) {
/*********************************************************
* Validate 2FA
*********************************************************/
if (tfatoken.length <= 0) {
updaterResponse(httpResponse(accepted))
} else {
@ -154,7 +174,10 @@ const validate2faAuthentication = informationUser => {
}
}
} else {
// without 2FA login
/*********************************************************
* Without 2FA
*********************************************************/
rtn = true
}
return rtn
@ -223,17 +246,21 @@ const setZones = () => {
}
const login = userData => {
let rtn = true
let rtn = false
if (userData) {
const findTextError = `[${namespace + defaultMethodUserInfo}]`
if (userData.indexOf && userData.indexOf(findTextError) >= 0) {
updaterResponse(httpResponse(unauthorized))
} else {
rtn = true
}
if (userData.USER) {
setZones()
if (validate2faAuthentication(userData.USER)) {
rtn = false
checkOpennebulaToken(userData.USER)
setDates()
getServerAdmin()
// checkOpennebulaToken(userData.USER) // aca seria el call de la funcion serveradmin
}
}
}
@ -242,6 +269,62 @@ const login = userData => {
}
}
const createTokenServerAdmin = (serverAdmin = '', username = '') => {
let rtn
const key = getKey()
const iv = getIV()
if (serverAdmin && username && key && iv) {
rtn = encrypt(
`${serverAdmin}:${username}:${parseInt(nowWithMinutes.toSeconds())}`,
key,
iv
)
}
return rtn
}
const wrapUserWithServerAdmin = (serverAdminData = {}) => {
const relativeTime = getRelativeTime()
const user = getUser()
let userPassword = ''
if (
relativeTime &&
serverAdminData &&
serverAdminData.USER &&
serverAdminData.USER.NAME &&
(userPassword = serverAdminData.USER.PASSWORD) &&
user
) {
/*********************************************************
* equals what is placed in:
* src/authm_mad/remotes/server_cipher/server_cipher_auth.rb:44
*********************************************************/
setKey(userPassword.substring(0, 32))
setIV(userPassword.substring(0, 16))
const tokenWithServerAdmin = createTokenServerAdmin(serverAdminData.USER.NAME, user)
if (tokenWithServerAdmin) {
console.log('FINAL --> ', `${serverAdminData.USER.NAME}:${user}:${tokenWithServerAdmin}`)
}
}
}
const getServerAdmin = () => {
const oneConnect = connectOpennebula()
oneConnect(
defaultMethodUserInfo,
[parseInt(serverAdmin, 10), false],
(err, value) => {
responseOpennebula(
updaterResponse,
err,
value,
wrapUserWithServerAdmin,
next)
}
)
}
const checkOpennebulaToken = userData => {
setDates()
if (userData && userData.LOGIN_TOKEN) {

View File

@ -15,6 +15,7 @@
const appName = 'fireedge'
const baseUrl = `${appName ? `/${appName}/` : '/'}`
const baseUrlWebsockets = 'websockets'
const apps = {
flow: {
name: 'flow',
@ -30,6 +31,8 @@ const default2FAOpennebulaVar = 'TWO_FACTOR_AUTH_SECRET'
const defaultIp = 'localhost'
const protocol = 'http'
const defaults = {
defaultServerAdminID: 1,
defaultTypeCrypto: 'aes-256-cbc',
defaultEmptyFunction: () => undefined,
defaultErrorTemplate: 'ERROR_FIREEDGE="%1$s"',
defaultOpennebulaExpiration: 180,
@ -41,11 +44,11 @@ const defaults = {
},
defaultFilesWebsockets: {
hooks: {
path: `${baseUrl}websockets/hooks`,
path: `${baseUrl}${baseUrlWebsockets}hooks`,
methods: ['GET', 'POST']
},
provision: {
path: `${baseUrl}websockets/provision`,
path: `${baseUrl}${baseUrlWebsockets}provision`,
methods: ['GET', 'POST']
}
},

View File

@ -43,7 +43,13 @@ const fillResourceforHookConection = (username = '', action = '', parameters = '
let match
// parameters[0] is the resource ID
if (username && action && (match = action.match(regexInfoAction)) && match[1] && parameters[0] >= 0) {
if (global.users[username] && !global.users[username].resourcesHooks) {
if (global && !global.users) {
global.users = {}
}
if (!global.users[username]) {
global.users[username] = {}
}
if (!global.users[username].resourcesHooks) {
global.users[username].resourcesHooks = {}
}
global.users[username].resourcesHooks[match[1]] = parameters[0]

View File

@ -15,6 +15,8 @@
const { env } = require('process')
const { Map } = require('immutable')
const { global } = require('window-or-global')
// eslint-disable-next-line node/no-deprecated-api
const { createCipheriv, createCipher, createDecipheriv, createDecipher } = require('crypto')
const { existsSync, readFileSync, createWriteStream } = require('fs-extra')
const { internalServerError } = require('./constants/http-codes')
const { messageTerminal } = require('server/utils/general')
@ -30,7 +32,8 @@ const {
defaultKeyFilename,
defaultWebpackMode,
defaultOpennebulaZones,
defaultEtcPath
defaultEtcPath,
defaultTypeCrypto
} = require('./constants/defaults')
let cert = ''
@ -117,6 +120,46 @@ const middlewareValidateAuthWebsocket = (server = {}, next = () => undefined) =>
}
}
const encrypt = (data = '', key = '', iv = '') => {
let rtn
if (data && key) {
try {
const cipher = iv ? createCipheriv(defaultTypeCrypto, key, iv) : createCipher(defaultTypeCrypto, key)
let encryptData = cipher.update(data, 'ascii', 'base64')
encryptData += cipher.final('base64')
rtn = encryptData
} catch (err) {
const errorData = (err && err.message) || ''
messageTerminal({
color: 'red',
message: 'Error: %s',
type: errorData
})
}
}
return rtn
}
const decrypt = (data = '', key = '', iv = '') => {
let rtn
if (data && key) {
try {
const cipher = iv ? createDecipheriv(defaultTypeCrypto, key, iv) : createDecipher(defaultTypeCrypto, key)
let decryptData = cipher.update(data, 'base64', 'ascii')
decryptData += cipher.final('ascii')
rtn = decryptData
} catch (err) {
const errorData = (err && err.message) || ''
messageTerminal({
color: 'red',
message: 'Error: %s',
type: errorData
})
}
}
return rtn
}
const existsFile = (path = '', success = () => undefined, error = () => undefined) => {
let rtn = false
let file
@ -262,6 +305,8 @@ const parsePostData = (postData = {}) => {
return rtn
}
module.exports = {
encrypt,
decrypt,
getDataZone,
existsFile,
createFile,