diff --git a/.github/workflows/api-test.yml b/.github/workflows/api-test.yml index 6db36ed57..ff1a9a828 100644 --- a/.github/workflows/api-test.yml +++ b/.github/workflows/api-test.yml @@ -24,5 +24,5 @@ jobs: - run: docker build -f Dockerfile -t mps:${GITHUB_SHA} . - run: docker-compose up -d - run: sleep 30 - - run: docker run --network=host -v /home/runner/work/mps/mps/test/collections/:/collections postman/newman run /collections/MPS.postman_collection.json -e /collections/MPS.postman_environment.json --insecure + - run: docker run --network=host -v /home/runner/work/mps/mps/src/test/collections/:/collections postman/newman run /collections/MPS.postman_collection.json -e /collections/MPS.postman_environment.json --insecure diff --git a/.gitignore b/.gitignore index 87f6db1e3..5e5beac68 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,9 @@ private/*.crt private/*.key private/*.cer mochawesome-report/ -test/private/*.cer -test/private/*.crt -test/private/*.key +src/test/private/*.cer +src/test/private/*.crt +src/test/private/*.key # build output folder dist/ diff --git a/.mpsrc b/.mpsrc index 36d794572..17f193f72 100644 --- a/.mpsrc +++ b/.mpsrc @@ -1,9 +1,6 @@ { "common_name": "localhost", "port": 4433, - "username": "standalone", - "pass": "G@ppm0ym", - "use_global_mps_credentials": true, "country": "US", "company": "NoCorp", "debug": true, @@ -13,15 +10,15 @@ "web_port" : 3000, "generate_certificates": true, "logger_off":false, - "web_admin_user": "standalone", - "web_admin_password": "G@ppm0ym", + "web_admin_user": "", + "web_admin_password": "", "vault_address": "http://localhost:8200", "vault_token": "myroot", "secrets_path": "secret/data/", "cert_format" : "file", "data_path" : "../private/data.json", "cert_path": "../private", - "jwt_secret": "supersecret", + "jwt_secret": "", "jwt_issuer": "9EmRJTbIiIb4bIeSsmgcWIjrR6HyETqc", "jwt_expiration": "1440", "cors_origin":"*", diff --git a/data/initMPS.sql b/data/initMPS.sql index ab855d839..0ea0f2a5b 100644 --- a/data/initMPS.sql +++ b/data/initMPS.sql @@ -12,5 +12,6 @@ CREATE TABLE IF NOT EXISTS devices( hostname varchar(256), mpsinstance text, connectionstatus boolean, + mpsusername text, CONSTRAINT device_guid UNIQUE(guid) ); diff --git a/docker-compose.yml b/docker-compose.yml index 1901240be..b1d9081a4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,10 +16,15 @@ services: environment: MPS_CONNECTION_STRING: "postgresql://postgresadmin:admin123@db:5432/mpsdb" MPS_VAULT_ADDRESS: "http://vault:8200" + MPS_WEB_ADMIN_USER: "standalone" + MPS_WEB_ADMIN_PASSWORD: "G@ppm0ym" + MPS_JWT_SECRET: "mpssecret" db: image: postgres networks: - openamtnetwork + ports: + - 5432:5432 restart: always environment: POSTGRES_USER: postgresadmin diff --git a/src/db/device.ts b/src/db/device.ts index 3cecf21e5..26df7566d 100644 --- a/src/db/device.ts +++ b/src/db/device.ts @@ -69,13 +69,14 @@ export class DeviceDb implements IDeviceDb { */ async insert (device: Device): Promise { try { - const results = await this.db.query('INSERT INTO devices(guid, hostname, tags, mpsinstance, connectionstatus) values($1, $2, ARRAY(SELECT json_array_elements_text($3)), $4, $5)', + const results = await this.db.query('INSERT INTO devices(guid, hostname, tags, mpsinstance, connectionstatus, mpsusername) values($1, $2, ARRAY(SELECT json_array_elements_text($3)), $4, $5, $6)', [ device.guid, device.hostname, JSON.stringify(device.tags), device.mpsInstance, - device.connectionStatus + device.connectionStatus, + device.mpsusername ]) if (results.rowCount > 0) { return await this.getById(device.guid) @@ -97,13 +98,14 @@ export class DeviceDb implements IDeviceDb { */ async update (device: Device): Promise { try { - const results = await this.db.query('UPDATE devices SET tags=$2, hostname=$3, mpsinstance=$4, connectionstatus=$5 WHERE guid=$1', + const results = await this.db.query('UPDATE devices SET tags=$2, hostname=$3, mpsinstance=$4, connectionstatus=$5, mpsusername=$6 WHERE guid=$1', [ device.guid, device.tags, device.hostname, device.mpsInstance, - device.connectionStatus + device.connectionStatus, + device.mpsusername ]) if (results.rowCount > 0) { return await this.getById(device.guid) diff --git a/src/db/mapToDevice.ts b/src/db/mapToDevice.ts index c51a7b805..874ce88ff 100644 --- a/src/db/mapToDevice.ts +++ b/src/db/mapToDevice.ts @@ -10,6 +10,7 @@ export function mapToDevice (result): Device { hostname: result.hostname, tags: result.tags, mpsInstance: result.mpsinstance, - connectionStatus: result.connectionstatus + connectionStatus: result.connectionstatus, + mpsusername: result.mpsusername } } diff --git a/src/index.ts b/src/index.ts index ddb07f1bd..1fc97a391 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,12 +14,12 @@ import { tlsConfig } from './utils/tlsConfiguration' import { IDbProvider } from './models/IDbProvider' import { SecretManagerService } from './utils/SecretManagerService' -import { SecretsDbProvider } from './utils/vaultDbProvider' import { parseValue } from './utils/parseEnvValue' import rc from 'rc' import { Environment } from './utils/Environment' import { DeviceDb } from './db/device' +import { AuthDbProvider } from './utils/AuthDbProvider' try { // To merge ENV variables. consider after lowercasing ENV since our config keys are lowercase process.env = Object.keys(process.env) @@ -31,8 +31,8 @@ try { // build config object const config: configType = rc('mps') - if (!config.web_admin_password || !config.web_admin_user) { - log.error('Web admin username, password and API key are mandatory. Make sure to set values for these variables.') + if (!config.web_admin_password || !config.web_admin_user || !config.jwt_secret) { + log.error('Web admin username, password and jwt secret are mandatory. Make sure to set values for these variables.') process.exit(1) } @@ -45,9 +45,8 @@ try { Environment.Config = config // DB initialization - - const db: IDbProvider = new SecretsDbProvider(new SecretManagerService(config, log), log, config) const deviceDb = new DeviceDb() + const db: IDbProvider = new AuthDbProvider(new SecretManagerService(config, log), deviceDb, log, config) // Cleans the DB before exit when it listens to the signals const signals = ['SIGINT', 'exit', 'uncaughtException', 'SIGTERM', 'SIGHUP'] diff --git a/src/models/Config.d.ts b/src/models/Config.d.ts index 0becb1414..17dadb151 100644 --- a/src/models/Config.d.ts +++ b/src/models/Config.d.ts @@ -7,9 +7,6 @@ export interface configType { common_name: string port: number - username: string - pass: string - use_global_mps_credentials: boolean country: string company: string listen_any: boolean diff --git a/src/models/IDbProvider.ts b/src/models/IDbProvider.ts index d0fcf65f4..0d1a82889 100644 --- a/src/models/IDbProvider.ts +++ b/src/models/IDbProvider.ts @@ -3,8 +3,8 @@ * Copyright (c) Intel Corporation 2020 * SPDX-License-Identifier: Apache-2.0 **********************************************************************/ -export interface IDbProvider { - CIRAAuth: (guid: string, username: string, password: string, cb: any) => any +export interface IDbProvider { // todo: change to auth provider? + CIRAAuth: (guid: string, username: string, password: string) => any getAmtPassword: (uuid: string) => any - IsGUIDApproved: (guid: string, cb: any) => any + IsGUIDApproved: (guid: string) => any } diff --git a/src/models/models.ts b/src/models/models.ts index 3db8e2474..4ca1cab27 100644 --- a/src/models/models.ts +++ b/src/models/models.ts @@ -7,6 +7,7 @@ export interface Device { mpsInstance: string hostname: string guid: string + mpsusername: string tags: string[] } export interface Credentials { diff --git a/src/routes/auth/authValidator.ts b/src/routes/auth/authValidator.ts new file mode 100644 index 000000000..33bc4decd --- /dev/null +++ b/src/routes/auth/authValidator.ts @@ -0,0 +1,19 @@ +/********************************************************************* + * Copyright (c) Intel Corporation 2021 + * SPDX-License-Identifier: Apache-2.0 + **********************************************************************/ + +import { check } from 'express-validator' + +export const authValidator = (): any => { + return [ + check('username') + .not() + .isEmpty() + .withMessage('User name is required'), + check('password') + .not() + .isEmpty() + .withMessage('Password is required') + ] +} diff --git a/src/routes/auth/login.ts b/src/routes/auth/login.ts index 64c100f0c..2fc872d49 100644 --- a/src/routes/auth/login.ts +++ b/src/routes/auth/login.ts @@ -1,23 +1,27 @@ +import { validationResult } from 'express-validator' import jws from 'jws' export async function login (req, res): Promise { + const errors = validationResult(req) + if (!errors.isEmpty()) { + res.status(400).json({ errors: errors.array() }) + return + } const username = req.body.username const password = req.body.password - if (username && password) { - // todo: implement a more advanced authentication system and RBAC - if (username === req.mpsService.config.web_admin_user && password === req.mpsService.config.web_admin_password) { - const expirationMinutes = Number(req.mpsService.config.jwt_expiration) - const expiration = Math.floor((Date.now() + (1000 * 60 * expirationMinutes)) / 1000) - const signature = jws.sign({ - header: { alg: 'HS256', typ: 'JWT' }, - payload: { - iss: req.mpsService.config.jwt_issuer, - exp: expiration - }, - secret: req.mpsService.config.jwt_secret - }) - res.status(200).send({ token: signature }) - } else { - res.status(401).send({ message: 'Incorrect Username and/or Password!' }) - } + // todo: implement a more advanced authentication system and RBAC + if (username === req.mpsService.config.web_admin_user && password === req.mpsService.config.web_admin_password) { + const expirationMinutes = Number(req.mpsService.config.jwt_expiration) + const expiration = Math.floor((Date.now() + (1000 * 60 * expirationMinutes)) / 1000) + const signature = jws.sign({ + header: { alg: 'HS256', typ: 'JWT' }, + payload: { + iss: req.mpsService.config.jwt_issuer, + exp: expiration + }, + secret: req.mpsService.config.jwt_secret + }) + res.status(200).send({ token: signature }) + } else { + res.status(401).send({ message: 'Incorrect Username and/or Password!' }) } } diff --git a/src/routes/devices/create.ts b/src/routes/devices/create.ts index 84264d23a..fac292ca3 100644 --- a/src/routes/devices/create.ts +++ b/src/routes/devices/create.ts @@ -22,6 +22,7 @@ export async function insertDevice (req, res): Promise { device.hostname = req.body.hostname ?? device.hostname device.tags = req.body.tags ?? device.tags device.connectionStatus = device.connectionStatus ?? false + device.mpsusername = req.body.mpsusername ?? device.mpsusername const results = await db.update(device) res.status(200).json(results) } else { @@ -30,6 +31,7 @@ export async function insertDevice (req, res): Promise { guid: req.body.guid, hostname: req.body.hostname ?? null, tags: req.body.tags ?? null, + mpsusername: req.body.mpsusername, mpsInstance: null } const results = await db.insert(device) diff --git a/src/routes/devices/deviceValidator.ts b/src/routes/devices/deviceValidator.ts index b752526ca..cc513bb17 100644 --- a/src/routes/devices/deviceValidator.ts +++ b/src/routes/devices/deviceValidator.ts @@ -29,6 +29,9 @@ export const validator = (): any => { check('hostname') .optional({ nullable: true }) .isString(), + check('mpsusername') + .optional({ nullable: true }) + .isString(), check('tags') .optional() .isArray() diff --git a/src/routes/index.ts b/src/routes/index.ts index cc72cd56d..a16913ed3 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -8,9 +8,10 @@ import deviceRouter from './devices/index' import { mpsrootcert } from './certs' import { login } from './auth/login' import amtRouter from './amt/index' +import { authValidator } from './auth/authValidator' const router: Router = Router() -router.post('/authorize', login) +router.post('/authorize', authValidator(), login) router.use('/devices', deviceRouter) router.get('/ciracert', mpsrootcert) router.use('/amt', amtRouter) diff --git a/src/server/mpsserver.ts b/src/server/mpsserver.ts index caabf3966..8ed5b7cf2 100644 --- a/src/server/mpsserver.ts +++ b/src/server/mpsserver.ts @@ -191,20 +191,18 @@ export class MPSServer { socket.tag.SystemId = this.guidToStr(common.rstr2hex(data.substring(13, 29))).toLowerCase() this.debug(3, 'MPS:PROTOCOLVERSION', socket.tag.MajorVersion, socket.tag.MinorVersion, socket.tag.SystemId) // Check if the device exits in db - this.db.IsGUIDApproved(socket.tag.SystemId, async (allowed): Promise => { + if (this.db.IsGUIDApproved(socket.tag.SystemId)) { socket.tag.nodeid = socket.tag.SystemId - if (allowed) { - if (socket.tag.certauth) { - this.ciraConnections[socket.tag.SystemId] = socket - await this.mpsService.CIRAConnected(socket.tag.nodeid) - } - } else { - try { - this.debug(1, `MPS:GUID ${socket.tag.SystemId} is not allowed to connect.`) - socket.end() - } catch (e) { } + if (socket.tag.certauth) { + this.ciraConnections[socket.tag.SystemId] = socket + await this.mpsService.CIRAConnected(socket.tag.nodeid) } - }) + } else { + try { + this.debug(1, `MPS:GUID ${socket.tag.SystemId} is not allowed to connect.`) + socket.end() + } catch (e) { } + } log.debug(`device uuid: ${socket.tag.SystemId}`) return 93 } @@ -224,17 +222,15 @@ export class MPSServer { this.debug(3, `MPS:USERAUTH_REQUEST usernameLen=${usernameLen} serviceNameLen=${serviceNameLen} methodNameLen=${methodNameLen}`) this.debug(3, `MPS:USERAUTH_REQUEST user=${username} service=${serviceName} method=${methodName} password=${password}`) // Authenticate device connection using username and password - this.db.CIRAAuth(socket.tag.SystemId, username, password, async (allowed): Promise => { - if (allowed) { - this.debug(1, 'MPS:CIRA Authentication successful for ', username) - this.ciraConnections[socket.tag.SystemId] = socket - await this.mpsService.CIRAConnected(socket.tag.SystemId) // Notify that a connection is successful to console - this.SendUserAuthSuccess(socket) // Notify the auth success on the CIRA connection - } else { - log.warn(`MPS: CIRA Authentication failed for: ${username} `) - this.SendUserAuthFail(socket) - } - }) + if (this.db.CIRAAuth(socket.tag.SystemId, username, password)) { + this.debug(1, 'MPS:CIRA Authentication successful for ', username) + this.ciraConnections[socket.tag.SystemId] = socket + await this.mpsService.CIRAConnected(socket.tag.SystemId) // Notify that a connection is successful to console + this.SendUserAuthSuccess(socket) // Notify the auth success on the CIRA connection + } else { + log.warn(`MPS: CIRA Authentication failed for: ${username} `) + this.SendUserAuthFail(socket) + } return 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen } case APFProtocol.SERVICE_REQUEST: { diff --git a/test/amt_xmlparser.spec.ts b/src/test/amt_xmlparser.spec.ts similarity index 99% rename from test/amt_xmlparser.spec.ts rename to src/test/amt_xmlparser.spec.ts index 5be85d047..ebbd2d68f 100644 --- a/test/amt_xmlparser.spec.ts +++ b/src/test/amt_xmlparser.spec.ts @@ -1,5 +1,5 @@ -import { ParseWsman } from '../src/amt_libraries/amt-xml' +import { ParseWsman } from '../amt_libraries/amt-xml' describe('AMT related XML parser testing ', () => { // AMT_audilog diff --git a/test/cim_xmlparser.spec.ts b/src/test/cim_xmlparser.spec.ts similarity index 99% rename from test/cim_xmlparser.spec.ts rename to src/test/cim_xmlparser.spec.ts index 72820e8d9..2b483e2fe 100644 --- a/test/cim_xmlparser.spec.ts +++ b/src/test/cim_xmlparser.spec.ts @@ -1,4 +1,4 @@ -import { ParseWsman } from '../src/amt_libraries/amt-xml' +import { ParseWsman } from '../amt_libraries/amt-xml' describe('CIM related XML parser testing ', () => { // CIM_BIOSElement diff --git a/test/collections/MPS.postman_collection.json b/src/test/collections/MPS.postman_collection.json similarity index 90% rename from test/collections/MPS.postman_collection.json rename to src/test/collections/MPS.postman_collection.json index 11fe62269..60bfdcd5a 100644 --- a/test/collections/MPS.postman_collection.json +++ b/src/test/collections/MPS.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "f17d0f89-6914-468b-95ba-b1f093ac9abd", + "_postman_id": "98c88f35-4651-4007-88b4-a48c76c29f3a", "name": "MPS", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -332,7 +332,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\r\n \"guid\": \"143e4567-e89b-12d3-a456-426614174000\",\r\n \"hostname\": \"hostname\",\r\n \"tags\": []\r\n}", + "raw": "{\r\n \"guid\": \"143e4567-e89b-12d3-a456-426614174000\",\r\n \"hostname\": \"hostname\",\r\n \"tags\": [],\r\n \"mpsusername\": \"admin\"\r\n}", "options": { "raw": { "language": "json" @@ -1410,52 +1410,157 @@ ] }, { - "name": "Authorize", - "event": [ + "name": "Login", + "item": [ { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test(\"Body should have JWT Token\", function () {\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData.token).to.be.not.null;\r", - "});\r", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"username\":\"standalone\",\r\n \"password\":\"G@ppm0ym\"\r\n}", - "options": { - "raw": { - "language": "json" - } - } + "name": "Authorize", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {\r", + " pm.response.to.have.status(200);\r", + "});\r", + "\r", + "pm.test(\"Body should have JWT Token\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData.token).to.be.not.null;\r", + "});\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\":\"standalone\",\r\n \"password\":\"G@ppm0ym\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{host}}/api/v1/authorize", + "protocol": "{{protocol}}", + "host": [ + "{{host}}" + ], + "path": [ + "api", + "v1", + "authorize" + ] + } + }, + "response": [] }, - "url": { - "raw": "{{protocol}}://{{host}}/api/v1/authorize", - "protocol": "{{protocol}}", - "host": [ - "{{host}}" + { + "name": "Authorize without username", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400\", function () {\r", + " pm.response.to.have.status(400);\r", + "});\r", + "\r", + "pm.test(\"request should fail without username\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData.errors[0].msg).to.be.eql(\"User name is required\");\r", + " pm.expect(jsonData.errors[0].param).to.be.eql(\"username\");\r", + " pm.expect(jsonData.errors[0].location).to.be.eql(\"body\");\r", + "});\r", + "" + ], + "type": "text/javascript" + } + } ], - "path": [ - "api", - "v1", - "authorize" - ] + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"password\":\"G@ppm0ym\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{host}}/api/v1/authorize", + "protocol": "{{protocol}}", + "host": [ + "{{host}}" + ], + "path": [ + "api", + "v1", + "authorize" + ] + } + }, + "response": [] + }, + { + "name": "Authorize without password", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 400\", function () {\r", + " pm.response.to.have.status(400);\r", + "});\r", + "\r", + "pm.test(\"request should fail without password\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData.errors[0].msg).to.be.eql(\"Password is required\");\r", + " pm.expect(jsonData.errors[0].param).to.be.eql(\"password\");\r", + " pm.expect(jsonData.errors[0].location).to.be.eql(\"body\");\r", + "});\r", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\":\"standalone\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{host}}/api/v1/authorize", + "protocol": "{{protocol}}", + "host": [ + "{{host}}" + ], + "path": [ + "api", + "v1", + "authorize" + ] + } + }, + "response": [] } - }, - "response": [] + ] } ], "auth": { diff --git a/test/collections/MPS.postman_environment.json b/src/test/collections/MPS.postman_environment.json similarity index 100% rename from test/collections/MPS.postman_environment.json rename to src/test/collections/MPS.postman_environment.json diff --git a/test/common.spec.ts b/src/test/common.spec.ts similarity index 99% rename from test/common.spec.ts rename to src/test/common.spec.ts index 9f09c7fce..1a5513388 100644 --- a/test/common.spec.ts +++ b/src/test/common.spec.ts @@ -1,5 +1,5 @@ // Import all required methods from common.js file -import { ReadInt, ShortToStr, ReadShort, ShortToStrX, ReadShortX, IntToStr, IntToStrX, ReadIntX, MakeToArray, SplitArray, Clone, IsFilenameValid, ArrayElementMove, rstr2hex, hex2rstr, char2hex, encode_utf8, decode_utf8, data2blob, quoteSplit, parseNameValueList, toNumber, escapeHtml, objKeysToLower, validateString, validateInt, validateArray, validateStrArray, validateObject, validateEmail, validateUsername } from '../src/utils/common' +import { ReadInt, ShortToStr, ReadShort, ShortToStrX, ReadShortX, IntToStr, IntToStrX, ReadIntX, MakeToArray, SplitArray, Clone, IsFilenameValid, ArrayElementMove, rstr2hex, hex2rstr, char2hex, encode_utf8, decode_utf8, data2blob, quoteSplit, parseNameValueList, toNumber, escapeHtml, objKeysToLower, validateString, validateInt, validateArray, validateStrArray, validateObject, validateEmail, validateUsername } from '../utils/common' const v = 256 const p = 0 const s3 = '256' diff --git a/test/helper/ciraclient.js b/src/test/helper/ciraclient.js similarity index 100% rename from test/helper/ciraclient.js rename to src/test/helper/ciraclient.js diff --git a/test/helper/common.js b/src/test/helper/common.js similarity index 100% rename from test/helper/common.js rename to src/test/helper/common.js diff --git a/test/helper/db.ts b/src/test/helper/db.ts similarity index 87% rename from test/helper/db.ts rename to src/test/helper/db.ts index 70a1564cb..de94f99ae 100644 --- a/test/helper/db.ts +++ b/src/test/helper/db.ts @@ -12,10 +12,10 @@ */ import fs from 'fs' -import { configType } from '../../src/models/Config' -import { logger as log } from '../../src/utils/logger' -import { IDbProvider } from '../../src/models/IDbProvider' -import { Credentials } from '../../src/models/models' +import { configType } from '../../models/Config' +import { logger as log } from '../../utils/logger' +import { IDbProvider } from '../../models/IDbProvider' +import { Credentials } from '../../models/models' export class Database implements IDbProvider { private readonly config: configType @@ -114,38 +114,34 @@ export class Database implements IDbProvider { } // check if a GUID is allowed to connect - IsGUIDApproved (guid, cb): void { + IsGUIDApproved (guid): boolean { try { let result = false const guids = this.getAllAmtCredentials() - console.log('test', guids[guid]) if (guids[guid]) { result = true log.silly('Guid found.') } - if (cb) { - cb(result) - } + return result } catch (error) { log.error(`Exception in IsGUIDApproved: ${error}`) } } // CIRA auth - CIRAAuth (guid, username, password, func): void { + CIRAAuth (guid, username, password): boolean { try { - let result = false + let result: boolean = false const cred = this.getCredentialsForGuid(guid) - log.info(cred) if (cred && cred.mpsuser === username && cred.mpspass === password) { result = true - } else if (cred && this.config.use_global_mps_credentials) { - if (this.config.username === username && this.config.pass === password) { + } else if (cred) { + if (username === 'admin' && password === 'P@ssw0rd') { result = true log.silly(`CIRAAuth successful. ${username} ${password}`) } } - if (func) func(result) + return result } catch (error) { log.error(`Exception in CIRAAuth: ${error}`) } diff --git a/test/helper/test_timout.js b/src/test/helper/test_timout.js similarity index 100% rename from test/helper/test_timout.js rename to src/test/helper/test_timout.js diff --git a/test/mpsservertest.test.ts b/src/test/mpsservertest.test.ts similarity index 92% rename from test/mpsservertest.test.ts rename to src/test/mpsservertest.test.ts index 38ed2f81a..803c3deeb 100644 --- a/test/mpsservertest.test.ts +++ b/src/test/mpsservertest.test.ts @@ -8,10 +8,10 @@ import * as net from 'net' import * as fs from 'fs' import * as https from 'https' import * as forge from 'node-forge' -import { certificates } from '../src/utils/certificates' -import { certificatesType, configType } from '../src/models/Config' -import { MPSMicroservice } from '../src/mpsMicroservice' -import { MPSServer } from '../src/server/mpsserver' +import { certificates } from '../utils/certificates' +import { certificatesType, configType } from '../models/Config' +import { MPSMicroservice } from '../mpsMicroservice' +import { MPSServer } from '../server/mpsserver' import { join } from 'path' import { Database } from './helper/db' @@ -20,9 +20,6 @@ import { Database } from './helper/db' const config: configType = { common_name: 'localhost', port: 4433, - username: 'standalone', - pass: 'G@ppm0ym', - use_global_mps_credentials: true, country: 'US', company: 'NoCorp', debug: true, @@ -187,8 +184,8 @@ describe('MPS Server', function () { port: config.port, clientName: 'hostname-prefix', uuid: '12345678-9abc-def1-2345-123456789000', // GUID template, last few chars of the string will be replaced - username: config.username, // mps username - password: config.pass, // mps password + username: 'admin', // mps username + password: 'P@ssw0rd', // mps password keepalive: 10000, // interval for keepalive ping debug: false, testciraState: 'USERAUTH_SUCCESS' // USERAUTH_SERVICE_ACCEPT, PFWD_SERVICE_ACCEPT, GLOBAL_REQUEST_SUCCESS, USERAUTH_SUCCESS, USERAUTH_FAILURE, PROTOCOL_VERSION_SENT, KEEPALIVE_REPLY @@ -208,8 +205,8 @@ describe('MPS Server', function () { port: config.port, clientName: 'hostname-prefix', uuid: '12345678-9abc-def1-2345-123456789000', // GUID template, last few chars of the string will be replaced - username: config.username, // mps username - password: config.pass, // mps password + username: 'admin', // mps username + password: 'P@ssw0rd', // mps password keepalive: 10000, // interval for keepalive ping debug: false, testciraState: 'USERAUTH_SERVICE_ACCEPT' // USERAUTH_SERVICE_ACCEPT, PFWD_SERVICE_ACCEPT, GLOBAL_REQUEST_SUCCESS, USERAUTH_SUCCESS, USERAUTH_FAILURE, PROTOCOL_VERSION_SENT, KEEPALIVE_REPLY @@ -230,8 +227,8 @@ describe('MPS Server', function () { port: config.port, clientName: 'hostname-prefix', uuid: '12345678-9abc-def1-2345-123456789000', // GUID template, last few chars of the string will be replaced - username: config.username, // mps username - password: config.pass, // mps password + username: 'admin', // mps username + password: 'P@ssw0rd', // mps password keepalive: 10000, // interval for keepalive ping debug: false, testciraState: 'PFWD_SERVICE_ACCEPT' // USERAUTH_SERVICE_ACCEPT, PFWD_SERVICE_ACCEPT, GLOBAL_REQUEST_SUCCESS, USERAUTH_SUCCESS, USERAUTH_FAILURE, PROTOCOL_VERSION_SENT, KEEPALIVE_REPLY @@ -252,8 +249,8 @@ describe('MPS Server', function () { port: config.port, clientName: 'hostname-prefix', uuid: '12345678-9abc-def1-2345-123456789000', // GUID template, last few chars of the string will be replaced - username: config.username, // mps username - password: config.pass, // mps password + username: 'admin', // mps username + password: 'P@ssw0rd', // mps password keepalive: 10000, // interval for keepalive ping debug: false, testciraState: 'GLOBAL_REQUEST_SUCCESS' // USERAUTH_SERVICE_ACCEPT, PFWD_SERVICE_ACCEPT, GLOBAL_REQUEST_SUCCESS, USERAUTH_SUCCESS, USERAUTH_FAILURE, PROTOCOL_VERSION_SENT, KEEPALIVE_REPLY @@ -274,8 +271,8 @@ describe('MPS Server', function () { port: config.port, clientName: 'hostname-prefix', uuid: '12345678-9abc-def1-2345-123456789000', // GUID template, last few chars of the string will be replaced - username: config.username, // mps username - password: config.pass, // mps password + username: 'admin', // mps username + password: 'P@ssw0rd', // mps password keepalive: 10000, // interval for keepalive ping debug: false, testciraState: 'PROTOCOL_VERSION_SENT' // USERAUTH_SERVICE_ACCEPT, PFWD_SERVICE_ACCEPT, GLOBAL_REQUEST_SUCCESS, USERAUTH_SUCCESS, USERAUTH_FAILURE, PROTOCOL_VERSION_SENT, KEEPALIVE_REPLY @@ -296,8 +293,8 @@ describe('MPS Server', function () { port: config.port, clientName: 'hostname-prefix', uuid: '12345678-9abc-def1-2345-123456789000', // GUID template, last few chars of the string will be replaced - username: config.username, // mps username - password: config.pass, // mps password + username: 'admin', // mps username + password: 'P@ssw0rd', // mps password keepalive: 10000, // interval for keepalive ping debug: false, testciraState: 'KEEPALIVE_REPLY' // USERAUTH_SERVICE_ACCEPT, PFWD_SERVICE_ACCEPT, GLOBAL_REQUEST_SUCCESS, USERAUTH_SUCCESS, USERAUTH_FAILURE, PROTOCOL_VERSION_SENT, KEEPALIVE_REPLY @@ -318,7 +315,7 @@ describe('MPS Server', function () { port: config.port, clientName: 'hostname-prefix', uuid: '12345678-9abc-def1-2345-123456789000', // GUID template, last few chars of the string will be replaced - username: config.username, // mps username + username: 'admin', // mps username password: 'pasdbenaksd', // Invalid mps password keepalive: 10000, // interval for keepalive ping debug: false, diff --git a/test/private/data.json b/src/test/private/data.json similarity index 93% rename from test/private/data.json rename to src/test/private/data.json index 99f585354..cfcd68cc7 100644 --- a/test/private/data.json +++ b/src/test/private/data.json @@ -12,7 +12,7 @@ "mpsuser": "standalone", "mpspass": "G@ppm0ym", "amtuser": "admin", - "amtpass": "G@ppm0ym" + "amtpass": "P@ssw0rd" } } } \ No newline at end of file diff --git a/src/utils/AuthDbProvider.ts b/src/utils/AuthDbProvider.ts new file mode 100644 index 000000000..4a0fb89e4 --- /dev/null +++ b/src/utils/AuthDbProvider.ts @@ -0,0 +1,73 @@ +/********************************************************************* +* Copyright (c) Intel Corporation 2020 +* SPDX-License-Identifier: Apache-2.0 +**********************************************************************/ +import { IDbProvider } from '../models/IDbProvider' +import { ISecretManagerService } from '../models/ISecretManagerService' +import { configType } from '../models/Config' +import { IDeviceDb } from '../interfaces/IDeviceDb' + +export class AuthDbProvider implements IDbProvider { + secretsManager: ISecretManagerService + deviceDb: IDeviceDb + secretsPath: string + logger: any + config: configType + constructor (secretsManager: ISecretManagerService, deviceDb: IDeviceDb, logger: any, config: configType) { + this.secretsManager = secretsManager + this.deviceDb = deviceDb + this.secretsPath = config.secrets_path + this.logger = logger + } + + async CIRAAuth (guid: string, username: string, password: string): Promise { + try { + const results = await this.deviceDb.getById(guid) + if (results != null) { + this.logger.debug(`CIRAAuth: device found: ${guid}, ${JSON.stringify(results)}`) + } else { + this.logger.warn(`CIRAAuth: device not found: ${guid}`) + return false + } + + const pwd = await this.secretsManager.getSecretFromKey(`${this.secretsPath}devices/${guid}`, 'MPS_PASSWORD') + if (username === results.mpsusername && password === pwd) { + return true + } + this.logger.info('invalid mps credentials') + return false + } catch (error) { + this.logger.error('Error while retrieving server credentials :', error) + return false + } + } + + async getAmtPassword (guid: string): Promise { + try { + const user = 'admin' + const data: any = await this.secretsManager.getSecretAtPath(`${this.secretsPath}devices/${guid}`) + const amtpass = data.data.AMT_PASSWORD + return [user, amtpass] + } catch (error) { + this.logger.error('Error while retrieving device credentials :', error) + return null + } + } + + async IsGUIDApproved (guid: string): Promise { + try { + let result: boolean = false + const results = await this.deviceDb.getById(guid) + if (results != null) { + this.logger.debug(`IsGUIDApproved: device found: ${guid}, ${JSON.stringify(results)}`) + result = true + } else { + this.logger.warn(`IsGUIDApproved: device not found: ${guid}`) + result = false + } + return result + } catch (error) { + this.logger.error('Error while retrieving guid:', error) + } + } +} diff --git a/src/utils/vaultDbProvider.ts b/src/utils/vaultDbProvider.ts deleted file mode 100644 index adddb208d..000000000 --- a/src/utils/vaultDbProvider.ts +++ /dev/null @@ -1,87 +0,0 @@ -/********************************************************************* -* Copyright (c) Intel Corporation 2020 -* SPDX-License-Identifier: Apache-2.0 -**********************************************************************/ -import { IDbProvider } from '../models/IDbProvider' -import { ISecretManagerService } from '../models/ISecretManagerService' -import { configType } from '../models/Config' - -export class SecretsDbProvider implements IDbProvider { - secretsManager: ISecretManagerService - secretsPath: string - logger: any - config: configType - constructor (secretsManager: ISecretManagerService, logger: any, config: configType) { - this.secretsManager = secretsManager - this.secretsPath = config.secrets_path - this.logger = logger - this.config = config - } - - async CIRAAuth (guid: string, username: string, password: string, cb: any): Promise { - try { - // let user = await this.secretsManager.getSecretFromKey(`${this.secretsPath}devices/${guid}`, `username`); - // let pwd = await this.secretsManager.getSecretFromKey(`${this.secretsPath}devices/${guid}`, `password`); - let user, pwd - if (this.config.use_global_mps_credentials) { - // user = await this.secretsManager.getSecretFromKey(`${this.secretsPath}global`, `username`); - // pwd = await this.secretsManager.getSecretFromKey(`${this.secretsPath}global`, `password`); - - // TODO: move this to vault. - user = this.config.username - pwd = this.config.pass - - if (username === user && password === pwd) { - if (cb) { - cb(true) - } - return - } - this.logger.info('invalid mps credentials') - if (cb) cb(false) - } else { - user = await this.secretsManager.getSecretFromKey(`${this.secretsPath}devices/${guid}`, 'mps_username') - pwd = await this.secretsManager.getSecretFromKey(`${this.secretsPath}devices/${guid}`, 'mps_password') - - if (username === user && password === pwd) { - if (cb) { - cb(true) - } - return - } - this.logger.info('invalid mps credentials') - if (cb) cb(false) - } - } catch (error) { - this.logger.error('Error while retrieving server credentials :', error) - return false - } - } - - async getAmtPassword (guid: string): Promise { - try { - const user = 'admin' - const data: any = await this.secretsManager.getSecretAtPath(`${this.secretsPath}devices/${guid}`) - const amtpass = data.data.AMT_PASSWORD - return [user, amtpass] - } catch (error) { - this.logger.error('Error while retrieving device credentials :', error) - return null - } - } - - async IsGUIDApproved (guid: string, cb: any): Promise { - try { - let result = false - const guids = await this.secretsManager.getSecretAtPath(`${this.secretsPath}devices/${guid}`) - if (guids?.data.AMT_PASSWORD != null) { - result = true - } - if (cb) { - cb(result) - } - } catch (error) { - this.logger.error('Error while retrieving guid:', error) - } - } -} diff --git a/tsconfig.json b/tsconfig.json index 5d26418d8..ed7dd4c85 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,6 @@ }, "include":[ "./src/**/*", - "./test/**/*" ], "type":[ "@types/jest",