Exemple #1
0
        /// <summary>
        /// Provisions a device to a starting hub, tries to open a connection, send telemetry,
        /// and (if supported by the protocol) send a twin update. Then, this method updates the enrollment
        /// to provision the device to a different hub. Based on the provided reprovisioning settings, this
        /// method then checks that the device was/was not reprovisioned as expected, and that the device
        /// did/did not migrate twin data as expected.
        /// </summary>
        public async Task ProvisioningDeviceClient_ReprovisioningFlow(
            Client.TransportType transportProtocol,
            AttestationMechanismType attestationType,
            EnrollmentType?enrollmentType,
            bool setCustomProxy,
            ReprovisionPolicy reprovisionPolicy,
            AllocationPolicy allocationPolicy,
            CustomAllocationDefinition customAllocationDefinition,
            ICollection <string> iotHubsToStartAt,
            ICollection <string> iotHubsToReprovisionTo,
            string proxyServerAddress = null)
        {
            ProvisioningServiceClient provisioningServiceClient = CreateProvisioningService(s_proxyServerAddress);
            string groupId = _devicePrefix + AttestationTypeToString(attestationType) + "-" + Guid.NewGuid();

            bool twinOperationsAllowed = transportProtocol != Client.TransportType.Http1;

            using ProvisioningTransportHandler transport = ProvisioningE2ETests.CreateTransportHandlerFromName(transportProtocol);
            using SecurityProvider security = await CreateSecurityProviderFromName(
                      attestationType,
                      enrollmentType,
                      groupId,
                      reprovisionPolicy,
                      allocationPolicy,
                      customAllocationDefinition,
                      iotHubsToStartAt)
                                              .ConfigureAwait(false);

            //Check basic provisioning
            if (ProvisioningE2ETests.ImplementsWebProxy(transportProtocol) && setCustomProxy)
            {
                transport.Proxy = (proxyServerAddress != null) ? new WebProxy(s_proxyServerAddress) : null;
            }

            ProvisioningDeviceClient provClient = ProvisioningDeviceClient.Create(
                s_globalDeviceEndpoint,
                Configuration.Provisioning.IdScope,
                security,
                transport);

            using var cts = new CancellationTokenSource(PassingTimeoutMiliseconds);
            DeviceRegistrationResult result = await provClient.RegisterAsync(cts.Token).ConfigureAwait(false);

            ValidateDeviceRegistrationResult(result);
            Client.IAuthenticationMethod auth = CreateAuthenticationMethodFromSecurityProvider(security, result.DeviceId);
            await ConfirmRegisteredDeviceWorks(result, auth, transportProtocol, twinOperationsAllowed).ConfigureAwait(false);

            //Check reprovisioning
            await UpdateEnrollmentToForceReprovision(enrollmentType, provisioningServiceClient, iotHubsToReprovisionTo, security, groupId).ConfigureAwait(false);

            result = await provClient.RegisterAsync(cts.Token).ConfigureAwait(false);

            ConfirmDeviceInExpectedHub(result, reprovisionPolicy, iotHubsToStartAt, iotHubsToReprovisionTo, allocationPolicy);
            await ConfirmDeviceWorksAfterReprovisioning(result, auth, transportProtocol, reprovisionPolicy, twinOperationsAllowed).ConfigureAwait(false);

            if (attestationType != AttestationMechanismType.X509) //x509 enrollments are hardcoded, should never be deleted
            {
                await ProvisioningE2ETests.DeleteCreatedEnrollmentAsync(enrollmentType, provisioningServiceClient, security, groupId).ConfigureAwait(false);
            }
        }
        /// <summary>
        /// Get details for Allocation Policy
        /// </summary>
        /// <param name="projectId">Your Google Cloud Project Id</param>
        /// <param name="policyId">The id of the game policy</param>
        /// <returns>Allocated Policy Name</returns>
        public string GetAllocationPolicy(
            string projectId = "YOUR-PROJECT-ID",
            string policyId  = "YOUR-POLICY-ID")
        {
            // Initialize the client
            AllocationPoliciesServiceClient client = AllocationPoliciesServiceClient.Create();

            // Construct the request
            string parent           = $"projects/{projectId}/locations/global";
            string policyName       = $"{parent}/allocationPolicies/{policyId}";
            var    allocationPolicy = new AllocationPolicy {
                Name = policyName, Priority = 1
            };
            var request = new GetAllocationPolicyRequest
            {
                Name = policyName
            };

            // Call the API
            try
            {
                var result = client.GetAllocationPolicy(request);

                // Inspect the result
                return($"Allocation Policy found: {result.Name}.");
            }
            catch (Exception e)
            {
                Console.WriteLine($"GetAllocationPolicy error:");
                Console.WriteLine($"{e.Message}");
                throw;
            }
        }
        public async Task ProvisioningServiceClient_GroupEnrollments_Create_Ok(
            string proxyServerAddress,
            AttestationMechanismType attestationType,
            ReprovisionPolicy reprovisionPolicy,
            AllocationPolicy allocationPolicy,
            CustomAllocationDefinition customAllocationDefinition,
            ICollection <string> iothubs)
        {
            string groupId = s_devicePrefix + AttestationTypeToString(attestationType) + "-" + Guid.NewGuid();

            using (ProvisioningServiceClient provisioningServiceClient = CreateProvisioningService(proxyServerAddress))
            {
                EnrollmentGroup enrollmentGroup = await CreateEnrollmentGroupAsync(
                    provisioningServiceClient,
                    attestationType,
                    groupId,
                    reprovisionPolicy,
                    allocationPolicy,
                    customAllocationDefinition,
                    iothubs,
                    null,
                    Logger).ConfigureAwait(false);

                EnrollmentGroup enrollmentGroupResult = null;
                await RetryOperationHelper
                .RetryOperationsAsync(
                    async() =>
                {
                    enrollmentGroupResult = await provisioningServiceClient.GetEnrollmentGroupAsync(enrollmentGroup.EnrollmentGroupId).ConfigureAwait(false);
                },
                    s_provisioningServiceRetryPolicy,
                    s_retryableExceptions,
                    Logger)
                .ConfigureAwait(false);

                if (enrollmentGroupResult == null)
                {
                    throw new ArgumentException($"The enrollment group with group Id {enrollmentGroup.EnrollmentGroupId} could not retrieved, exiting test.");
                }

                Assert.AreEqual(enrollmentGroupResult.ProvisioningStatus, ProvisioningStatus.Enabled);

                if (reprovisionPolicy != null)
                {
                    Assert.AreEqual(reprovisionPolicy.MigrateDeviceData, enrollmentGroupResult.ReprovisionPolicy.MigrateDeviceData);
                    Assert.AreEqual(reprovisionPolicy.UpdateHubAssignment, enrollmentGroupResult.ReprovisionPolicy.UpdateHubAssignment);
                }

                if (customAllocationDefinition != null)
                {
                    Assert.AreEqual(customAllocationDefinition.WebhookUrl, enrollmentGroupResult.CustomAllocationDefinition.WebhookUrl);
                    Assert.AreEqual(customAllocationDefinition.ApiVersion, enrollmentGroupResult.CustomAllocationDefinition.ApiVersion);
                }

                Assert.AreEqual(allocationPolicy, enrollmentGroup.AllocationPolicy);

                await DeleteCreatedEnrollmentAsync(EnrollmentType.Group, "", enrollmentGroup.EnrollmentGroupId, Logger).ConfigureAwait(false);
            }
        }
        public async Task ProvisioningServiceClient_SymmetricKey_IndividualEnrollment_Create_Http_Ok_WithReprovisioningFields()
        {
            //This webhook won't actually work for reprovisioning, but this test is only testing that the field is accepted by the service
            var customAllocationDefinition = new CustomAllocationDefinition() { ApiVersion = "2019-03-31", WebhookUrl = "https://www.microsoft.com" };
            var reprovisionPolicy = new ReprovisionPolicy() { MigrateDeviceData = false, UpdateHubAssignment = true };
            AllocationPolicy allocationPolicy = AllocationPolicy.GeoLatency;

            await ProvisioningServiceClient_IndividualEnrollments_Create_Ok("", AttestationMechanismType.SymmetricKey, reprovisionPolicy, allocationPolicy, customAllocationDefinition, null).ConfigureAwait(false);
        }
        public static async Task <EnrollmentGroup> CreateEnrollmentGroupAsync(
            ProvisioningServiceClient provisioningServiceClient,
            AttestationMechanismType attestationType,
            string groupId,
            ReprovisionPolicy reprovisionPolicy,
            AllocationPolicy allocationPolicy,
            CustomAllocationDefinition customAllocationDefinition,
            ICollection <string> iothubs,
            DeviceCapabilities capabilities,
            MsTestLogger logger)
        {
            Attestation attestation;

            switch (attestationType)
            {
            case AttestationMechanismType.Tpm:
                throw new NotSupportedException("Group enrollments do not support tpm attestation");

            case AttestationMechanismType.SymmetricKey:
                string primaryKey   = CryptoKeyGenerator.GenerateKey(32);
                string secondaryKey = CryptoKeyGenerator.GenerateKey(32);
                attestation = new SymmetricKeyAttestation(primaryKey, secondaryKey);
                break;

            case AttestationMechanismType.X509:
            default:
                throw new NotSupportedException("Test code has not been written for testing this attestation type yet");
            }

            var enrollmentGroup = new EnrollmentGroup(groupId, attestation)
            {
                Capabilities               = capabilities,
                ReprovisionPolicy          = reprovisionPolicy,
                AllocationPolicy           = allocationPolicy,
                CustomAllocationDefinition = customAllocationDefinition,
                IotHubs = iothubs,
            };

            EnrollmentGroup createdEnrollmentGroup = null;
            await RetryOperationHelper
            .RetryOperationsAsync(
                async() =>
            {
                createdEnrollmentGroup = await provisioningServiceClient.CreateOrUpdateEnrollmentGroupAsync(enrollmentGroup).ConfigureAwait(false);
            },
                s_provisioningServiceRetryPolicy,
                s_retryableExceptions,
                logger)
            .ConfigureAwait(false);

            if (createdEnrollmentGroup == null)
            {
                throw new ArgumentException($"The enrollment entry with group Id {groupId} could not be created, exiting test.");
            }

            return(createdEnrollmentGroup);
        }
Exemple #6
0
        /// <summary>
        /// Executes the HLS design flow.
        /// </summary>
        /// <param name="design">the design</param>
        /// <param name="host">the hosting component</param>
        /// <param name="proc">the process being subject to HLS</param>
        /// <param name="targetProject">the target project</param>
        /// <remarks>Inside the hosting component, the process will be replaced by the synthesized hardware.</remarks>
        public void Execute(DesignContext design, Component host, ProcessDescriptor proc, IProject targetProject)
        {
            Contract.Requires <ArgumentNullException>(design != null);
            Contract.Requires <ArgumentNullException>(host != null);
            Contract.Requires <ArgumentNullException>(proc != null);
            Contract.Requires <ArgumentNullException>(targetProject != null);

            design.CurrentProcess = proc.Instance;

            var        clk = proc.Sensitivity[0];
            SignalBase clkI;
            var        sdClk = clk as SignalDescriptor;

            if (sdClk == null)
            {
                clkI = ((SignalDescriptor)((PortDescriptor)clk).BoundSignal).Instance;
            }
            else
            {
                clkI = sdClk.Instance;
            }

            var state = new HLSState(this, design, host, proc, targetProject);

            proc.AddAttribute(state);

            if (_beginHLS != null)
            {
                _beginHLS(state);
            }

            var dpb = new DefaultDatapathBuilder(host, clkI, proc.Name);

            state.InterconnectBuilder = InterconnectBuilder.Create(host, dpb.ICBinder);
            state.ControlpathBuilder  = ControlPathBuilder.Create(host, dpb.FUBinder);
            state.ControlpathBuilder.PersonalizePlan(this);

            do
            {
                XILSFunction fnasm;
                if (!proc.HasAttribute <XILSFunction>())
                {
                    var func = proc.Implementation;
                    IEnumerable <Function> inlinedFunctions;
                    func = func.InlineCalls(out inlinedFunctions);
                    if (ConvertFieldsToLocals)
                    {
                        Variable[] newLocals;
                        func = func.ConvertFieldsToLocals(out newLocals);
                    }
                    state.PreprocessedFunction = func;

                    fnasm = state.PreprocessedFunction.Compile(DefaultInstructionSet.Instance);
                }
                else
                {
                    fnasm = proc.QueryAttribute <XILSFunction>();
                }
                fnasm.SanityCheck();
                state.XILSInput = fnasm;
                IList <XILSInstr> instrs = state.XILSInput.Instructions.ToList();
                foreach (var rw in XILSTransformations)
                {
                    instrs = rw.Rewrite(instrs);
                    fnasm  = new XILSFunction(fnasm.Name, fnasm.Arguments, fnasm.Locals, instrs.ToArray());
                    fnasm.SanityCheck();
                }
                state.XILSTransformed = fnasm;

                XIL3Function fnasm3 = fnasm.ToXIL3();
                state.XIL3Input = fnasm3;

                foreach (IXIL3Rewriter rw in XIL3Transformations)
                {
                    fnasm3 = rw.Rewrite(fnasm3);
                    fnasm3.SanityCheck();
                }

                state.XIL3Transformed = fnasm3;
                state.NotifyProgress(EHLSProgress.Compiled);
            } while (state._repeat);
            if (state._cancel)
            {
                return;
            }

            SchedulingConstraints constraints;

            do
            {
                var xmm = new XILMapperManager();
                foreach (var dpu in Enumerable.Reverse(XILMappers))
                {
                    xmm.AddMapper(dpu);
                }

                DesignContext.Push();

                var xilsa = new XILSchedulingAdapter(state.XIL3Transformed, xmm, host, targetProject);
                if (AllocationPolicy != null)
                {
                    xilsa.Allocator.Policy = AllocationPolicy.Create();
                }
                if (_onFUCreated != null)
                {
                    xilsa.Allocator.OnFUAllocation += _onFUCreated;
                }
                state.SchedulingAdapter = xilsa;
                state.NotifyProgress(EHLSProgress.AboutToSchedule);

                constraints = SchedulingConstraints;
                if (constraints == null)
                {
                    if (proc.Implementation != null)
                    {
                        constraints = proc.Implementation.QueryAttribute <SchedulingConstraints>();
                    }
                    if (constraints == null)
                    {
                        constraints = new SchedulingConstraints();
                    }
                }
                state.Constraints = constraints;

                if (constraints.MinimizeNumberOfFUs)
                {
                    foreach (var instr in state.XIL3Transformed.Instructions)
                    {
                        xilsa.SetMaxFUAllocation(xilsa.IClass[instr], 1);
                    }
                }

                Scheduler.Schedule(xilsa.CFG, constraints, xilsa);
                DesignContext.Pop();

                state.NotifyProgress(EHLSProgress.Scheduled);
            } while (state._repeat);

            ComputeCStepsForBranchTargets(state.SchedulingAdapter);

            do
            {
                state.ControlpathBuilder.PrepareAllocation(state.SchedulingAdapter.ComputeCStepCount());
                var flowSpec = state.SchedulingAdapter.Allocate(dpb);
                state.RawFlows = flowSpec;
                var realFlow = new FlowMatrix();
                state.InterconnectBuilder.CreateInterconnect(flowSpec, realFlow);
                state.RealFlows = realFlow;
                state.NotifyProgress(EHLSProgress.InterconnectCreated);
            } while (state._repeat);
            if (state._cancel)
            {
                return;
            }

            Debug.Assert(state.RealFlows.FlowSources.All(sr => sr.Desc.Owner != null));
            Debug.Assert(state.RealFlows.FlowTargets.All(sr => sr.Desc.Owner != null));

            do
            {
                state.ControlpathBuilder.CreateControlpath(state.RealFlows, proc.Name);
                foreach (var prof in constraints.Profilers)
                {
                    prof.ExtractFrom(state.XIL3Transformed, state.SchedulingAdapter);
                }
                state.NotifyProgress(EHLSProgress.ControlpathCreated);
            } while (state._repeat);
            if (state._cancel)
            {
                return;
            }
        }
        public static async Task<EnrollmentGroup> CreateEnrollmentGroup(ProvisioningServiceClient provisioningServiceClient, AttestationMechanismType attestationType, string groupId, ReprovisionPolicy reprovisionPolicy, AllocationPolicy allocationPolicy, CustomAllocationDefinition customAllocationDefinition, ICollection<string> iothubs, DeviceCapabilities capabilities)
        {
            Attestation attestation;
            switch (attestationType)
            {
                case AttestationMechanismType.Tpm:
                    throw new NotSupportedException("Group enrollments do not support tpm attestation");
                case AttestationMechanismType.SymmetricKey:
                    string primaryKey = CryptoKeyGenerator.GenerateKey(32);
                    string secondaryKey = CryptoKeyGenerator.GenerateKey(32);
                    attestation = new SymmetricKeyAttestation(primaryKey, secondaryKey);
                    break;

                case AttestationMechanismType.X509:
                default:
                    throw new NotSupportedException("Test code has not been written for testing this attestation type yet");
            }

            var enrollmentGroup = new EnrollmentGroup(groupId, attestation)
            {
                Capabilities = capabilities,
                ReprovisionPolicy = reprovisionPolicy,
                AllocationPolicy = allocationPolicy,
                CustomAllocationDefinition = customAllocationDefinition,
                IotHubs = iothubs,
            };

            return await provisioningServiceClient.CreateOrUpdateEnrollmentGroupAsync(enrollmentGroup).ConfigureAwait(false);
        }
        public static async Task<IndividualEnrollment> CreateIndividualEnrollment(ProvisioningServiceClient provisioningServiceClient, AttestationMechanismType attestationType, ReprovisionPolicy reprovisionPolicy, AllocationPolicy allocationPolicy, CustomAllocationDefinition customAllocationDefinition, ICollection<string> iotHubsToProvisionTo, DeviceCapabilities capabilities)
        {
            string registrationId = AttestationTypeToString(attestationType) + "-registration-id-" + Guid.NewGuid();
            Attestation attestation;
            IndividualEnrollment individualEnrollment;
            switch (attestationType)
            {
                case AttestationMechanismType.Tpm:
                    using (var tpmSim = new SecurityProviderTpmSimulator(registrationId))
                    {
                        string base64Ek = Convert.ToBase64String(tpmSim.GetEndorsementKey());
                        var provisioningService = ProvisioningServiceClient.CreateFromConnectionString(Configuration.Provisioning.ConnectionString);
                        individualEnrollment = new IndividualEnrollment(registrationId, new TpmAttestation(base64Ek))
                        {
                            Capabilities = capabilities,
                            AllocationPolicy = allocationPolicy,
                            ReprovisionPolicy = reprovisionPolicy,
                            CustomAllocationDefinition = customAllocationDefinition,
                            IotHubs = iotHubsToProvisionTo
                        };

                        IndividualEnrollment enrollment = await provisioningService.CreateOrUpdateIndividualEnrollmentAsync(individualEnrollment).ConfigureAwait(false);
                        attestation = new TpmAttestation(base64Ek);
                        enrollment.Attestation = attestation;
                        return await provisioningService.CreateOrUpdateIndividualEnrollmentAsync(enrollment).ConfigureAwait(false);
                    }
                case AttestationMechanismType.SymmetricKey:
                    string primaryKey = CryptoKeyGenerator.GenerateKey(32);
                    string secondaryKey = CryptoKeyGenerator.GenerateKey(32);
                    attestation = new SymmetricKeyAttestation(primaryKey, secondaryKey);
                    break;

                case AttestationMechanismType.X509:
                default:
                    throw new NotSupportedException("Test code has not been written for testing this attestation type yet");
            }

            individualEnrollment = new IndividualEnrollment(registrationId, attestation);
            individualEnrollment.Capabilities = capabilities;
            individualEnrollment.CustomAllocationDefinition = customAllocationDefinition;
            individualEnrollment.ReprovisionPolicy = reprovisionPolicy;
            individualEnrollment.IotHubs = iotHubsToProvisionTo;
            individualEnrollment.AllocationPolicy = allocationPolicy;
            return await provisioningServiceClient.CreateOrUpdateIndividualEnrollmentAsync(individualEnrollment).ConfigureAwait(false);
        }
        public static async Task ProvisioningServiceClient_GroupEnrollments_Create_Ok(string proxyServerAddress, AttestationMechanismType attestationType, ReprovisionPolicy reprovisionPolicy, AllocationPolicy allocationPolicy, CustomAllocationDefinition customAllocationDefinition, ICollection<string> iothubs)
        {
            string groupId = s_devicePrefix + AttestationTypeToString(attestationType) + "-" + Guid.NewGuid();
            using (ProvisioningServiceClient provisioningServiceClient = CreateProvisioningService(proxyServerAddress))
            {
                EnrollmentGroup enrollmentGroup = await CreateEnrollmentGroup(provisioningServiceClient, attestationType, groupId, reprovisionPolicy, allocationPolicy, customAllocationDefinition, iothubs, null).ConfigureAwait(false);
                EnrollmentGroup enrollmentGroupResult = await provisioningServiceClient.GetEnrollmentGroupAsync(enrollmentGroup.EnrollmentGroupId).ConfigureAwait(false);
                Assert.AreEqual(enrollmentGroupResult.ProvisioningStatus, ProvisioningStatus.Enabled);

                if (reprovisionPolicy != null)
                {
                    Assert.AreEqual(reprovisionPolicy.MigrateDeviceData, enrollmentGroupResult.ReprovisionPolicy.MigrateDeviceData);
                    Assert.AreEqual(reprovisionPolicy.UpdateHubAssignment, enrollmentGroupResult.ReprovisionPolicy.UpdateHubAssignment);
                }

                if (customAllocationDefinition != null)
                {
                    Assert.AreEqual(customAllocationDefinition.WebhookUrl, enrollmentGroupResult.CustomAllocationDefinition.WebhookUrl);
                    Assert.AreEqual(customAllocationDefinition.ApiVersion, enrollmentGroupResult.CustomAllocationDefinition.ApiVersion);
                }

                Assert.AreEqual(allocationPolicy, enrollmentGroup.AllocationPolicy);

                try
                {
                    await provisioningServiceClient.DeleteEnrollmentGroupAsync(enrollmentGroup.EnrollmentGroupId).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Cleanup of enrollment group failed due to {ex}");
                }
            }
        }
        public static async Task ProvisioningServiceClient_IndividualEnrollments_Create_Ok(string proxyServerAddress, AttestationMechanismType attestationType, ReprovisionPolicy reprovisionPolicy, AllocationPolicy allocationPolicy, CustomAllocationDefinition customAllocationDefinition, ICollection<string> iotHubsToProvisionTo)
        {
            using (ProvisioningServiceClient provisioningServiceClient = CreateProvisioningService(proxyServerAddress))
            {
                IndividualEnrollment individualEnrollment = await CreateIndividualEnrollment(provisioningServiceClient, attestationType, reprovisionPolicy, allocationPolicy, customAllocationDefinition, iotHubsToProvisionTo, null).ConfigureAwait(false);
                IndividualEnrollment individualEnrollmentResult = await provisioningServiceClient.GetIndividualEnrollmentAsync(individualEnrollment.RegistrationId).ConfigureAwait(false);
                Assert.AreEqual(individualEnrollmentResult.ProvisioningStatus, ProvisioningStatus.Enabled);

                if (reprovisionPolicy != null)
                {
                    Assert.AreEqual(reprovisionPolicy.UpdateHubAssignment, individualEnrollmentResult.ReprovisionPolicy.UpdateHubAssignment);
                    Assert.AreEqual(reprovisionPolicy.MigrateDeviceData, individualEnrollmentResult.ReprovisionPolicy.MigrateDeviceData);
                }

                if (customAllocationDefinition != null)
                {
                    Assert.AreEqual(customAllocationDefinition.WebhookUrl, individualEnrollmentResult.CustomAllocationDefinition.WebhookUrl);
                    Assert.AreEqual(customAllocationDefinition.ApiVersion, individualEnrollmentResult.CustomAllocationDefinition.ApiVersion);
                }

                //allocation policy is never null
                Assert.AreEqual(allocationPolicy, individualEnrollmentResult.AllocationPolicy);

                await provisioningServiceClient.DeleteIndividualEnrollmentAsync(individualEnrollment.RegistrationId).ConfigureAwait(false);
            }
        }
Exemple #11
0
        /// <summary>
        /// Confirm that the hub the device belongs to did or did not change, depending on the reprovision policy
        /// </summary>
        private void ConfirmDeviceInExpectedHub(DeviceRegistrationResult result, ReprovisionPolicy reprovisionPolicy, ICollection <string> iotHubsToStartAt, ICollection <string> iotHubsToReprovisionTo, AllocationPolicy allocationPolicy)
        {
            if (reprovisionPolicy.UpdateHubAssignment)
            {
                Assert.IsTrue(iotHubsToReprovisionTo.Contains(result.AssignedHub));
                Assert.IsFalse(iotHubsToStartAt.Contains(result.AssignedHub));

                if (allocationPolicy == AllocationPolicy.GeoLatency)
                {
                    Assert.AreNotEqual(result.AssignedHub, Configuration.Provisioning.FarAwayIotHubHostName);
                }
            }
            else
            {
                Assert.IsFalse(iotHubsToReprovisionTo.Contains(result.AssignedHub));
                Assert.IsTrue(iotHubsToStartAt.Contains(result.AssignedHub));
            }
        }
Exemple #12
0
        private async Task <SecurityProvider> CreateSecurityProviderFromName(AttestationType attestationType, EnrollmentType?enrollmentType, string groupId, ReprovisionPolicy reprovisionPolicy, AllocationPolicy allocationPolicy, CustomAllocationDefinition customAllocationDefinition, ICollection <string> iothubs, DeviceCapabilities capabilities = null)
        {
            _verboseLog.WriteLine($"{nameof(CreateSecurityProviderFromName)}({attestationType})");

            var provisioningServiceClient = ProvisioningServiceClient.CreateFromConnectionString(Configuration.Provisioning.ConnectionString);

            switch (attestationType)
            {
            case AttestationType.Tpm:
                string registrationId = AttestationTypeToString(attestationType) + "-registration-id-" + Guid.NewGuid();
                var    tpmSim         = new SecurityProviderTpmSimulator(registrationId);

                string base64Ek = Convert.ToBase64String(tpmSim.GetEndorsementKey());


                var provisioningService = ProvisioningServiceClient.CreateFromConnectionString(Configuration.Provisioning.ConnectionString);

                _log.WriteLine($"Getting enrollment: RegistrationID = {registrationId}");
                IndividualEnrollment individualEnrollment = new IndividualEnrollment(registrationId, new TpmAttestation(base64Ek))
                {
                    AllocationPolicy = allocationPolicy, ReprovisionPolicy = reprovisionPolicy, IotHubs = iothubs, CustomAllocationDefinition = customAllocationDefinition, Capabilities = capabilities
                };
                IndividualEnrollment enrollment = await provisioningService.CreateOrUpdateIndividualEnrollmentAsync(individualEnrollment).ConfigureAwait(false);

                var attestation = new TpmAttestation(base64Ek);
                enrollment.Attestation = attestation;
                _log.WriteLine($"Updating enrollment: RegistrationID = {registrationId} EK = '{base64Ek}'");
                await provisioningService.CreateOrUpdateIndividualEnrollmentAsync(enrollment).ConfigureAwait(false);

                return(tpmSim);

            case AttestationType.x509:

                X509Certificate2           certificate = null;
                X509Certificate2Collection collection  = null;
                switch (enrollmentType)
                {
                case EnrollmentType.Individual:
                    certificate = Configuration.Provisioning.GetIndividualEnrollmentCertificate();
                    break;

                case EnrollmentType.Group:
                    certificate = Configuration.Provisioning.GetGroupEnrollmentCertificate();
                    collection  = Configuration.Provisioning.GetGroupEnrollmentChain();
                    break;

                default:
                    throw new NotSupportedException($"Unknown X509 type: '{enrollmentType}'");
                }

                return(new SecurityProviderX509Certificate(certificate, collection));

            case AttestationType.SymmetricKey:
                switch (enrollmentType)
                {
                case EnrollmentType.Group:
                    EnrollmentGroup symmetricKeyEnrollmentGroup = await CreateEnrollmentGroup(provisioningServiceClient, AttestationType.SymmetricKey, groupId, reprovisionPolicy, allocationPolicy, customAllocationDefinition, iothubs, capabilities).ConfigureAwait(false);

                    Assert.IsTrue(symmetricKeyEnrollmentGroup.Attestation is SymmetricKeyAttestation);
                    SymmetricKeyAttestation symmetricKeyAttestation = (SymmetricKeyAttestation)symmetricKeyEnrollmentGroup.Attestation;
                    string registrationIdSymmetricKey  = IdPrefix + Guid.NewGuid();
                    string primaryKeyEnrollmentGroup   = symmetricKeyAttestation.PrimaryKey;
                    string secondaryKeyEnrollmentGroup = symmetricKeyAttestation.SecondaryKey;

                    string primaryKeyIndividual   = ProvisioningE2ETests.ComputeDerivedSymmetricKey(Convert.FromBase64String(primaryKeyEnrollmentGroup), registrationIdSymmetricKey);
                    string secondaryKeyIndividual = ProvisioningE2ETests.ComputeDerivedSymmetricKey(Convert.FromBase64String(secondaryKeyEnrollmentGroup), registrationIdSymmetricKey);

                    return(new SecurityProviderSymmetricKey(registrationIdSymmetricKey, primaryKeyIndividual, secondaryKeyIndividual));

                case EnrollmentType.Individual:
                    IndividualEnrollment symmetricKeyEnrollment = await CreateIndividualEnrollment(provisioningServiceClient, AttestationType.SymmetricKey, reprovisionPolicy, allocationPolicy, customAllocationDefinition, iothubs, capabilities).ConfigureAwait(false);

                    Assert.IsTrue(symmetricKeyEnrollment.Attestation is SymmetricKeyAttestation);
                    symmetricKeyAttestation = (SymmetricKeyAttestation)symmetricKeyEnrollment.Attestation;

                    registrationIdSymmetricKey = symmetricKeyEnrollment.RegistrationId;
                    string primaryKey   = symmetricKeyAttestation.PrimaryKey;
                    string secondaryKey = symmetricKeyAttestation.SecondaryKey;
                    return(new SecurityProviderSymmetricKey(registrationIdSymmetricKey, primaryKey, secondaryKey));

                default:
                    throw new NotSupportedException("Unrecognized enrollment type");
                }

            default:
                throw new NotSupportedException("Unrecognized attestation type");
            }

            throw new NotSupportedException($"Unknown security type: '{attestationType}'.");
        }
Exemple #13
0
        private async Task<SecurityProvider> CreateSecurityProviderFromNameAsync(
            AttestationMechanismType attestationType,
            EnrollmentType? enrollmentType,
            string groupId,
            ReprovisionPolicy reprovisionPolicy,
            AllocationPolicy allocationPolicy,
            CustomAllocationDefinition customAllocationDefinition,
            ICollection<string> iothubs,
            DeviceCapabilities capabilities = null)
        {
            _verboseLog.WriteLine($"{nameof(CreateSecurityProviderFromNameAsync)}({attestationType})");

            string registrationId = AttestationTypeToString(attestationType) + "-" + Guid.NewGuid();
            using var provisioningServiceClient = ProvisioningServiceClient.CreateFromConnectionString(TestConfiguration.Provisioning.ConnectionString);

            switch (attestationType)
            {
                case AttestationMechanismType.Tpm:
                    IndividualEnrollment tpmEnrollment = await CreateIndividualEnrollmentAsync(
                        provisioningServiceClient,
                        registrationId,
                        AttestationMechanismType.Tpm,
                        null,
                        reprovisionPolicy,
                        allocationPolicy,
                        customAllocationDefinition,
                        iothubs,
                        capabilities,
                        Logger).ConfigureAwait(false);

                    return new SecurityProviderTpmSimulator(tpmEnrollment.RegistrationId);

                case AttestationMechanismType.X509:
                    X509Certificate2 certificate = null;
                    X509Certificate2Collection collection = null;
                    switch (enrollmentType)
                    {
                        case EnrollmentType.Individual:
                            X509Certificate2Helper.GenerateSelfSignedCertificateFiles(registrationId, s_x509CertificatesFolder, Logger);

#pragma warning disable CA2000 // Dispose objects before losing scope
                            // This certificate is used for authentication with IoT hub and is returned to the caller of this method.
                            // It is disposed when the caller to this method is disposed, at the end of the test method.
                            certificate = X509Certificate2Helper.CreateX509Certificate2FromPfxFile(registrationId, s_x509CertificatesFolder);
#pragma warning restore CA2000 // Dispose objects before losing scope

                            using (X509Certificate2 publicCertificate = X509Certificate2Helper.CreateX509Certificate2FromCerFile(registrationId, s_x509CertificatesFolder))
                            {
                                IndividualEnrollment x509IndividualEnrollment = await CreateIndividualEnrollmentAsync(
                                    provisioningServiceClient,
                                    registrationId,
                                    AttestationMechanismType.X509,
                                    publicCertificate,
                                    reprovisionPolicy,
                                    allocationPolicy,
                                    customAllocationDefinition,
                                    iothubs,
                                    capabilities,
                                    Logger).ConfigureAwait(false);

                                x509IndividualEnrollment.Attestation.Should().BeAssignableTo<X509Attestation>();
                            }

                            break;

                        case EnrollmentType.Group:
                            // The X509 enrollment group has been hardcoded for the purpose of E2E tests and the root certificate has been verified on DPS.
                            // Each device identity provisioning through the above enrollment group is created on-demand.

                            X509Certificate2Helper.GenerateIntermediateCertificateSignedCertificateFiles(
                                registrationId,
                                s_intermediateCertificateSubject,
                                s_x509CertificatesFolder,
                                Logger);

#pragma warning disable CA2000 // Dispose objects before losing scope
                            // This certificate is used for authentication with IoT hub and is returned to the caller of this method.
                            // It is disposed when the caller to this method is disposed, at the end of the test method.
                            certificate = X509Certificate2Helper.CreateX509Certificate2FromPfxFile(registrationId, s_x509CertificatesFolder);
#pragma warning restore CA2000 // Dispose objects before losing scope

                            collection = new X509Certificate2Collection
                            {
                                TestConfiguration.CommonCertificates.GetRootCaCertificate(),
                                TestConfiguration.CommonCertificates.GetIntermediate1Certificate(),
                                TestConfiguration.CommonCertificates.GetIntermediate2Certificate(),
                                X509Certificate2Helper.CreateX509Certificate2FromCerFile(registrationId, s_x509CertificatesFolder)
                            };
                            break;

                        default:
                            throw new NotSupportedException($"Unknown X509 type: '{enrollmentType}'");
                    }

                    return new SecurityProviderX509Certificate(certificate, collection);

                case AttestationMechanismType.SymmetricKey:
                    switch (enrollmentType)
                    {
                        case EnrollmentType.Group:
                            EnrollmentGroup symmetricKeyEnrollmentGroup = await CreateEnrollmentGroupAsync(
                                    provisioningServiceClient,
                                    AttestationMechanismType.SymmetricKey,
                                    groupId,
                                    reprovisionPolicy,
                                    allocationPolicy,
                                    customAllocationDefinition,
                                    iothubs,
                                    capabilities,
                                    Logger)
                                .ConfigureAwait(false);
                            Assert.IsTrue(symmetricKeyEnrollmentGroup.Attestation is SymmetricKeyAttestation);
                            var symmetricKeyAttestation = (SymmetricKeyAttestation)symmetricKeyEnrollmentGroup.Attestation;
                            string registrationIdSymmetricKey = _idPrefix + Guid.NewGuid();
                            string primaryKeyEnrollmentGroup = symmetricKeyAttestation.PrimaryKey;
                            string secondaryKeyEnrollmentGroup = symmetricKeyAttestation.SecondaryKey;

                            string primaryKeyIndividual = ComputeDerivedSymmetricKey(Convert.FromBase64String(primaryKeyEnrollmentGroup), registrationIdSymmetricKey);
                            string secondaryKeyIndividual = ComputeDerivedSymmetricKey(Convert.FromBase64String(secondaryKeyEnrollmentGroup), registrationIdSymmetricKey);

                            return new SecurityProviderSymmetricKey(registrationIdSymmetricKey, primaryKeyIndividual, secondaryKeyIndividual);

                        case EnrollmentType.Individual:
                            IndividualEnrollment symmetricKeyEnrollment = await CreateIndividualEnrollmentAsync(
                                provisioningServiceClient,
                                registrationId,
                                AttestationMechanismType.SymmetricKey,
                                null,
                                reprovisionPolicy,
                                allocationPolicy,
                                customAllocationDefinition,
                                iothubs,
                                capabilities,
                                Logger).ConfigureAwait(false);

                            Assert.IsTrue(symmetricKeyEnrollment.Attestation is SymmetricKeyAttestation);
                            symmetricKeyAttestation = (SymmetricKeyAttestation)symmetricKeyEnrollment.Attestation;

                            registrationIdSymmetricKey = symmetricKeyEnrollment.RegistrationId;
                            string primaryKey = symmetricKeyAttestation.PrimaryKey;
                            string secondaryKey = symmetricKeyAttestation.SecondaryKey;
                            return new SecurityProviderSymmetricKey(registrationIdSymmetricKey, primaryKey, secondaryKey);

                        default:
                            throw new NotSupportedException("Unrecognized enrollment type");
                    }
                default:
                    throw new NotSupportedException("Unrecognized attestation type");
            }

            throw new NotSupportedException($"Unknown security type: '{attestationType}'.");
        }
Exemple #14
0
        /// <summary>
        /// Provisions a device to a starting hub, tries to open a connection, send telemetry,
        /// and (if supported by the protocol) send a twin update. Then, this method updates the enrollment
        /// to provision the device to a different hub. Based on the provided reprovisioning settings, this
        /// method then checks that the device was/was not reprovisioned as expected, and that the device
        /// did/did not migrate twin data as expected.
        /// </summary>
        public async Task ProvisioningDeviceClient_ReprovisioningFlow(
            Client.TransportType transportProtocol,
            AttestationMechanismType attestationType,
            EnrollmentType? enrollmentType,
            bool setCustomProxy,
            ReprovisionPolicy reprovisionPolicy,
            AllocationPolicy allocationPolicy,
            CustomAllocationDefinition customAllocationDefinition,
            ICollection<string> iotHubsToStartAt,
            ICollection<string> iotHubsToReprovisionTo,
            string proxyServerAddress = null)
        {
            using ProvisioningServiceClient provisioningServiceClient = CreateProvisioningService(s_proxyServerAddress);

            string groupId = null;
            if (enrollmentType == EnrollmentType.Group)
            {
                if (attestationType == AttestationMechanismType.X509)
                {
                    groupId = TestConfiguration.Provisioning.X509GroupEnrollmentName;
                }
                else
                {
                    groupId = _idPrefix + AttestationTypeToString(attestationType) + "-" + Guid.NewGuid();
                }
            }

            bool transportProtocolSupportsTwinOperations = transportProtocol != Client.TransportType.Http1;

            using ProvisioningTransportHandler transport = CreateTransportHandlerFromName(transportProtocol);
            using SecurityProvider security = await CreateSecurityProviderFromNameAsync(
                    attestationType,
                    enrollmentType,
                    groupId,
                    reprovisionPolicy,
                    allocationPolicy,
                    customAllocationDefinition,
                    iotHubsToStartAt)
                .ConfigureAwait(false);

            //Check basic provisioning
            if (ImplementsWebProxy(transportProtocol) && setCustomProxy)
            {
                transport.Proxy = (proxyServerAddress != null) ? new WebProxy(s_proxyServerAddress) : null;
            }

            var provClient = ProvisioningDeviceClient.Create(
                s_globalDeviceEndpoint,
                TestConfiguration.Provisioning.IdScope,
                security,
                transport);
            using var cts = new CancellationTokenSource(PassingTimeoutMiliseconds);
            DeviceRegistrationResult result = await provClient.RegisterAsync(cts.Token).ConfigureAwait(false);
            ValidateDeviceRegistrationResult(result);

#pragma warning disable CA2000 // Dispose objects before losing scope
            // The certificate instance referenced in the DeviceAuthenticationWithX509Certificate instance is common for all tests in this class. It is disposed during class cleanup.
            Client.IAuthenticationMethod auth = CreateAuthenticationMethodFromSecurityProvider(security, result.DeviceId);
#pragma warning restore CA2000 // Dispose objects before losing scope

            await ConfirmRegisteredDeviceWorks(result, auth, transportProtocol, transportProtocolSupportsTwinOperations).ConfigureAwait(false);

            //Check reprovisioning
            await UpdateEnrollmentToForceReprovision(enrollmentType, provisioningServiceClient, iotHubsToReprovisionTo, security, groupId).ConfigureAwait(false);
            result = await provClient.RegisterAsync(cts.Token).ConfigureAwait(false);
            ConfirmDeviceInExpectedHub(result, reprovisionPolicy, iotHubsToStartAt, iotHubsToReprovisionTo, allocationPolicy);
            await ConfirmDeviceWorksAfterReprovisioning(result, auth, transportProtocol, reprovisionPolicy, transportProtocolSupportsTwinOperations).ConfigureAwait(false);

            if (attestationType == AttestationMechanismType.X509 && enrollmentType == EnrollmentType.Group)
            {
                Logger.Trace($"The test enrollment type {attestationType}-{enrollmentType} with group Id {groupId} is currently hardcoded - do not delete.");
            }
            else
            {
                Logger.Trace($"Deleting test enrollment type {attestationType}-{enrollmentType} with registration Id {security.GetRegistrationID()}.");
                await DeleteCreatedEnrollmentAsync(enrollmentType, security, groupId, Logger).ConfigureAwait(false);
            }

            if (security is SecurityProviderX509 x509Security)
            {
                X509Certificate2 deviceCertificate = x509Security.GetAuthenticationCertificate();
                deviceCertificate?.Dispose();
            }

            if (auth != null && auth is IDisposable disposableAuth)
            {
                disposableAuth?.Dispose();
            }
        }
Exemple #15
0
        public static async Task ProvisioningServiceClient_GroupEnrollments_Create_Ok(string proxyServerAddress, AttestationType attestationType, ReprovisionPolicy reprovisionPolicy, AllocationPolicy allocationPolicy, CustomAllocationDefinition customAllocationDefinition, ICollection <string> iothubs)
        {
            string groupId = "some-valid-group-id-" + attestationTypeToString(attestationType) + "-" + Guid.NewGuid();

            using (ProvisioningServiceClient provisioningServiceClient = CreateProvisioningService(proxyServerAddress))
            {
                EnrollmentGroup enrollmentGroup = await CreateEnrollmentGroup(provisioningServiceClient, attestationType, groupId, reprovisionPolicy, allocationPolicy, customAllocationDefinition, iothubs).ConfigureAwait(false);

                EnrollmentGroup enrollmentGroupResult = await provisioningServiceClient.GetEnrollmentGroupAsync(enrollmentGroup.EnrollmentGroupId).ConfigureAwait(false);

                Assert.AreEqual(enrollmentGroupResult.ProvisioningStatus, ProvisioningStatus.Enabled);

                if (reprovisionPolicy != null)
                {
                    Assert.AreEqual(reprovisionPolicy.MigrateDeviceData, enrollmentGroupResult.ReprovisionPolicy.MigrateDeviceData);
                    Assert.AreEqual(reprovisionPolicy.UpdateHubAssignment, enrollmentGroupResult.ReprovisionPolicy.UpdateHubAssignment);
                }

                if (customAllocationDefinition != null)
                {
                    Assert.AreEqual(customAllocationDefinition.WebhookUrl, enrollmentGroupResult.CustomAllocationDefinition.WebhookUrl);
                    Assert.AreEqual(customAllocationDefinition.ApiVersion, enrollmentGroupResult.CustomAllocationDefinition.ApiVersion);
                }

                Assert.AreEqual(allocationPolicy, enrollmentGroup.AllocationPolicy);

                await provisioningServiceClient.DeleteEnrollmentGroupAsync(enrollmentGroup.EnrollmentGroupId).ConfigureAwait(false);
            }
        }
        public static async Task <IndividualEnrollment> CreateIndividualEnrollmentAsync(
            ProvisioningServiceClient provisioningServiceClient,
            string registrationId,
            AttestationMechanismType attestationType,
            X509Certificate2 authenticationCertificate,
            ReprovisionPolicy reprovisionPolicy,
            AllocationPolicy allocationPolicy,
            CustomAllocationDefinition customAllocationDefinition,
            ICollection <string> iotHubsToProvisionTo,
            DeviceCapabilities capabilities,
            MsTestLogger logger)
        {
            Attestation          attestation;
            IndividualEnrollment individualEnrollment;
            IndividualEnrollment createdEnrollment = null;

            switch (attestationType)
            {
            case AttestationMechanismType.Tpm:
                using (var tpmSim = new SecurityProviderTpmSimulator(registrationId))
                {
                    string base64Ek = Convert.ToBase64String(tpmSim.GetEndorsementKey());
                    individualEnrollment = new IndividualEnrollment(registrationId, new TpmAttestation(base64Ek))
                    {
                        Capabilities               = capabilities,
                        AllocationPolicy           = allocationPolicy,
                        ReprovisionPolicy          = reprovisionPolicy,
                        CustomAllocationDefinition = customAllocationDefinition,
                        IotHubs = iotHubsToProvisionTo
                    };

                    IndividualEnrollment temporaryCreatedEnrollment = null;
                    await RetryOperationHelper
                    .RetryOperationsAsync(
                        async() =>
                    {
                        temporaryCreatedEnrollment = await provisioningServiceClient.CreateOrUpdateIndividualEnrollmentAsync(individualEnrollment).ConfigureAwait(false);
                    },
                        s_provisioningServiceRetryPolicy,
                        s_retryableExceptions,
                        logger)
                    .ConfigureAwait(false);

                    if (temporaryCreatedEnrollment == null)
                    {
                        throw new ArgumentException($"The enrollment entry with registration Id {registrationId} could not be created, exiting test.");
                    }

                    attestation = new TpmAttestation(base64Ek);
                    temporaryCreatedEnrollment.Attestation = attestation;

                    await RetryOperationHelper
                    .RetryOperationsAsync(
                        async() =>
                    {
                        createdEnrollment = await provisioningServiceClient.CreateOrUpdateIndividualEnrollmentAsync(temporaryCreatedEnrollment).ConfigureAwait(false);
                    },
                        s_provisioningServiceRetryPolicy,
                        s_retryableExceptions,
                        logger)
                    .ConfigureAwait(false);

                    if (createdEnrollment == null)
                    {
                        throw new ArgumentException($"The enrollment entry with registration Id {registrationId} could not be updated, exiting test.");
                    }

                    return(createdEnrollment);
                }

            case AttestationMechanismType.SymmetricKey:
                string primaryKey   = CryptoKeyGenerator.GenerateKey(32);
                string secondaryKey = CryptoKeyGenerator.GenerateKey(32);
                attestation = new SymmetricKeyAttestation(primaryKey, secondaryKey);
                break;

            case AttestationMechanismType.X509:
                attestation = X509Attestation.CreateFromClientCertificates(authenticationCertificate);
                break;

            default:
                throw new NotSupportedException("Test code has not been written for testing this attestation type yet");
            }

            individualEnrollment = new IndividualEnrollment(registrationId, attestation)
            {
                Capabilities               = capabilities,
                AllocationPolicy           = allocationPolicy,
                ReprovisionPolicy          = reprovisionPolicy,
                CustomAllocationDefinition = customAllocationDefinition,
                IotHubs = iotHubsToProvisionTo,
            };

            await RetryOperationHelper
            .RetryOperationsAsync(
                async() =>
            {
                createdEnrollment = await provisioningServiceClient.CreateOrUpdateIndividualEnrollmentAsync(individualEnrollment).ConfigureAwait(false);
            },
                s_provisioningServiceRetryPolicy,
                s_retryableExceptions,
                logger)
            .ConfigureAwait(false);

            if (createdEnrollment == null)
            {
                throw new ArgumentException($"The enrollment entry with registration Id {registrationId} could not be created, exiting test.");
            }

            return(createdEnrollment);
        }
Exemple #17
0
        /// <summary>
        /// Confirm that the hub the device belongs to did or did not change, depending on the reprovision policy
        /// </summary>
        private void ConfirmDeviceInExpectedHub(DeviceRegistrationResult result, ReprovisionPolicy reprovisionPolicy, ICollection<string> iotHubsToStartAt, ICollection<string> iotHubsToReprovisionTo, AllocationPolicy allocationPolicy)
        {
            if (reprovisionPolicy.UpdateHubAssignment)
            {
                iotHubsToReprovisionTo.Should().Contain(result.AssignedHub);
                iotHubsToStartAt.Should().NotContain(result.AssignedHub);

                if (allocationPolicy == AllocationPolicy.GeoLatency)
                {
                    result.AssignedHub.Should().NotBe(TestConfiguration.Provisioning.FarAwayIotHubHostName);
                }
            }
            else
            {
                iotHubsToReprovisionTo.Should().NotContain(result.AssignedHub);
                iotHubsToStartAt.Should().Contain(result.AssignedHub);
            }
        }
        public async Task ProvisioningServiceClient_IndividualEnrollments_Create_Ok(
            string proxyServerAddress,
            AttestationMechanismType attestationType,
            ReprovisionPolicy reprovisionPolicy,
            AllocationPolicy allocationPolicy,
            CustomAllocationDefinition customAllocationDefinition,
            ICollection <string> iotHubsToProvisionTo)
        {
            using (ProvisioningServiceClient provisioningServiceClient = CreateProvisioningService(proxyServerAddress))
            {
                string registrationId = AttestationTypeToString(attestationType) + "-" + Guid.NewGuid();

                IndividualEnrollment individualEnrollment = await CreateIndividualEnrollmentAsync(
                    provisioningServiceClient,
                    registrationId,
                    attestationType,
                    null,
                    reprovisionPolicy,
                    allocationPolicy,
                    customAllocationDefinition,
                    iotHubsToProvisionTo,
                    null,
                    Logger).ConfigureAwait(false);

                IndividualEnrollment individualEnrollmentResult = null;
                await RetryOperationHelper
                .RetryOperationsAsync(
                    async() =>
                {
                    individualEnrollmentResult = await provisioningServiceClient.GetIndividualEnrollmentAsync(individualEnrollment.RegistrationId).ConfigureAwait(false);
                },
                    s_provisioningServiceRetryPolicy,
                    s_retryableExceptions,
                    Logger)
                .ConfigureAwait(false);

                if (individualEnrollmentResult == null)
                {
                    throw new ArgumentException($"The individual enrollment with registration Id {individualEnrollment.RegistrationId} could not retrieved, exiting test.");
                }

                Assert.AreEqual(individualEnrollmentResult.ProvisioningStatus, ProvisioningStatus.Enabled);

                if (reprovisionPolicy != null)
                {
                    Assert.AreEqual(reprovisionPolicy.UpdateHubAssignment, individualEnrollmentResult.ReprovisionPolicy.UpdateHubAssignment);
                    Assert.AreEqual(reprovisionPolicy.MigrateDeviceData, individualEnrollmentResult.ReprovisionPolicy.MigrateDeviceData);
                }

                if (customAllocationDefinition != null)
                {
                    Assert.AreEqual(customAllocationDefinition.WebhookUrl, individualEnrollmentResult.CustomAllocationDefinition.WebhookUrl);
                    Assert.AreEqual(customAllocationDefinition.ApiVersion, individualEnrollmentResult.CustomAllocationDefinition.ApiVersion);
                }

                //allocation policy is never null
                Assert.AreEqual(allocationPolicy, individualEnrollmentResult.AllocationPolicy);

                await DeleteCreatedEnrollmentAsync(EnrollmentType.Individual, individualEnrollment.RegistrationId, null, Logger);
            }
        }