Skip to content

Commit

Permalink
feat(api): adds multitenancy support from header
Browse files Browse the repository at this point in the history
  • Loading branch information
rsdmike committed Nov 19, 2022
1 parent b7a849f commit c45326f
Show file tree
Hide file tree
Showing 70 changed files with 343 additions and 195 deletions.
4 changes: 3 additions & 1 deletion .rpsrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@
"mps_server": "http://localhost:3000",
"delay_timer": 12,
"mqtt_address": "",
"disable_cira_domain_name": ""
"disable_cira_domain_name": "",
"jwt_token_header": "x-id-token",
"jwt_tenant_property": "custom:tenantId"
}
90 changes: 86 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"express-ws": "^5.0.2",
"got": "^11.8.5",
"http-z": "^6.1.2",
"jws": "^4.0.0",
"minimist": "^1.2.7",
"mqtt": "^4.3.7",
"node-forge": "^1.3.1",
Expand All @@ -69,6 +70,7 @@
"@types/body-parser": "^1.19.2",
"@types/express": "^4.17.14",
"@types/jest": "^27.5.0",
"@types/jws": "^3.2.4",
"@types/node": "^16.18.3",
"@types/node-forge": "^1.3.0",
"@types/pg": "^8.6.5",
Expand Down
4 changes: 2 additions & 2 deletions src/DataProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ export class DataProcessor {
this.setConnectionParams(clientId)
activation.service.start()
if (devices[clientId].activationStatus) {
activation.service.send({ type: 'ACTIVATED', clientId: clientId, isActivated: true })
activation.service.send({ type: 'ACTIVATED', tenantId: clientMsg.tenantId, clientId: clientId, isActivated: true })
} else {
activation.service.send({ type: 'ACTIVATION', clientId: clientId })
activation.service.send({ type: 'ACTIVATION', tenantId: clientMsg.tenantId, clientId: clientId })
}
}

Expand Down
15 changes: 9 additions & 6 deletions src/DomainCredentialManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ export class DomainCredentialManager implements IDomainCredentialManager {
/**
* @description get the provisioning cert storage format for a given domain
* @param {string} domainSuffix
* @param {string} tenantId
* @returns {string} returns path to provisioning cert storage format if domain is found otherwise null
*/
async getProvisioningCertStorageType (domainSuffix: string): Promise<string> {
const domain = await this.amtDomains.getDomainByDomainSuffix(domainSuffix)
async getProvisioningCertStorageType (domainSuffix: string, tenantId: string): Promise<string> {
const domain = await this.amtDomains.getDomainByDomainSuffix(domainSuffix, tenantId)
let format: string = null
if (domain?.provisioningCertStorageFormat) {
format = domain.provisioningCertStorageFormat
Expand All @@ -40,10 +41,11 @@ export class DomainCredentialManager implements IDomainCredentialManager {
/**
* @description get the provisioning cert for a given domain
* @param {string} domainSuffix
* @param {string} tenantId
* @returns {AMTDomain} returns domain object
*/
async getProvisioningCert (domainSuffix: string): Promise<AMTDomain> {
const domain = await this.amtDomains.getDomainByDomainSuffix(domainSuffix)
async getProvisioningCert (domainSuffix: string, tenantId: string): Promise<AMTDomain> {
const domain = await this.amtDomains.getDomainByDomainSuffix(domainSuffix, tenantId)
this.logger.debug(`domain : ${JSON.stringify(domain)}`)
let certPwd = null
if (domain?.provisioningCert) {
Expand All @@ -62,10 +64,11 @@ export class DomainCredentialManager implements IDomainCredentialManager {
/**
* @description Checks if the AMT domain exists or not
* @param {string} domainSuffix
* @param {string} tenantId
* @returns {boolean} returns true if domain exists otherwise false.
*/
public async doesDomainExist (domainSuffix: string): Promise<boolean> {
if (await this.amtDomains.getDomainByDomainSuffix(domainSuffix)) {
public async doesDomainExist (domainSuffix: string, tenantId: string): Promise<boolean> {
if (await this.amtDomains.getDomainByDomainSuffix(domainSuffix, tenantId)) {
return true
} else {
return false
Expand Down
30 changes: 15 additions & 15 deletions src/ProfileManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export class ProfileManager implements IProfileManager {
* @param {string} profileName profile to look up
* @returns {string} returns the activation to be performed
*/
public async getActivationMode (profileName: string): Promise<string> {
const profile = await this.getAmtProfile(profileName)
public async getActivationMode (profileName: string, tenantId: string): Promise<string> {
const profile = await this.getAmtProfile(profileName, tenantId)
let activation: string

if (profile?.activation) {
Expand All @@ -49,8 +49,8 @@ export class ProfileManager implements IProfileManager {
* @param {string} profile of cira config
* @returns {string} returns the config for CIRA for a given profile
*/
public async getCiraConfiguration (profileName: string): Promise<CIRAConfig> {
const profile = await this.getAmtProfile(profileName)
public async getCiraConfiguration (profileName: string, tenantId: string): Promise<CIRAConfig> {
const profile = await this.getAmtProfile(profileName, tenantId)
let ciraConfig: CIRAConfig

if (profile?.ciraConfigName && profile.ciraConfigObject) {
Expand All @@ -68,8 +68,8 @@ export class ProfileManager implements IProfileManager {
* @param {string} profileName profile name of amt password
* @returns {string} returns the amt password for a given profile
*/
public async getAmtPassword (profileName: string): Promise<string> {
const profile: AMTConfiguration = await this.getAmtProfile(profileName)
public async getAmtPassword (profileName: string, tenantId: string): Promise<string> {
const profile: AMTConfiguration = await this.getAmtProfile(profileName, tenantId)
let amtPassword: string
if (profile) {
if (profile.generateRandomPassword) {
Expand Down Expand Up @@ -101,8 +101,8 @@ export class ProfileManager implements IProfileManager {
* @param {string} profileName profile name of amt password
* @returns {string} returns the amt password for a given profile
*/
public async getMEBxPassword (profileName: string): Promise<string> {
const profile: AMTConfiguration = await this.getAmtProfile(profileName)
public async getMEBxPassword (profileName: string, tenantId: string): Promise<string> {
const profile: AMTConfiguration = await this.getAmtProfile(profileName, tenantId)
let mebxPassword: string
if (profile) {
if (profile.generateRandomMEBxPassword) {
Expand Down Expand Up @@ -136,8 +136,8 @@ export class ProfileManager implements IProfileManager {
* @param {string} profileName profile name of MPS password
* @returns {string} returns the MPS password for a given profile
*/
public async getMPSPassword (profileName: string): Promise<string> {
const profile: AMTConfiguration = await this.getAmtProfile(profileName)
public async getMPSPassword (profileName: string, tenantId: string): Promise<string> {
const profile: AMTConfiguration = await this.getAmtProfile(profileName, tenantId)
let mpsPassword: string

if (profile?.ciraConfigObject) {
Expand Down Expand Up @@ -165,15 +165,15 @@ export class ProfileManager implements IProfileManager {
* @param {string} profile
* @returns {AMTConfiguration} returns AMTConfig object if profile exists otherwise null.
*/
public async getAmtProfile (profile: string): Promise<AMTConfiguration> {
public async getAmtProfile (profile: string, tenantId: string): Promise<AMTConfiguration> {
try {
if (!profile) {
return null
}
const amtProfile: AMTConfiguration = await this.amtConfigurations.getByName(profile)
const amtProfile: AMTConfiguration = await this.amtConfigurations.getByName(profile, tenantId)
// If the CIRA Config associated with profile, retrieves from DB
if (amtProfile?.ciraConfigName != null) {
amtProfile.ciraConfigObject = await this.amtConfigurations.getCiraConfigForProfile(amtProfile.ciraConfigName)
amtProfile.ciraConfigObject = await this.amtConfigurations.getCiraConfigForProfile(amtProfile.ciraConfigName, tenantId)
}
// If the TLS Config associated with profile, retrieves from DB
if (amtProfile.tlsMode != null) {
Expand All @@ -196,8 +196,8 @@ export class ProfileManager implements IProfileManager {
* @param {string} profile
* @returns {boolean} returns true if profile exists otherwise false.
*/
public async doesProfileExist (profileName: string): Promise<boolean> {
const profile = await this.getAmtProfile(profileName)
public async doesProfileExist (profileName: string, tenantId: string): Promise<boolean> {
const profile = await this.getAmtProfile(profileName, tenantId)
if (profile) {
// this.logger.debug(`found profile ${profileName}`);
return true
Expand Down
18 changes: 9 additions & 9 deletions src/Validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class Validator implements IValidator {
throw new RPSError(`Device ${payload.uuid} activation failed. Missing password.`)
}
// Check for client requested action and profile activation
const profile: AMTConfiguration = await this.configurator.profileManager.getAmtProfile(payload.profile)
const profile: AMTConfiguration = await this.configurator.profileManager.getAmtProfile(payload.profile, msg.tenantId)
if (!profile) {
throw new RPSError(`Device ${payload.uuid} activation failed. ${payload.profile} does not match list of available AMT profiles.`)
}
Expand All @@ -96,7 +96,7 @@ export class Validator implements IValidator {
}
// Validate client message to configure ACM message
if (clientObj.action === ClientAction.ADMINCTLMODE) {
await this.verifyActivationMsgForACM(payload)
await this.verifyActivationMsgForACM(msg)
}
// }
}
Expand Down Expand Up @@ -242,15 +242,15 @@ export class Validator implements IValidator {
return msg.payload
}

async verifyActivationMsgForACM (payload: Payload): Promise<void> {
if (!payload.certHashes) {
throw new RPSError(`Device ${payload.uuid} activation failed. Missing certificate hashes from the device.`)
async verifyActivationMsgForACM (msg: ClientMsg): Promise<void> {
if (!msg.payload.certHashes) {
throw new RPSError(`Device ${msg.payload.uuid} activation failed. Missing certificate hashes from the device.`)
}
if (!payload.fqdn) {
throw new RPSError(`Device ${payload.uuid} activation failed. Missing DNS Suffix.`)
if (!msg.payload.fqdn) {
throw new RPSError(`Device ${msg.payload.uuid} activation failed. Missing DNS Suffix.`)
}
if (!(await this.configurator.domainCredentialManager.doesDomainExist(payload.fqdn))) {
throw new RPSError(`Device ${payload.uuid} activation failed. Specified AMT domain suffix: ${payload.fqdn} does not match list of available AMT domain suffixes.`)
if (!(await this.configurator.domainCredentialManager.doesDomainExist(msg.payload.fqdn, msg.tenantId))) {
throw new RPSError(`Device ${msg.payload.uuid} activation failed. Specified AMT domain suffix: ${msg.payload.fqdn} does not match list of available AMT domain suffixes.`)
}
}

Expand Down
1 change: 1 addition & 0 deletions src/commandParser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ function getBasicMessage (): ClientMsg {
protocolVersion: '4.0.0',
status: 'ok',
message: "all's good!",
tenantId: '',
payload: {
ver: '11.8.50',
build: '3425',
Expand Down
Loading

0 comments on commit c45326f

Please sign in to comment.