Skip to content

Commit

Permalink
refactor(auto): check for jwt secret and mps credentials
Browse files Browse the repository at this point in the history
BREAKING CHANGES: db schema changed to accept mps username
  • Loading branch information
madhavilosetty-intel committed Jun 10, 2021
1 parent b57c0ca commit c9fa298
Show file tree
Hide file tree
Showing 31 changed files with 349 additions and 238 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/api-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand Down
9 changes: 3 additions & 6 deletions .mpsrc
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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":"*",
Expand Down
1 change: 1 addition & 0 deletions data/initMPS.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ CREATE TABLE IF NOT EXISTS devices(
hostname varchar(256),
mpsinstance text,
connectionstatus boolean,
mpsusername text,
CONSTRAINT device_guid UNIQUE(guid)
);
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 6 additions & 4 deletions src/db/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,14 @@ export class DeviceDb implements IDeviceDb {
*/
async insert (device: Device): Promise<Device> {
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)
Expand All @@ -97,13 +98,14 @@ export class DeviceDb implements IDeviceDb {
*/
async update (device: Device): Promise <Device> {
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)
Expand Down
3 changes: 2 additions & 1 deletion src/db/mapToDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
9 changes: 4 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
}

Expand All @@ -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']
Expand Down
3 changes: 0 additions & 3 deletions src/models/Config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions src/models/IDbProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
1 change: 1 addition & 0 deletions src/models/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Device {
mpsInstance: string
hostname: string
guid: string
mpsusername: string
tags: string[]
}
export interface Credentials {
Expand Down
19 changes: 19 additions & 0 deletions src/routes/auth/authValidator.ts
Original file line number Diff line number Diff line change
@@ -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')
]
}
38 changes: 21 additions & 17 deletions src/routes/auth/login.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import { validationResult } from 'express-validator'
import jws from 'jws'
export async function login (req, res): Promise<void> {
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!' })
}
}
2 changes: 2 additions & 0 deletions src/routes/devices/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export async function insertDevice (req, res): Promise<void> {
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 {
Expand All @@ -30,6 +31,7 @@ export async function insertDevice (req, res): Promise<void> {
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)
Expand Down
3 changes: 3 additions & 0 deletions src/routes/devices/deviceValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export const validator = (): any => {
check('hostname')
.optional({ nullable: true })
.isString(),
check('mpsusername')
.optional({ nullable: true })
.isString(),
check('tags')
.optional()
.isArray()
Expand Down
3 changes: 2 additions & 1 deletion src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
42 changes: 19 additions & 23 deletions src/server/mpsserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> => {
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
}
Expand All @@ -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<void> => {
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: {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading

0 comments on commit c9fa298

Please sign in to comment.