diff --git a/src/stateMachines/ciraConfiguration.test.ts b/src/stateMachines/ciraConfiguration.test.ts index 373639ae5..95d9dd196 100644 --- a/src/stateMachines/ciraConfiguration.test.ts +++ b/src/stateMachines/ciraConfiguration.test.ts @@ -32,6 +32,33 @@ jest.unstable_mockModule('./common.js', () => ({ const { CIRAConfiguration, MPSType } = await import('./ciraConfiguration.js') +const pullRemoteAccessPolicyAppliesToMPSResponse = { + Envelope: { + Body: { + PullResponse: { + Items: { + AMT_RemoteAccessPolicyAppliesToMPS: [ + { + PolicySet: { + ReferenceParameters: { + SelectorSet: { Selector: [{ $: { Name: 'PolicyRuleName' }, _: 'TestPolicy1' }] } + } + } + }, + { + PolicySet: { + ReferenceParameters: { + SelectorSet: { Selector: [{ $: { Name: 'PolicyRuleName' }, _: 'TestPolicy2' }] } + } + } + } + ] + } + } + } + } +} + describe('CIRA Configuration State Machine', () => { const clientId = randomUUID() const httpHandler = new HttpHandler() @@ -83,7 +110,8 @@ describe('CIRA Configuration State Machine', () => { message: null, ciraConfig: null, statusMessage: '', - privateCerts: [] + privateCerts: [], + remoteAccessPolicies: [], } machineConfig = { actors: { @@ -101,7 +129,7 @@ describe('CIRA Configuration State Machine', () => { enumerateRemoteAccessPolicyAppliesToMPS: fromPromise( async ({ input }) => await Promise.resolve(wsmanEnumerationResponse) ), - pullRemoteAccessPolicyAppliesToMPS: fromPromise(async ({ input }) => await Promise.resolve({})), + pullRemoteAccessPolicyAppliesToMPS: fromPromise(async ({ input }) => await Promise.resolve(pullRemoteAccessPolicyAppliesToMPSResponse)), putRemoteAccessPolicyAppliesToMPS: fromPromise(async ({ input }) => await Promise.resolve({})), userInitiatedConnectionService: fromPromise( async ({ input }) => @@ -129,9 +157,11 @@ describe('CIRA Configuration State Machine', () => { 'ENUMERATE_MANAGEMENT_PRESENCE_REMOTE_SAP', 'PULL_MANAGEMENT_PRESENCE_REMOTE_SAP', 'ADD_REMOTE_ACCESS_POLICY_RULE', + 'ADD_USER_INITIATED_REMOTE_ACCESS_POLICY_RULE', 'ENUMERATE_REMOTE_ACCESS_POLICY_APPLIESTOMPS', 'PULL_REMOTE_ACCESS_POLICY_APPLIESTOMPS', 'PUT_REMOTE_ACCESS_POLICY_APPLIESTOMPS', + 'CHECK_REMOTE_ACCESS_POLICY_APPLIESTOMPS', 'USER_INITIATED_CONNECTION_SERVICE', 'GET_ENVIRONMENT_DETECTION_SETTINGS', 'PUT_ENVIRONMENT_DETECTION_SETTINGS', @@ -144,13 +174,15 @@ describe('CIRA Configuration State Machine', () => { } const ciraConfigurationService = createActor(mockCiraConfigurationMachine, { input: machineContext }) ciraConfigurationService.subscribe((state) => { - const expected = flowStates[currentStateIndex++] - const actual = state.value as string - expect(actual).toEqual(expected) - if (state.matches('SUCCESS') || state.matches('FAILURE') || currentStateIndex === flowStates.length) { - const status = devices[clientId].status.CIRAConnection - expect(status).toEqual('Configured') - done() + if (state.value) { + const expected = flowStates[currentStateIndex++] + const actual = state.value as string + expect(actual).toEqual(expected) + if (state.matches('SUCCESS') || state.matches('FAILURE') || currentStateIndex === flowStates.length) { + const status = devices[clientId].status.CIRAConnection + expect(status).toEqual('Configured') + done() + } } }) ciraConfigurationService.start() @@ -274,9 +306,9 @@ describe('CIRA Configuration State Machine', () => { expect(loggerSpy).toHaveBeenCalled() }) it('should send wsman on call to putRemoteAccessPolicyAppliesToMPS', async () => { - machineContext.message = { - Envelope: { Body: { PullResponse: { Items: { AMT_RemoteAccessPolicyAppliesToMPS: MPSType } } } } - } + machineContext.message = pullRemoteAccessPolicyAppliesToMPSResponse + machineContext.remoteAccessPolicies = + machineContext.message.Envelope.Body.PullResponse.Items.AMT_RemoteAccessPolicyAppliesToMPS await ciraStateMachineImpl.putRemoteAccessPolicyAppliesToMPS({ input: machineContext }) expect(invokeWsmanCallSpy).toHaveBeenCalled() }) @@ -296,7 +328,6 @@ describe('CIRA Configuration State Machine', () => { describe('send wsman message to add MPS server and certificate', () => { beforeEach(() => { - // spoof getCiraConfiguration machineContext.ciraConfig = ciraConfig }) it('should send wsman message to add Trusted Root Certificate', async () => { diff --git a/src/stateMachines/ciraConfiguration.ts b/src/stateMachines/ciraConfiguration.ts index b6b03236a..28d8db626 100644 --- a/src/stateMachines/ciraConfiguration.ts +++ b/src/stateMachines/ciraConfiguration.ts @@ -32,6 +32,7 @@ export interface CIRAConfigContext extends CommonContext { amt?: AMT.Messages retryCount: number tenantId: string + remoteAccessPolicies: any[] } export interface CIRAConfigEvent { @@ -135,6 +136,24 @@ export class CIRAConfiguration { } } + addUserInitiatedRemoteAccessPolicyRule = async ({ input }: { input: CIRAConfigContext }): Promise => { + if (input.amt != null) { + const selector = { + name: 'Name', + value: input.message.Envelope.Body.PullResponse.Items.AMT_ManagementPresenceRemoteSAP.Name + } + const policy: AMT.Models.RemoteAccessPolicyRule = { + Trigger: 0, // 0 – User Initiated + TunnelLifeTime: 300, // 300 seconds + ExtendedData: '' // Empty for User Initiated + } + input.xmlMessage = input.amt.RemoteAccessService.AddRemoteAccessPolicyRule(policy, selector) + return await invokeWsmanCall(input, 2) + } else { + this.logger.error('Null object in addUserInitiatedRemoteAccessPolicyRule()') + } + } + getEnvironmentDetectionSettings = async ({ input }: { input: CIRAConfigContext }): Promise => { if (input.amt != null) { input.xmlMessage = input.amt.EnvironmentDetectionSettingData.Get() @@ -213,9 +232,24 @@ export class CIRAConfiguration { putRemoteAccessPolicyAppliesToMPS = async ({ input }: { input: CIRAConfigContext }): Promise => { if (input.amt != null) { - const data = input.message.Envelope.Body.PullResponse.Items.AMT_RemoteAccessPolicyAppliesToMPS + const data = input.remoteAccessPolicies.length > 0 ? input.remoteAccessPolicies[0] : input.remoteAccessPolicies data.MpsType = MPSType.Both - input.xmlMessage = input.amt.RemoteAccessPolicyAppliesToMPS.Put(data) + data.OrderOfAccess = 0 + + let policySelector + try { + policySelector = data.PolicySet.ReferenceParameters.SelectorSet.Selector.find( + (selector: any) => selector.$?.Name === 'PolicyRuleName' + ) + } catch (err) { + this.logger.error('Error in putRemoteAccessPolicyAppliesToMPS()', err) + } + + const policyName = policySelector?._ + const baseXml = input.amt.RemoteAccessPolicyAppliesToMPS.Put(data) + const customSelector = `
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
http://intel.com/wbem/wscim/1/amt-schema/1/AMT_ManagementPresenceRemoteSAPAMT_ManagementPresenceRemoteSAPIntel(r) AMT:Management Presence Server 0CIM_ComputerSystemIntel(r) AMT
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
http://intel.com/wbem/wscim/1/amt-schema/1/AMT_RemoteAccessPolicyRuleAMT_RemoteAccessPolicyRule${policyName}CIM_ComputerSystemIntel(r) AMT
` + input.xmlMessage = baseXml.replace('', customSelector.trim()) + return await invokeWsmanCall(input, 2) } else { this.logger.error('Null object in putRemoteAccessPolicyAppliesToMPS()') @@ -245,6 +279,7 @@ export class CIRAConfiguration { pullManagementPresenceRemoteSAP: fromPromise(this.pullManagementPresenceRemoteSAP), addRemoteAccessPolicyRule: fromPromise(this.addRemoteAccessPolicyRule), enumerateRemoteAccessPolicyAppliesToMPS: fromPromise(this.enumerateRemoteAccessPolicyAppliesToMPS), + addUserInitiatedRemoteAccessPolicyRule: fromPromise(this.addUserInitiatedRemoteAccessPolicyRule), pullRemoteAccessPolicyAppliesToMPS: fromPromise(this.pullRemoteAccessPolicyAppliesToMPS), putRemoteAccessPolicyAppliesToMPS: fromPromise(this.putRemoteAccessPolicyAppliesToMPS), userInitiatedConnectionService: fromPromise(this.userInitiatedConnectionService), @@ -258,7 +293,14 @@ export class CIRAConfiguration { guards: { userInitiatedConnectionServiceSuccessful: ({ event }) => event.output.Envelope.Body?.RequestStateChange_OUTPUT?.ReturnValue === 0, - shouldRetry: ({ context, event }) => context.retryCount < 3 && event.output instanceof UNEXPECTED_PARSE_ERROR + shouldRetry: ({ context, event }) => context.retryCount < 3 && event.output instanceof UNEXPECTED_PARSE_ERROR, + isRemoteAccessPolicyExists: ({ context }) => { + context.remoteAccessPolicies = context.remoteAccessPolicies.slice(1) + if (context.remoteAccessPolicies.length > 0) { + return true + } + return false + } }, actions: { 'Update Configuration Status': ({ context, event }) => { @@ -284,7 +326,8 @@ export class CIRAConfiguration { privateCerts: input.privateCerts, tenantId: input.tenantId, retryCount: input.retryCount, - amt: input.amt + amt: input.amt, + remoteAccessPolicies: [] }), id: 'cira-machine', initial: 'CIRACONFIGURED', @@ -310,7 +353,8 @@ export class CIRAConfiguration { ciraConfig: context.ciraConfig, retryCount: context.retryCount, httpHandler: context.httpHandler, - status: context.status + status: context.status, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'get-cira-config', onDone: { @@ -331,7 +375,8 @@ export class CIRAConfiguration { ciraConfig: context.ciraConfig, retryCount: context.retryCount, httpHandler: context.httpHandler, - status: context.status + status: context.status, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'set-mps-password', onDone: { @@ -367,7 +412,8 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'add-trusted-root-certificate', onDone: { @@ -391,7 +437,8 @@ export class CIRAConfiguration { ciraConfig: context.ciraConfig, retryCount: context.retryCount, httpHandler: context.httpHandler, - status: context.status + status: context.status, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'save-mps-password-to-secret-provider', onDone: 'SAVE_DEVICE_TO_MPS', @@ -412,7 +459,8 @@ export class CIRAConfiguration { ciraConfig: context.ciraConfig, retryCount: context.retryCount, httpHandler: context.httpHandler, - status: context.status + status: context.status, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'save-device-to-mps', onDone: 'ADD_MPS', @@ -436,7 +484,8 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'add-mps', onDone: { @@ -463,7 +512,8 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'enumerate-management-presence-remote-sap', onDone: { @@ -490,7 +540,8 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'pull-management-presence-remote-sap', onDone: { @@ -524,16 +575,42 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'add-remote-policy-access-rule', - onDone: 'ENUMERATE_REMOTE_ACCESS_POLICY_APPLIESTOMPS', + onDone: 'ADD_USER_INITIATED_REMOTE_ACCESS_POLICY_RULE', onError: { actions: assign({ statusMessage: () => 'Failed to add remote policy access rule' }), target: 'FAILURE' } } }, + ADD_USER_INITIATED_REMOTE_ACCESS_POLICY_RULE: { + invoke: { + src: 'addUserInitiatedRemoteAccessPolicyRule', + input: ({ context }) => ({ + clientId: context.clientId, + tenantId: context.tenantId, + profile: context.profile, + profileName: context.profile?.profileName, + ciraConfig: context.ciraConfig, + retryCount: context.retryCount, + status: context.status, + httpHandler: context.httpHandler, + message: context.message, + amt: context.amt, + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies + }), + id: 'add-user-initiated-remote-policy-access-rule', + onDone: 'ENUMERATE_REMOTE_ACCESS_POLICY_APPLIESTOMPS', + onError: { + actions: assign({ statusMessage: () => 'Failed to add User Initiated remote policy access rule' }), + target: 'FAILURE' + } + } + }, ENUMERATE_REMOTE_ACCESS_POLICY_APPLIESTOMPS: { invoke: { src: 'enumerateRemoteAccessPolicyAppliesToMPS', @@ -548,7 +625,8 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'enumerate-remote-access-policy-rule', onDone: { @@ -575,11 +653,20 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'pull-remote-access-policy-rule', onDone: { - actions: [assign({ message: ({ event }) => event.output }), 'Reset Retry Count'], + actions: [ + assign({ + message: ({ event }) => event.output, + remoteAccessPolicies: ({ event }) => + event.output.Envelope.Body.PullResponse.Items.AMT_RemoteAccessPolicyAppliesToMPS + }), + 'Reset Retry Count' + + ], target: 'PUT_REMOTE_ACCESS_POLICY_APPLIESTOMPS' }, onError: [ @@ -609,19 +696,33 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'put-remote-access-policy-rule', - onDone: { - actions: assign({ message: ({ event }) => event.output }), - target: 'USER_INITIATED_CONNECTION_SERVICE' - }, + onDone: [ + { + actions: assign({ message: ({ event }) => event.output }), + target: 'CHECK_REMOTE_ACCESS_POLICY_APPLIESTOMPS' + } + ], onError: { actions: assign({ statusMessage: () => 'Failed to put AMT_RemoteAccessPolicyAppliesToMPS' }), target: 'FAILURE' } } }, + CHECK_REMOTE_ACCESS_POLICY_APPLIESTOMPS: { + always: [ + { + guard: 'isRemoteAccessPolicyExists', + target: 'PUT_REMOTE_ACCESS_POLICY_APPLIESTOMPS' + }, + { + target: 'USER_INITIATED_CONNECTION_SERVICE' + } + ] + }, USER_INITIATED_CONNECTION_SERVICE: { invoke: { src: 'userInitiatedConnectionService', @@ -636,7 +737,8 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'user-initiated-connection-service', onDone: [ @@ -669,7 +771,8 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'get-environment-detection-settings', onDone: { @@ -696,7 +799,8 @@ export class CIRAConfiguration { httpHandler: context.httpHandler, message: context.message, amt: context.amt, - xmlMessage: context.xmlMessage + xmlMessage: context.xmlMessage, + remoteAccessPolicies: context.remoteAccessPolicies }), id: 'put-environment-detection-settings', onDone: {