public static async Task Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            // Create the Azure Digital Twins client for API calls
            string adtInstanceUrl = "https://<your-instance-hostname>";
            var    credentials    = new DefaultAzureCredential();
            var    client         = new DigitalTwinsClient(new Uri(adtInstanceUrl), credentials);

            Console.WriteLine($"Service client created – ready to go");

            // Upload models
            Console.WriteLine($"Upload a model");
            string dtdl   = File.ReadAllText("<path-to>/Room.json");
            var    models = new List <string> {
                dtdl
            };
            // Upload the model to the service
            await client.CreateModelsAsync(models);

            // Create new digital twin
            // <CreateTwin_withHelper>
            string twinId   = "myTwinID";
            var    initData = new BasicDigitalTwin
            {
                Id       = twinId,
                Metadata = { ModelId = "dtmi:example:Room;1" },
                // Initialize properties
                Contents =
                {
                    { "Temperature", 25.0 },
                    { "Humidity",    50.0 },
                },
            };

            // <CreateTwinCall>
            await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(twinId, initData);

            // </CreateTwinCall>
            // </CreateTwin_withHelper>
            Console.WriteLine("Twin created successfully");

            //Print twin
            Console.WriteLine("--- Printing twin details:");
            await CustomMethod_FetchAndPrintTwinAsync(twinId, client);

            Console.WriteLine("--------");

            //Update twin data
            var updateTwinData = new JsonPatchDocument();

            updateTwinData.AppendAdd("/Temperature", 30.0);
            // <UpdateTwinCall>
            await client.UpdateDigitalTwinAsync(twinId, updateTwinData);

            // </UpdateTwinCall>
            Console.WriteLine("Twin properties updated");
            Console.WriteLine();

            //Print twin again
            Console.WriteLine("--- Printing twin details (after update):");
            await CustomMethod_FetchAndPrintTwinAsync(twinId, client);

            Console.WriteLine("--------");
            Console.WriteLine();

            //Delete twin
            await CustomMethod_DeleteTwinAsync(client, twinId);
        }
Пример #2
0
        public void ValidateUnhandledException([Values(0, 1, 2, 3)] int exPossition)
        {
            var credFactory = new MockDefaultAzureCredentialFactory(CredentialPipeline.GetInstance(null));

            credFactory.OnCreateEnvironmentCredential = (c) =>
            {
                ((MockExtendedTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    if (exPossition > 0)
                    {
                        return(new ExtendedAccessToken(new CredentialUnavailableException("EnvironmentCredential Unavailable")));
                    }
                    else
                    {
                        return(new ExtendedAccessToken(new MockClientException("EnvironmentCredential unhandled exception")));
                    }
                };
            };
            credFactory.OnCreateManagedIdentityCredential = (clientId, c) =>
            {
                ((MockExtendedTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    if (exPossition > 1)
                    {
                        return(new ExtendedAccessToken(new CredentialUnavailableException("ManagedIdentityCredential Unavailable")));
                    }
                    else
                    {
                        return(new ExtendedAccessToken(new MockClientException("ManagedIdentityCredential unhandled exception")));
                    }
                };
            };
            credFactory.OnCreateSharedTokenCacheCredential = (tenantId, username, c) =>
            {
                ((MockExtendedTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    if (exPossition > 2)
                    {
                        return(new ExtendedAccessToken(new CredentialUnavailableException("SharedTokenCacheCredential Unavailable")));
                    }
                    else
                    {
                        return(new ExtendedAccessToken(new MockClientException("SharedTokenCacheCredential unhandled exception")));
                    }
                };
            };
            credFactory.OnCreateInteractiveBrowserCredential = (_, c) =>
            {
                ((MockExtendedTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    return(new ExtendedAccessToken(new MockClientException("InteractiveBrowserCredential unhandled exception")));
                };
            };

            var options = new DefaultAzureCredentialOptions
            {
                ExcludeEnvironmentCredential        = false,
                ExcludeManagedIdentityCredential    = false,
                ExcludeSharedTokenCacheCredential   = false,
                ExcludeInteractiveBrowserCredential = false
            };

            var cred = new DefaultAzureCredential(credFactory, options);

            var ex = Assert.ThrowsAsync <AuthenticationFailedException>(async() => await cred.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));

            if (exPossition > 0)
            {
                Assert.True(ex.Message.Contains("EnvironmentCredential Unavailable"));
            }

            if (exPossition > 1)
            {
                Assert.True(ex.Message.Contains("ManagedIdentityCredential Unavailable"));
            }

            if (exPossition > 2)
            {
                Assert.True(ex.Message.Contains("SharedTokenCacheCredential Unavailable"));
            }

            switch (exPossition)
            {
            case 0:
                Assert.True(ex.Message.Contains("EnvironmentCredential unhandled exception"));
                break;

            case 1:
                Assert.True(ex.Message.Contains("ManagedIdentityCredential unhandled exception"));
                break;

            case 2:
                Assert.True(ex.Message.Contains("SharedTokenCacheCredential unhandled exception"));
                break;

            case 3:
                Assert.True(ex.Message.Contains("InteractiveBrowserCredential unhandled exception"));
                break;

            default:
                Assert.Fail();
                break;
            }
        }
Пример #3
0
        async Task <BlobDownloadDetails> IAzureBlobStoreClient.FetchBlobAndWriteToStream(string containerName, string blobName, string?blobVersion, byte[] contentHash, Stream streamToWriteTo, CancellationToken cancellationToken)
        {
            // https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad-msi
            // https://docs.microsoft.com/en-gb/dotnet/api/overview/azure/identity-readme

            if (string.IsNullOrWhiteSpace(containerName))
            {
                throw new ArgumentNullException(nameof(containerName));
            }
            if (string.IsNullOrWhiteSpace(blobName))
            {
                throw new ArgumentNullException(nameof(blobName));
            }
            if (contentHash is null)
            {
                throw new ArgumentNullException(nameof(contentHash));
            }

            if (streamToWriteTo is null)
            {
                throw new ArgumentNullException(nameof(streamToWriteTo));
            }

            cancellationToken.ThrowIfCancellationRequested();

            var managedIdentityCredential = new DefaultAzureCredential();

            var blobClientOptions = GetBlobClientOptions(_geoRedundantServiceUrl);

            var blobRequestConditions = new BlobRequestConditions()
            {
            };

            var blobServiceClient = new BlobServiceClient(_primaryServiceUrl, managedIdentityCredential, blobClientOptions);

            var containerClient = blobServiceClient.GetBlobContainerClient(containerName);

            var blobClient = containerClient.GetBlobClient(blobName);

            if (blobVersion is not null)
            {
                blobClient = blobClient.WithVersion(blobVersion);
            }

            try
            {
                var result = await blobClient.DownloadStreamingAsync(conditions : blobRequestConditions, cancellationToken : cancellationToken);

                using var response = result.GetRawResponse();

                if (!IsSuccessStatusCode(response.Status))
                {
                    _logger?.LogDebug("Unable to download file from blob storage.  {ClientRequestId} - Reported '{ReasonPhrase}' with status code: '{StatusCode} {StatusCodeName}'", response.ClientRequestId, response.ReasonPhrase, response.Status, Enum.Parse(typeof(HttpStatusCode), Convert.ToString(response.Status, CultureInfo.InvariantCulture)));

                    throw new IrretrievableFileException($"{response.ClientRequestId}: Unable to download file from storage.  Please consult log files for more information");
                }

                var details = result.Value.Details;

                // TODO - Need to understand the correct way to determine that the file hasn't been tampered with since we uploaded it.
                //        We use blob versioning so if we store the uploaded version then we should be ok so long as we also use the version
                //        when downloading (albeit we are not storing that yet so cannot implement it), however, might be a good idea
                //        to verify the original hash code with the one for the file we download.   Have to be careful for larger files
                //        > 100MB.  Not convinced the existing MVCForum upload code is storing
                //        the correct hash in the DB (or for that matter not just trusting the one blob store returns, which is really supposed to be
                //        used to verify it has stored the file correctly) so I need to revisit this fully when time allows.   For now, we
                //        cannot check the hashes

                var blobContentHash = Convert.ToBase64String(details.BlobContentHash ?? details.ContentHash);
                var encodedHash     = Convert.ToBase64String(contentHash);

                if (0 != string.CompareOrdinal(blobContentHash, encodedHash))
                {
                    throw new IrretrievableFileException($"{response.ClientRequestId}: Unable to share the file with the user as the content hash stored during upload does not match that of the downloaded file - '{blobName}' + '{blobVersion}'");
                }

                await result.Value.Content.CopyToAsync(streamToWriteTo, cancellationToken);

                return(details);
            }
            catch (AuthenticationFailedException ex)
            {
                _logger?.LogError(ex, "Unable to authenticate with the Azure Blob Storage service using the default credentials.  Please ensure the user account this application is running under has permissions to access the Blob Storage account we are targeting");

                throw;
            }
            catch (RequestFailedException ex)
            {
                _logger?.LogError(ex, "Unable to access the storage endpoint as the download request failed: '{StatusCode} {StatusCodeName}'", ex.Status, Enum.Parse(typeof(HttpStatusCode), Convert.ToString(ex.Status, CultureInfo.InvariantCulture)));

                throw;
            }
        }
Пример #4
0
        private async Task OnExecuteAsync()
        {
            Stopwatch sw = Stopwatch.StartNew();
            ConcurrentBag <double> sendDurations = new ConcurrentBag <double>();
            ConcurrentBag <Task>   pendingSends  = new ConcurrentBag <Task>();

            byte[] payload = new byte[BodySize];
            rnd.NextBytes(payload);

            if (Wait > 0)
            {
                AsyncCompletion = false;
            }

            Console.WriteLine($"Sending {Count} messages to entity '{EntityName}' in namespace '{NamespaceName}'");

            var cred   = new DefaultAzureCredential();
            var client = new ServiceBusClient(NamespaceName, cred);
            var sender = client.CreateSender(EntityName);

            if (BatchSize == 0)
            {
                if (AsyncCompletion)
                {
                    // first message is sent sync to start the connection
                    long sendStart = sw.ElapsedMilliseconds;
                    var  message   = CreateServiceBusMessage(payload);
                    await sender.SendMessageAsync(message);

                    sendDurations.Add(sw.ElapsedMilliseconds - sendStart);

                    // into the loop!
                    for (int i = 1; i < Count; i++)
                    {
                        sendStart = sw.ElapsedMilliseconds;
                        message   = CreateServiceBusMessage(payload);
                        pendingSends.Add(sender.SendMessageAsync(message).ContinueWith(task =>
                        {
                            sendDurations.Add(sw.ElapsedMilliseconds - sendStart);
                        }));
                    }
                    await Task.WhenAll(pendingSends);
                }
                else
                {
                    for (int i = 0; i < Count; i++)
                    {
                        long sendStart = sw.ElapsedMilliseconds;
                        var  message   = CreateServiceBusMessage(payload);
                        await sender.SendMessageAsync(message);

                        sendDurations.Add(sw.ElapsedMilliseconds - sendStart);

                        if (Wait > 0)
                        {
                            await Task.Delay(Wait);
                        }
                    }
                }
            }
            else
            {
                if (AsyncCompletion)
                {
                    var batch = await sender.CreateMessageBatchAsync();

                    for (int i = 0; i < Count; i++)
                    {
                        var message = CreateServiceBusMessage(payload);

                        if (batch.Count >= BatchSize || !batch.TryAddMessage(message))
                        {
                            // batch is full, send the batch, make a new one, and add this message there
                            long sendStart = sw.ElapsedMilliseconds;
                            pendingSends.Add(sender.SendMessagesAsync(batch).ContinueWith(task =>
                            {
                                sendDurations.Add(sw.ElapsedMilliseconds - sendStart);
                            }));

                            batch = await sender.CreateMessageBatchAsync();

                            batch.TryAddMessage(message);
                        }

                        if (i + 1 >= Count)
                        {
                            // if the loop is about to end, send the batch
                            long sendStart = sw.ElapsedMilliseconds;
                            pendingSends.Add(sender.SendMessagesAsync(batch).ContinueWith(task =>
                            {
                                sendDurations.Add(sw.ElapsedMilliseconds - sendStart);
                            }));
                        }
                    }
                    await Task.WhenAll(pendingSends);
                }
                else
                {
                    var batch = await sender.CreateMessageBatchAsync();

                    for (int i = 0; i < Count; i++)
                    {
                        var message = CreateServiceBusMessage(payload);
                        if (batch.Count >= BatchSize || !batch.TryAddMessage(message))
                        {
                            // batch is full, send the batch, make a new one, and add this message there
                            long sendStart = sw.ElapsedMilliseconds;
                            await sender.SendMessagesAsync(batch);

                            sendDurations.Add(sw.ElapsedMilliseconds - sendStart);

                            if (Wait > 0)
                            {
                                await Task.Delay(Wait);
                            }

                            batch = await sender.CreateMessageBatchAsync();

                            batch.TryAddMessage(message);
                        }

                        if (i + 1 >= Count)
                        {
                            // if the loop is about to end, send the batch
                            long sendStart = sw.ElapsedMilliseconds;
                            await sender.SendMessagesAsync(batch);

                            sendDurations.Add(sw.ElapsedMilliseconds - sendStart);

                            if (Wait > 0)
                            {
                                await Task.Delay(Wait);
                            }
                        }
                    }
                }
            }

            await sender.CloseAsync();

            await client.DisposeAsync();

            long elapsed = sw.ElapsedMilliseconds;

            Console.WriteLine($"Time elapsed {elapsed} ms");
            Console.WriteLine($"{sendDurations.Count / (elapsed/1000.0):F} snd/sec");
            Console.WriteLine($"{Count / (elapsed / 1000.0):F} msg/sec");
            Console.WriteLine($"Min {sendDurations.Min():F} ms");
            Console.WriteLine($"Avg {sendDurations.Average():F} ms");
            Console.WriteLine($"Med {sendDurations.Median():F} ms");
            Console.WriteLine($"StdDev {sendDurations.StandardDeviation():F} ms");
            Console.WriteLine($"50% {sendDurations.Quantile(0.5):F} ms, 95% {sendDurations.Quantile(0.95):F} ms, 99% {sendDurations.Quantile(0.99):F} ms, 99.9 % { sendDurations.Quantile(0.999):F} ms");
        }
Пример #5
0
        public static async Task Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            //Create the Azure Digital Twins client for API calls
            string             adtInstanceUrl = "https://<your-instance-hostname>";
            var                credentials    = new DefaultAzureCredential();
            DigitalTwinsClient client         = new DigitalTwinsClient(new Uri(adtInstanceUrl), credentials);

            Console.WriteLine($"Service client created – ready to go");
            Console.WriteLine();

            //Upload models
            Console.WriteLine($"Upload a model");
            Console.WriteLine();
            string dtdl     = File.ReadAllText("<path-to>/Room.json");
            var    typeList = new List <string>();

            typeList.Add(dtdl);
            // Upload the model to the service
            await client.CreateModelsAsync(typeList);

            //Create new digital twin
            // <CreateTwin_helper>
            BasicDigitalTwin initData = new BasicDigitalTwin();
            string           twin_ID  = "myTwinID";

            initData.Metadata         = new DigitalTwinMetadata();
            initData.Metadata.ModelId = "dtmi:example:Room;1";
            // Initialize properties
            Dictionary <string, object> props = new Dictionary <string, object>();

            props.Add("Temperature", 25.0);
            props.Add("Humidity", 50.0);
            initData.Contents = props;

            // <CreateTwinCall>
            await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(twin_ID, initData);

            // </CreateTwinCall>
            // </CreateTwin_helper>
            Console.WriteLine("Twin created successfully");
            Console.WriteLine();

            //Print twin
            Console.WriteLine("--- Printing twin details:");
            twin = FetchAndPrintTwin(twin_ID, client);
            Console.WriteLine("--------");
            Console.WriteLine();

            //Update twin data
            var updateTwinData = new JsonPatchDocument();

            updateTwinData.AppendAdd("/Temperature", 25.0);
            // <UpdateTwinCall>
            await client.UpdateDigitalTwinAsync(twin_ID, updateTwinData);

            // </UpdateTwinCall>
            Console.WriteLine("Twin properties updated");
            Console.WriteLine();

            //Print twin again
            Console.WriteLine("--- Printing twin details (after update):");
            FetchAndPrintTwin(twin_ID, client);
            Console.WriteLine("--------");
            Console.WriteLine();

            //Delete twin
            await DeleteTwin(client, twin_ID);
        }
        public async Task DefaultAzureCredential()
        {
            #region Snippet:EventHubs_Processor_Sample05_DefaultAzureCredential

            TokenCredential credential = new DefaultAzureCredential();

            var storageEndpoint   = "<< STORAGE ENDPOINT (likely similar to {your-account}.blob.core.windows.net) >>";
            var blobContainerName = "<< NAME OF THE BLOB CONTAINER >>";
            /*@@*/
            /*@@*/ storageEndpoint   = new BlobServiceClient(StorageTestEnvironment.Instance.StorageConnectionString).Uri.ToString();
            /*@@*/ blobContainerName = _storageScope.ContainerName;

            var fullyQualifiedNamespace = "<< NAMESPACE (likely similar to {your-namespace}.servicebus.windows.net) >>";
            var eventHubName            = "<< NAME OF THE EVENT HUB >>";
            var consumerGroup           = "<< NAME OF THE EVENT HUB CONSUMER GROUP >>";
            /*@@*/
            /*@@*/ fullyQualifiedNamespace = EventHubsTestEnvironment.Instance.FullyQualifiedNamespace;
            /*@@*/ eventHubName            = _eventHubScope.EventHubName;
            /*@@*/ consumerGroup           = _eventHubScope.ConsumerGroups.First();
            /*@@*/ credential = EventHubsTestEnvironment.Instance.Credential;

            var blobUriBuilder = new BlobUriBuilder(new Uri(storageEndpoint));
            blobUriBuilder.BlobContainerName = blobContainerName;

            var storageClient = new BlobContainerClient(
                blobUriBuilder.ToUri(),
                credential);

            var processor = new EventProcessorClient(
                storageClient,
                consumerGroup,
                fullyQualifiedNamespace,
                eventHubName,
                credential);

            try
            {
                using var cancellationSource = new CancellationTokenSource();
                cancellationSource.CancelAfter(TimeSpan.FromSeconds(30));

                // The event handlers are not relevant for this sample; for
                // illustration, they're delegating the implementation to the
                // host application.

                processor.ProcessEventAsync += Application.ProcessorEventHandler;
                processor.ProcessErrorAsync += Application.ProcessorErrorHandler;

                try
                {
                    await processor.StartProcessingAsync(cancellationSource.Token);

                    await Task.Delay(Timeout.Infinite, cancellationSource.Token);
                }
                catch (TaskCanceledException)
                {
                    // This is expected if the cancellation token is
                    // signaled.
                }
                finally
                {
                    // This may take up to the length of time defined
                    // as part of the configured TryTimeout of the processor;
                    // by default, this is 60 seconds.

                    await processor.StopProcessingAsync();
                }
            }
            catch
            {
                // If this block is invoked, then something external to the
                // processor was the source of the exception.
            }
            finally
            {
                // It is encouraged that you unregister your handlers when you have
                // finished using the Event Processor to ensure proper cleanup.

                processor.ProcessEventAsync -= Application.ProcessorEventHandler;
                processor.ProcessErrorAsync -= Application.ProcessorErrorHandler;
            }

            #endregion
        }
Пример #7
0
        public static async Task Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
        {
            DigitalTwinsClient client;

            // Authenticate on ADT APIs
            try
            {
                var credentials = new DefaultAzureCredential();
                client = new DigitalTwinsClient(new Uri(adtServiceUrl), credentials, new DigitalTwinsClientOptions {
                    Transport = new HttpClientTransport(httpClient)
                });
            }
            catch (Exception e)
            {
                log.LogError($"ADT service client connection failed. {e}");
                return;
            }

            if (client != null)
            {
                if (eventGridEvent != null && eventGridEvent.Data != null)
                {
                    string  twinId  = eventGridEvent.Subject.ToString();
                    JObject message = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString());

                    log.LogInformation($"Reading event from {twinId}: {eventGridEvent.EventType}: {message["data"]}");

                    // Read properties which values have been changed in each operation
                    foreach (var operation in message["data"]["patch"])
                    {
                        string opValue = (string)operation["op"];
                        if (opValue.Equals("replace"))
                        {
                            string propertyPath = ((string)operation["path"]);

                            if (propertyPath.Equals("/CurrentWind"))
                            {
                                float currentWind = operation["value"].Value <float>();
                                AsyncPageable <IncomingRelationship> windAlertRelashion = client.GetIncomingRelationshipsAsync(twinId);
                                await foreach (IncomingRelationship windAlert in windAlertRelashion)
                                {
                                    if (windAlert.RelationshipName == "windAlert")
                                    {
                                        try
                                        {
                                            if (currentWind > 20)
                                            {
                                                await AdtUtilities.UpdateTwinPropertyAsync(client, windAlert.SourceId, "/Mode", "Safety", log);

                                                log.LogInformation($"Wind alert triggered on {windAlert.SourceId}, mode changed to Safety");
                                            }
                                            else
                                            {
                                                await AdtUtilities.UpdateTwinPropertyAsync(client, windAlert.SourceId, "/Mode", "Auto", log);

                                                log.LogInformation($"Wind alert triggered on {windAlert.SourceId}, mode changed to Safety");
                                            }
                                        }
                                        catch (Exception e)
                                        {
                                            log.LogError($"failed to update {windAlert.SourceId}. Error:{e}");
                                            return;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        public async Task ValidateSelectedCredentialCaching([Values(typeof(EnvironmentCredential), typeof(ManagedIdentityCredential), typeof(SharedTokenCacheCredential), typeof(InteractiveBrowserCredential))] Type availableCredential)
        {
            var expToken = new AccessToken(Guid.NewGuid().ToString(), DateTimeOffset.MaxValue);

            var credFactory = new MockDefaultAzureCredentialFactory(CredentialPipeline.GetInstance(null));

            List <Type> calledCredentials = new List <Type>();

            credFactory.OnCreateEnvironmentCredential = (c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    calledCredentials.Add(typeof(EnvironmentCredential));

                    return((availableCredential == typeof(EnvironmentCredential)) ? expToken : throw new CredentialUnavailableException("Unavailable"));
                };
            };
            credFactory.OnCreateManagedIdentityCredential = (clientId, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    calledCredentials.Add(typeof(ManagedIdentityCredential));

                    return((availableCredential == typeof(ManagedIdentityCredential)) ? expToken : throw new CredentialUnavailableException("Unavailable"));
                };
            };
            credFactory.OnCreateSharedTokenCacheCredential = (tenantId, username, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    calledCredentials.Add(typeof(SharedTokenCacheCredential));

                    return((availableCredential == typeof(SharedTokenCacheCredential)) ? expToken : throw new CredentialUnavailableException("Unavailable"));
                };
            };
            credFactory.OnCreateInteractiveBrowserCredential = (_, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    calledCredentials.Add(typeof(InteractiveBrowserCredential));

                    return((availableCredential == typeof(InteractiveBrowserCredential)) ? expToken : throw new CredentialUnavailableException("Unavailable"));
                };
            };

            var options = new DefaultAzureCredentialOptions
            {
                ExcludeEnvironmentCredential        = false,
                ExcludeManagedIdentityCredential    = false,
                ExcludeSharedTokenCacheCredential   = false,
                ExcludeInteractiveBrowserCredential = false
            };

            var cred = new DefaultAzureCredential(credFactory, options);

            AccessToken actToken = await cred.GetTokenAsync(new TokenRequestContext(MockScopes.Default));

            Assert.AreEqual(expToken.Token, actToken.Token);

            // assert that the available credential was the last credential called
            Assert.AreEqual(calledCredentials[calledCredentials.Count - 1], availableCredential);

            calledCredentials.Clear();

            actToken = await cred.GetTokenAsync(new TokenRequestContext(MockScopes.Default));

            Assert.AreEqual(expToken.Token, actToken.Token);

            // assert that the available credential was the only credential called
            Assert.AreEqual(calledCredentials.Count, 1);

            Assert.AreEqual(calledCredentials[0], availableCredential);
        }
Пример #9
0
        public override void Configure(IFunctionsHostBuilder builder)
        {
            // Add Configuration as a Singleton Service
            builder.Services.Configure <CertbotConfiguration>(Configuration);
            var config = Configuration.Get <CertbotConfiguration>();

            builder.Services.AddSingleton(config);

            // Add HttpClient
            builder.Services.AddHttpClient();

            // Add the DNS LookupClient as a Singleton Service
            builder.Services.AddSingleton(new LookupClient {
                UseCache = false, EnableAuditTrail = true
            });

            // Add the ACME protocol client factory as a Scoped Service
            builder.Services.AddScoped <IAcmeProtocolClientFactory, AcmeProtocolClientFactory>();

            // Add the KeyVaultClient as a Scoped Service
            builder.Services.AddScoped(_ =>
            {
                var tokenProvider = new AzureServiceTokenProvider();
                return(new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(tokenProvider.KeyVaultTokenCallback)));
            });

            // Add the KeyVault SecretClient as a Scoped Service
            builder.Services.AddScoped(_ =>
            {
                var managedServiceIdentityCredential = new DefaultAzureCredential();
                return(new SecretClient(new Uri(config.KeyVaultBaseUrl), managedServiceIdentityCredential));
            });

            // Add the KeyVault CertificateClient as a Scoped Service
            builder.Services.AddScoped(_ =>
            {
                var managedServiceIdentityCredential = new DefaultAzureCredential();
                return(new CertificateClient(new Uri(config.KeyVaultBaseUrl), managedServiceIdentityCredential));
            });

            // Add the Azure API client as a Scoped Service
            builder.Services.AddScoped(_ =>
            {
                var tokenProvider = new AzureServiceTokenProvider();
                return(Microsoft.Azure.Management.Fluent.Azure
                       .Configure()
                       .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
                       .Authenticate(new AzureCredentials(
                                         new TokenCredentials(tokenProvider.GetAccessTokenAsync("https://management.azure.com/", config.TenantId).Result),
                                         new TokenCredentials(tokenProvider.GetAccessTokenAsync("https://graph.windows.net/", config.TenantId).Result),
                                         config.TenantId,
                                         AzureEnvironment.AzureGlobalCloud))
                       .WithSubscription(config.SubscriptionId));
            });

            // Add the BlobContainerClient as a Scoped Service
            builder.Services.AddScoped(_ =>
            {
                var managedServiceIdentityCredential = new DefaultAzureCredential();

                // Get a credential and create a client object for the blob container.
                var blobContainerClient = new BlobContainerClient(new Uri(config.BlobContainerUrl), managedServiceIdentityCredential);

                // Create the container if it does not exist.
                blobContainerClient.CreateIfNotExistsAsync(PublicAccessType.Blob).Wait();

                return(blobContainerClient);
            });
        }
Пример #10
0
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton <ILocalizationProvider, StorageLocalizationProvider>();
            services.AddTextLocalization(options =>
            {
                options.ReturnOnlyKeyIfNotFound = !_environment.IsDevelopment();
                options.FallBackNeutralCulture  = !_environment.IsDevelopment();
            }).Configure <RequestLocalizationOptions>(options =>
            {
                options.DefaultRequestCulture = new RequestCulture(Settings.SupportedCultures[0]);
                options.AddSupportedCultures(Settings.SupportedCultures);
                options.AddSupportedUICultures(Settings.SupportedCultures);
            });

            services.AddScoped <LazyAssemblyLoader>();

            var dataProtectionBuilder = services.AddDataProtection().SetApplicationName(projectName);

            services.RegisterStorage(Configuration);

            services.Configure <ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; });

            services.AddIdentity <ApplicationUser, ApplicationRole>()
            .AddRoles <ApplicationRole>()
            .AddEntityFrameworkStores <ApplicationDbContext>()
            .AddDefaultTokenProviders()
            .AddErrorDescriber <LocalizedIdentityErrorDescriber>();

            services.AddScoped <IUserClaimsPrincipalFactory <ApplicationUser>,
                                AdditionalUserClaimsPrincipalFactory>();

            var authAuthority = Configuration[$"{projectName}:IS4ApplicationUrl"].TrimEnd('/');

            // Adds IdentityServer https://identityserver4.readthedocs.io/en/latest/reference/options.html
            var identityServerBuilder = services.AddIdentityServer(options =>
            {
                options.IssuerUri = authAuthority;
                options.Events.RaiseErrorEvents       = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents     = true;
                options.Events.RaiseSuccessEvents     = true;
                options.UserInteraction.ErrorUrl      = "/identityserver/error";
            })
                                        .AddIdentityServerStores(Configuration)
                                        .AddAspNetIdentity <ApplicationUser>(); //https://identityserver4.readthedocs.io/en/latest/reference/aspnet_identity.html

            X509Certificate2 cert = null;

            var keysLocalFolder = Path.Combine(_environment.ContentRootPath, "Keys");

            if (_environment.IsDevelopment())
            {
                // The AddDeveloperSigningCredential extension creates temporary key material tempkey.jwk for signing tokens.
                // This might be useful to get started, but needs to be replaced by some persistent key material for production scenarios.
                // See http://docs.identityserver.io/en/release/topics/crypto.html#refcrypto for more information.
                // https://stackoverflow.com/questions/42351274/identityserver4-hosting-in-iis

                identityServerBuilder.AddDeveloperSigningCredential();

                dataProtectionBuilder.PersistKeysToFileSystem(new DirectoryInfo(keysLocalFolder));
            }
            else
            {
                // Running on Azure Web App service - read the setup doc at blazor-boilerplate.readthedocs.io

                // appsettings.json parameters used:
                //  "RunsOnAzure": true,
                //  "RunningAsAppService": true,
                //  "RunningAsDocker": false, // not implemented yet
                //  "AzureKeyVault": {
                //      "UsingKeyVault": true,
                //      "UseManagedAppIdentity": true,
                //      "AppKey": "", // not implemented yet.
                //      "AppSecret": "",
                //      "KeyVaultURI": "https://YOURVAULTNAMEHERE.vault.azure.net/",
                //      "CertificateIdentifier": "https://YOURVAULTNAMEHERE.vault.azure.net/certificates/BBAUTH/<HEX_VERSION_STRING_HERE>",
                //      "CertificateName": "BBAUTH",
                //      "StorageAccountBlobBaseUrl": "https://<YOUR_STORAGE_ACCOUNT_NAME_HERE>.blob.core.windows.net",
                //      "ContainerName": "blazor-boilerplate-keys",
                //      "KeysBlobName": "keys.xml"
                if (Convert.ToBoolean(Configuration["HostingOnAzure:RunsOnAzure"]) == true)
                {
                    if (Convert.ToBoolean(Configuration["HostingOnAzure:AzureKeyVault:UsingKeyVault"]) == true)
                    {
                        if (Convert.ToBoolean(Configuration["HostingOnAzure:AzurekeyVault:UseManagedAppIdentity"]) == true)
                        {
                            //https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview

                            // In production environment we have already configured Managed Identity (blazor-boilerplate) using Azure Portal for our app to access Key Vault and Blob Storage.

                            // Set up TokenCredential options for production and development environments
                            bool isDeployed        = !_environment.IsDevelopment();
                            var  credentialOptions = new DefaultAzureCredentialOptions
                            {
                                ExcludeEnvironmentCredential        = isDeployed,
                                ExcludeManagedIdentityCredential    = false, // we only use this one in production
                                ExcludeSharedTokenCacheCredential   = isDeployed,
                                ExcludeVisualStudioCredential       = isDeployed,
                                ExcludeVisualStudioCodeCredential   = isDeployed,
                                ExcludeAzureCliCredential           = isDeployed,
                                ExcludeInteractiveBrowserCredential = isDeployed,
                            };

                            // In development environment DefaultAzureCredential() will use the shared token credential from the IDE. In Visual Studio this is under Options - Azure Service Authentication.
                            if (_environment.IsDevelopment())
                            {
                                // credentialOptions.SharedTokenCacheUsername = "******"; // specify user name to use if more than one Azure username is configured in IDE.
                                // var defaultTenantId = "?????-????-????-????-????????"; // specify AAD tenant to authenticate against (from Azure Portal - AAD - Tenant ID)
                                // credentialOptions.SharedTokenCacheTenantId = defaultTenantId;
                                // credentialOptions.VisualStudioCodeTenantId = defaultTenantId;
                                // credentialOptions.VisualStudioTenantId = defaultTenantId;
                            }

                            TokenCredential tokenCredential = new DefaultAzureCredential(credentialOptions);

                            // The Azure Storage Container (blazor-boilerplate-keys) Access Control must grant blazor-boilerplate the following roles:
                            // - Storage Blob Data Contributor

                            var blobServiceClient = new BlobServiceClient(
                                new Uri(Configuration["HostingOnAzure:AzureKeyVault:StorageAccountBlobBaseUrl"]),
                                tokenCredential);

                            BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient(Configuration["HostingOnAzure:AzureKeyVault:ContainerName"]);
                            BlobClient          blobClient          = blobContainerClient.GetBlobClient(Configuration["HostingOnAzure:AzureKeyVault:KeysBlobName"]);

                            var certificateIdentifier = Configuration["HostingOnAzure:AzureKeyVault:CertificateIdentifier"];

                            dataProtectionBuilder.PersistKeysToAzureBlobStorage(blobClient);
                            // 1. Remove the call to ProtectKeysWithAzureKeyVault below for the first run to create the keys.xml blob in place.
                            // 2. Add the call to ProtectKeysWithAzureKeyVault for subsequent runs.so that keys.xml gets created - see the setup doc for more information
                            dataProtectionBuilder.ProtectKeysWithAzureKeyVault(new Uri(certificateIdentifier), tokenCredential);

                            // Azure Key Vault Access Policy must grant the following permissions to the blazor-boilerplate app:
                            // - Secret Permissions: Get
                            // - Certificate Permissions: Get

                            // Retrieve the certificate and extract the secret so that we can build the new X509 certificate for later use by Identity Server
                            var certificateClient = new CertificateClient(vaultUri: new Uri(Configuration["HostingOnAzure:AzureKeyVault:KeyVaultUri"]), credential: new DefaultAzureCredential());
                            var secretClient      = new SecretClient(vaultUri: new Uri(Configuration["HostingOnAzure:AzureKeyVault:KeyVaultUri"]), credential: new DefaultAzureCredential());
                            KeyVaultCertificateWithPolicy certificateWithPolicy = certificateClient.GetCertificateAsync(Configuration["HostingOnAzure:AzureKeyVault:CertificateName"]).GetAwaiter().GetResult(); // retrieves latest version of certificate
                            KeyVaultSecretIdentifier      secretIdentifier      = new(certificateWithPolicy.SecretId);
                            KeyVaultSecret secret          = secretClient.GetSecretAsync(secretIdentifier.Name, secretIdentifier.Version).GetAwaiter().GetResult();
                            byte[]         privateKeyBytes = Convert.FromBase64String(secret.Value);

                            cert = new X509Certificate2(privateKeyBytes, (string)null, X509KeyStorageFlags.MachineKeySet);
                        }
                    }
                    else // if app id and app secret are used
                    {
                        throw new NotImplementedException();
                    }
                }
                else
                {
                    dataProtectionBuilder.PersistKeysToFileSystem(new DirectoryInfo(keysLocalFolder));
                }

                //TODO this implementation does not consider certificate expiration
                if (Convert.ToBoolean(Configuration[$"{projectName}:UseLocalCertStore"]) == true)
                {
                    var certificateThumbprint = Configuration[$"{projectName}:CertificateThumbprint"];

                    var storeLocation = StoreLocation.LocalMachine;

                    dynamic storeName = "WebHosting";

                    if (OperatingSystem.IsLinux())
                    {
                        storeLocation = StoreLocation.CurrentUser;
                        storeName     = StoreName.My;
                    }

                    using X509Store store = new(storeName, storeLocation);
                    store.Open(OpenFlags.ReadOnly);
                    var certs = store.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);
                    if (certs.Count > 0)
                    {
                        cert = certs[0];
                    }
                    else
                    {
                        var certPath = Path.Combine(_environment.ContentRootPath, "AuthSample.pfx");

                        if (File.Exists(certPath))
                        {
                            string certificatePassword = Configuration[$"{projectName}:CertificatePassword"] ?? "Admin123";
                            cert = new X509Certificate2(certPath, certificatePassword,
                                                        X509KeyStorageFlags.MachineKeySet |
                                                        X509KeyStorageFlags.PersistKeySet |
                                                        X509KeyStorageFlags.Exportable);
                        }
                    }

                    store.Close();
                }

                // pass the resulting certificate to Identity Server
                if (cert != null)
                {
                    identityServerBuilder.AddSigningCredential(cert);
                    Log.Logger.Information($"Added certificate {cert.Subject} to Identity Server");
                }
                else if (OperatingSystem.IsWindows())
                {
                    Log.Logger.Debug("Trying to use WebHosting Certificate for Identity Server");
                    identityServerBuilder.AddWebHostingCertificate();
                }
                else
                {
                    throw new Exception("Missing Certificate for Identity Server");
                }
            }

            var authBuilder = services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                              .AddJwtBearer(options =>
            {
                options.Authority            = authAuthority;
                options.RequireHttpsMetadata = _environment.IsProduction();
                options.Audience             = IdentityServerConfig.LocalApiName;
                options.TokenValidationParameters.ValidTypes = new[] { JwtTypes.AccessToken };

                options.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var accessToken = context.Request.Query["access_token"];

                        // If the request is for our hub...
                        var path = context.HttpContext.Request.Path;
                        if (!string.IsNullOrEmpty(accessToken) &&
                            path.StartsWithSegments(Constants.HubPaths.Chat))
                        {
                            // Read the token out of the query string
                            context.Token = accessToken;
                        }
                        return(Task.CompletedTask);
                    }
                };
            });

            #region ExternalAuthProviders
            //https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authentication/samples/SocialSample/Startup.cs
            //https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins
            if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Google:Enabled"] ?? "false"))
            {
                authBuilder.AddGoogle(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    options.ClientId     = Configuration["ExternalAuthProviders:Google:ClientId"];
                    options.ClientSecret = Configuration["ExternalAuthProviders:Google:ClientSecret"];

                    options.AuthorizationEndpoint += "?prompt=consent"; // Hack so we always get a refresh token, it only comes on the first authorization response
                    options.AccessType             = "offline";
                    options.SaveTokens             = true;
                    options.Events = new OAuthEvents()
                    {
                        OnRemoteFailure = HandleOnRemoteFailure
                    };
                    options.ClaimActions.MapJsonSubKey("urn:google:image", "image", "url");
                    options.ClaimActions.Remove(ClaimTypes.GivenName);
                });
            }

            if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Facebook:Enabled"] ?? "false"))
            {
                // You must first create an app with Facebook and add its ID and Secret to your user-secrets.
                // https://developers.facebook.com/apps/
                // https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#login
                authBuilder.AddFacebook(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    options.AppId     = Configuration["ExternalAuthProviders:Facebook:AppId"];
                    options.AppSecret = Configuration["ExternalAuthProviders:Facebook:AppSecret"];

                    options.Scope.Add("email");
                    options.Fields.Add("name");
                    options.Fields.Add("email");
                    options.SaveTokens = true;
                    options.Events     = new OAuthEvents()
                    {
                        OnRemoteFailure = HandleOnRemoteFailure
                    };
                });
            }

            if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Twitter:Enabled"] ?? "false"))
            {
                // You must first create an app with Twitter and add its key and Secret to your user-secrets.
                // https://apps.twitter.com/
                // https://developer.twitter.com/en/docs/basics/authentication/api-reference/access_token
                authBuilder.AddTwitter(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    options.ConsumerKey    = Configuration["ExternalAuthProviders:Twitter:ConsumerKey"];
                    options.ConsumerSecret = Configuration["ExternalAuthProviders:Twitter:ConsumerSecret"];

                    // http://stackoverflow.com/questions/22627083/can-we-get-email-id-from-twitter-oauth-api/32852370#32852370
                    // http://stackoverflow.com/questions/36330675/get-users-email-from-twitter-api-for-external-login-authentication-asp-net-mvc?lq=1
                    options.RetrieveUserDetails = true;
                    options.SaveTokens          = true;
                    options.ClaimActions.MapJsonKey("urn:twitter:profilepicture", "profile_image_url", ClaimTypes.Uri);
                    options.Events = new TwitterEvents()
                    {
                        OnRemoteFailure = HandleOnRemoteFailure
                    };
                });
            }

            //https://github.com/xamarin/Essentials/blob/master/Samples/Sample.Server.WebAuthenticator/Startup.cs
            if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Apple:Enabled"] ?? "false"))
            {
                authBuilder.AddApple(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    options.ClientId = Configuration["ExternalAuthProviders:Apple:ClientId"];
                    options.KeyId    = Configuration["ExternalAuthProviders:Apple:KeyId"];
                    options.TeamId   = Configuration["ExternalAuthProviders:Apple:TeamId"];

                    options.UsePrivateKey(keyId
                                          => _environment.ContentRootFileProvider.GetFileInfo($"AuthKey_{keyId}.p8"));
                    options.SaveTokens = true;
                });
            }

            // You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets.
            // https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
            if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Microsoft:Enabled"] ?? "false"))
            {
                authBuilder.AddMicrosoftAccount(options =>
                {
                    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                    options.ClientId     = Configuration["ExternalAuthProviders:Microsoft:ClientId"];
                    options.ClientSecret = Configuration["ExternalAuthProviders:Microsoft:ClientSecret"];

                    options.SaveTokens = true;
                    options.Scope.Add("offline_access");
                    options.Events = new OAuthEvents()
                    {
                        OnRemoteFailure = HandleOnRemoteFailure
                    };
                });
            }
            #endregion

            #region Authorization
            //Add Policies / Claims / Authorization - https://identityserver4.readthedocs.io/en/latest/topics/add_apis.html#advanced
            services.AddScoped <EntityPermissions>();
            services.AddSingleton <IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
            services.AddTransient <IAuthorizationHandler, DomainRequirementHandler>();
            services.AddTransient <IAuthorizationHandler, EmailVerifiedHandler>();
            services.AddTransient <IAuthorizationHandler, PermissionRequirementHandler>();
            #endregion

            services.Configure <IdentityOptions>(options =>
            {
                options.Password.RequireDigit           = RequireDigit;
                options.Password.RequiredLength         = RequiredLength;
                options.Password.RequireNonAlphanumeric = RequireNonAlphanumeric;
                options.Password.RequireUppercase       = RequireUppercase;
                options.Password.RequireLowercase       = RequireLowercase;
                //options.Password.RequiredUniqueChars = 6;

                options.Lockout.DefaultLockoutTimeSpan  = TimeSpan.FromMinutes(30);
                options.Lockout.MaxFailedAccessAttempts = 10;
                options.Lockout.AllowedForNewUsers      = true;

                if (Convert.ToBoolean(Configuration[$"{projectName}:RequireConfirmedEmail"] ?? "false"))
                {
                    options.User.RequireUniqueEmail      = true;
                    options.SignIn.RequireConfirmedEmail = true;
                }
            });

            #region Cookies
            // cookie policy to deal with temporary browser incompatibilities
            services.AddSameSiteCookiePolicy();

            //https://docs.microsoft.com/en-us/aspnet/core/security/gdpr
            services.Configure <CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential
                // cookies is needed for a given request.
                options.CheckConsentNeeded = context => false; //consent not required
                // requires using Microsoft.AspNetCore.Http;
                //options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            //services.ConfigureExternalCookie(options =>
            // {
            // macOS login fix
            //options.Cookie.SameSite = SameSiteMode.None;
            //});

            services.ConfigureApplicationCookie(options =>
            {
                options.Cookie.IsEssential  = true;
                options.Cookie.HttpOnly     = true;
                options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
                options.ExpireTimeSpan      = TimeSpan.FromDays(Convert.ToDouble(Configuration[$"{projectName}:CookieExpireTimeSpanDays"] ?? "30"));
                options.LoginPath           = Constants.Settings.LoginPath;
                //options.AccessDeniedPath = "/Identity/Account/AccessDenied";
                // ReturnUrlParameter requires
                //using Microsoft.AspNetCore.Authentication.Cookies;
                options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
                options.SlidingExpiration  = true;

                // Suppress redirect on API URLs in ASP.NET Core -> https://stackoverflow.com/a/56384729/54159
                options.Events = new CookieAuthenticationEvents()
                {
                    OnRedirectToAccessDenied = context =>
                    {
                        if (context.Request.Path.StartsWithSegments("/api"))
                        {
                            context.Response.StatusCode = Status403Forbidden;
                        }

                        return(Task.CompletedTask);
                    },
                    OnRedirectToLogin = context =>
                    {
                        context.Response.StatusCode = Status401Unauthorized;
                        return(Task.CompletedTask);
                    }
                };
            });
            #endregion

            services.AddMvc().AddNewtonsoftJson(opt =>
            {
                // Set Breeze defaults for entity serialization
                var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings);
                if (ss.ContractResolver is DefaultContractResolver resolver)
                {
                    resolver.NamingStrategy = null;  // remove json camelCasing; names are converted on the client.
                }
                if (_environment.IsDevelopment())
                {
                    ss.Formatting = Newtonsoft.Json.Formatting.Indented; // format JSON for debugging
                }
            })                                                           // Add Breeze exception filter to send errors back to the client
            .AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); })
            .AddViewLocalization().AddDataAnnotationsLocalization(options =>
            {
                options.DataAnnotationLocalizerProvider = (type, factory) =>
                {
                    return(factory.Create(typeof(Global)));
                };
            }).AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining <LocalizationRecordValidator>());

            services.AddServerSideBlazor().AddCircuitOptions(o =>
            {
                if (_environment.IsDevelopment())
                {
                    o.DetailedErrors = true;
                }
            }).AddHubOptions(o =>
            {
                o.MaximumReceiveMessageSize = 131072;
            });

            services.AddSignalR();
            services.AddSingleton <IUserIdProvider, UserIdProvider>();

            if (_enableAPIDoc)
            {
                services.AddOpenApiDocument(document =>
                {
                    document.Title   = "BlazorBoilerplate API";
                    document.Version = typeof(Startup).GetTypeInfo().Assembly.GetName().Version.ToString();
                    document.AddSecurity("bearer", Enumerable.Empty <string>(), new OpenApiSecurityScheme
                    {
                        Type             = OpenApiSecuritySchemeType.OAuth2,
                        Description      = "Local Identity Server",
                        OpenIdConnectUrl = $"{authAuthority}/.well-known/openid-configuration", //not working
                        Flow             = OpenApiOAuth2Flow.AccessCode,
                        Flows            = new OpenApiOAuthFlows()
                        {
                            AuthorizationCode = new OpenApiOAuthFlow()
                            {
                                Scopes = new Dictionary <string, string>
                                {
                                    { LocalApi.ScopeName, IdentityServerConfig.LocalApiName }
                                },
                                AuthorizationUrl = $"{authAuthority}/connect/authorize",
                                TokenUrl         = $"{authAuthority}/connect/token"
                            },
                        }
                    });;

                    document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("bearer"));
                    //      new OperationSecurityScopeProcessor("bearer"));
                });
            }

            services.AddScoped <IUserSession, UserSession>();

            services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();

            services.Add(ServiceDescriptor.Scoped(typeof(ITenantSettings <>), typeof(TenantSettingsManager <>)));

            services.AddTransient <IEmailFactory, EmailFactory>();

            services.AddTransient <IAccountManager, AccountManager>();
            services.AddTransient <IAdminManager, AdminManager>();
            services.AddTransient <IEmailManager, EmailManager>();
            services.AddTransient <IExternalAuthManager, ExternalAuthManager>();

            #region Automapper
            //Automapper to map DTO to Models https://www.c-sharpcorner.com/UploadFile/1492b1/crud-operations-using-automapper-in-mvc-application/
            var automapperConfig = new MapperConfiguration(configuration =>
            {
                configuration.AddProfile(new MappingProfile());
            });

            var autoMapper = automapperConfig.CreateMapper();

            services.AddSingleton(autoMapper);
            #endregion

            /* ServerSideBlazor */
            services.AddScoped <IAccountApiClient, AccountApiClient>();
            services.AddScoped <AppState>();

            // setup HttpClient for server side in a client side compatible fashion ( with auth cookie )
            // if (!services.Any(x => x.ServiceType == typeof(HttpClient)))
            // {
            services.AddScoped(s =>
            {
                // creating the URI helper needs to wait until the JS Runtime is initialized, so defer it.
                var navigationManager   = s.GetRequiredService <NavigationManager>();
                var httpContextAccessor = s.GetRequiredService <IHttpContextAccessor>();
                var cookies             = httpContextAccessor.HttpContext.Request.Cookies;
                var httpClientHandler   = new HttpClientHandler()
                {
                    UseCookies = false
                };
                if (_environment.IsDevelopment())
                {
                    // Return 'true' to allow certificates that are untrusted/invalid
                    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return(true); };
                }
                var client = new HttpClient(httpClientHandler);
                if (cookies.Any())
                {
                    var cks = new List <string>();

                    foreach (var cookie in cookies)
                    {
                        cks.Add($"{cookie.Key}={cookie.Value}");
                    }

                    client.DefaultRequestHeaders.Add("Cookie", string.Join(';', cks));
                }

                client.BaseAddress = new Uri(navigationManager.BaseUri);

                return(client);
            });
            // }

            services.AddScoped <ILocalizationApiClient, LocalizationApiClient>();
            services.AddScoped <IApiClient, ApiClient>();

            // Authentication providers
            Log.Logger.Debug("Removing AuthenticationStateProvider...");
            var serviceDescriptor = services.FirstOrDefault(descriptor => descriptor.ServiceType == typeof(AuthenticationStateProvider));
            if (serviceDescriptor != null)
            {
                services.Remove(serviceDescriptor);
            }

            Log.Logger.Debug("Adding AuthenticationStateProvider...");
            services.AddScoped <AuthenticationStateProvider, IdentityAuthenticationStateProvider>();
            /**********************/

            services.AddModules();

            if (Log.Logger.IsEnabled(Serilog.Events.LogEventLevel.Debug))
            {
                Log.Logger.Debug($"Total Services Registered: {services.Count}");
                foreach (var service in services)
                {
                    Log.Logger.Debug($"\n\tService: {service.ServiceType.FullName}\n\tLifetime: {service.Lifetime}\n\tInstance: {service.ImplementationType?.FullName}");
                }
            }
        }
Пример #11
0
        public void ValidateAllUnavailable([Values(true, false)] bool excludeEnvironmentCredential,
                                           [Values(true, false)] bool excludeManagedIdentityCredential,
                                           [Values(true, false)] bool excludeSharedTokenCacheCredential,
                                           [Values(true, false)] bool excludeVisualStudioCredential,
                                           [Values(true, false)] bool excludeVisualStudioCodeCredential,
                                           [Values(true, false)] bool excludeCliCredential,
                                           [Values(true, false)] bool excludePowerShellCredential,
                                           [Values(true, false)] bool excludeInteractiveBrowserCredential)
        {
            if (excludeEnvironmentCredential && excludeManagedIdentityCredential && excludeSharedTokenCacheCredential && excludeVisualStudioCredential && excludeVisualStudioCodeCredential && excludeCliCredential && excludeInteractiveBrowserCredential)
            {
                Assert.Pass();
            }

            var credFactory = new MockDefaultAzureCredentialFactory(CredentialPipeline.GetInstance(null));

            void SetupMockForException <T>(Mock <T> mock) where T : TokenCredential =>
            mock.Setup(m => m.GetTokenAsync(It.IsAny <TokenRequestContext>(), It.IsAny <CancellationToken>()))
            .Throws(new CredentialUnavailableException($"{typeof(T).Name} Unavailable"));

            credFactory.OnCreateEnvironmentCredential = c =>
                                                        SetupMockForException(c);
            credFactory.OnCreateInteractiveBrowserCredential = (_, _, c) =>
                                                               SetupMockForException(c);
            credFactory.OnCreateManagedIdentityCredential = (_, c) =>
                                                            SetupMockForException(c);
            credFactory.OnCreateSharedTokenCacheCredential = (_, _, c) =>
                                                             SetupMockForException(c);
            credFactory.OnCreateAzureCliCredential = c =>
                                                     SetupMockForException(c);
            credFactory.OnCreateAzurePowerShellCredential = c =>
                                                            SetupMockForException(c);
            credFactory.OnCreateVisualStudioCredential = (_, c) =>
                                                         SetupMockForException(c);
            credFactory.OnCreateVisualStudioCodeCredential = (_, c) =>
                                                             SetupMockForException(c);

            var options = new DefaultAzureCredentialOptions
            {
                ExcludeEnvironmentCredential        = excludeEnvironmentCredential,
                ExcludeManagedIdentityCredential    = excludeManagedIdentityCredential,
                ExcludeSharedTokenCacheCredential   = excludeSharedTokenCacheCredential,
                ExcludeVisualStudioCredential       = excludeVisualStudioCredential,
                ExcludeVisualStudioCodeCredential   = excludeVisualStudioCodeCredential,
                ExcludeAzureCliCredential           = excludeCliCredential,
                ExcludeAzurePowerShellCredential    = excludePowerShellCredential,
                ExcludeInteractiveBrowserCredential = excludeInteractiveBrowserCredential
            };

            var cred = new DefaultAzureCredential(credFactory, options);

            var ex = Assert.ThrowsAsync <CredentialUnavailableException>(async() => await cred.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));

            if (!excludeEnvironmentCredential)
            {
                Assert.True(ex.Message.Contains("EnvironmentCredential Unavailable"));
            }
            if (!excludeManagedIdentityCredential)
            {
                Assert.True(ex.Message.Contains("ManagedIdentityCredential Unavailable"));
            }
            if (!excludeSharedTokenCacheCredential)
            {
                Assert.True(ex.Message.Contains("SharedTokenCacheCredential Unavailable"));
            }
            if (!excludeCliCredential)
            {
                Assert.True(ex.Message.Contains("CliCredential Unavailable"));
            }
            if (!excludePowerShellCredential)
            {
                Assert.True(ex.Message.Contains("PowerShellCredential Unavailable"));
            }
            if (!excludeInteractiveBrowserCredential)
            {
                Assert.True(ex.Message.Contains("InteractiveBrowserCredential Unavailable"));
            }
            if (!excludeVisualStudioCredential)
            {
                Assert.True(ex.Message.Contains("VisualStudioCredential Unavailable"));
            }
            if (!excludeVisualStudioCodeCredential)
            {
                Assert.True(ex.Message.Contains("VisualStudioCodeCredential Unavailable"));
            }
        }
Пример #12
0
        public void ValidateUnhandledException([Values(0, 1, 2, 3, 4, 5, 6)] int exPossition)
        {
            var credFactory = new MockDefaultAzureCredentialFactory(CredentialPipeline.GetInstance(null));

            credFactory.OnCreateEnvironmentCredential = (c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    if (exPossition > 0)
                    {
                        throw new CredentialUnavailableException("EnvironmentCredential Unavailable");
                    }
                    else
                    {
                        throw new MockClientException("EnvironmentCredential unhandled exception");
                    }
                };
            };
            credFactory.OnCreateManagedIdentityCredential = (clientId, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    if (exPossition > 1)
                    {
                        throw new CredentialUnavailableException("ManagedIdentityCredential Unavailable");
                    }
                    else
                    {
                        throw new MockClientException("ManagedIdentityCredential unhandled exception");
                    }
                };
            };
            credFactory.OnCreateSharedTokenCacheCredential = (tenantId, username, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    if (exPossition > 2)
                    {
                        throw new CredentialUnavailableException("SharedTokenCacheCredential Unavailable");
                    }
                    else
                    {
                        throw new MockClientException("SharedTokenCacheCredential unhandled exception");
                    }
                };
            };
            credFactory.OnCreateVisualStudioCredential = (_, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    if (exPossition > 3)
                    {
                        throw new CredentialUnavailableException("VisualStudioCredential Unavailable");
                    }
                    else
                    {
                        throw new MockClientException("VisualStudioCredential unhandled exception");
                    }
                };
            };
            credFactory.OnCreateVisualStudioCodeCredential = (_, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    if (exPossition > 4)
                    {
                        throw new CredentialUnavailableException("VisualStudioCodeCredential Unavailable");
                    }
                    else
                    {
                        throw new MockClientException("VisualStudioCodeCredential unhandled exception");
                    }
                };
            };
            credFactory.OnCreateAzureCliCredential = (c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    if (exPossition > 5)
                    {
                        throw new CredentialUnavailableException("CliCredential Unavailable");
                    }
                    else
                    {
                        throw new MockClientException("CliCredential unhandled exception");
                    }
                };
            };
            credFactory.OnCreateInteractiveBrowserCredential = (_, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) =>
                {
                    throw new MockClientException("InteractiveBrowserCredential unhandled exception");
                };
            };

            var options = new DefaultAzureCredentialOptions
            {
                ExcludeEnvironmentCredential        = false,
                ExcludeManagedIdentityCredential    = false,
                ExcludeSharedTokenCacheCredential   = false,
                ExcludeAzureCliCredential           = false,
                ExcludeInteractiveBrowserCredential = false
            };

            var cred = new DefaultAzureCredential(credFactory, options);

            var ex = Assert.ThrowsAsync <AuthenticationFailedException>(async() => await cred.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));

            switch (exPossition)
            {
            case 0:
                Assert.AreEqual(ex.InnerException.Message, "EnvironmentCredential unhandled exception");
                break;

            case 1:
                Assert.AreEqual(ex.InnerException.Message, "ManagedIdentityCredential unhandled exception");
                break;

            case 2:
                Assert.AreEqual(ex.InnerException.Message, "SharedTokenCacheCredential unhandled exception");
                break;

            case 3:
                Assert.AreEqual(ex.InnerException.Message, "VisualStudioCredential unhandled exception");
                break;

            case 4:
                Assert.AreEqual(ex.InnerException.Message, "VisualStudioCodeCredential unhandled exception");
                break;

            case 5:
                Assert.AreEqual(ex.InnerException.Message, "CliCredential unhandled exception");
                break;

            case 6:
                Assert.AreEqual(ex.InnerException.Message, "InteractiveBrowserCredential unhandled exception");
                break;

            default:
                Assert.Fail();
                break;
            }
        }
Пример #13
0
        public void ValidateAllUnavailable([Values(true, false)] bool excludeEnvironmentCredential,
                                           [Values(true, false)] bool excludeManagedIdentityCredential,
                                           [Values(true, false)] bool excludeSharedTokenCacheCredential,
                                           [Values(true, false)] bool excludeVisualStudioCredential,
                                           [Values(true, false)] bool excludeVisualStudioCodeCredential,
                                           [Values(true, false)] bool excludeCliCredential,
                                           [Values(true, false)] bool excludeInteractiveBrowserCredential)
        {
            if (excludeEnvironmentCredential && excludeManagedIdentityCredential && excludeSharedTokenCacheCredential && excludeVisualStudioCredential && excludeVisualStudioCodeCredential && excludeCliCredential && excludeInteractiveBrowserCredential)
            {
                Assert.Pass();
            }

            var credFactory = new MockDefaultAzureCredentialFactory(CredentialPipeline.GetInstance(null));

            credFactory.OnCreateEnvironmentCredential = (c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) => { throw new CredentialUnavailableException("EnvironmentCredential Unavailable"); };
            };
            credFactory.OnCreateInteractiveBrowserCredential = (_, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) => { throw new CredentialUnavailableException("InteractiveBrowserCredential Unavailable"); };
            };
            credFactory.OnCreateManagedIdentityCredential = (clientId, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) => { throw new CredentialUnavailableException("ManagedIdentityCredential Unavailable"); };
            };
            credFactory.OnCreateSharedTokenCacheCredential = (tenantId, username, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) => { throw new CredentialUnavailableException("SharedTokenCacheCredential Unavailable"); };
            };
            credFactory.OnCreateAzureCliCredential = (c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) => { throw new CredentialUnavailableException("CliCredential Unavailable"); };
            };
            credFactory.OnCreateVisualStudioCredential = (_, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) => { throw new CredentialUnavailableException("VisualStudioCredential Unavailable"); };
            };
            credFactory.OnCreateVisualStudioCodeCredential = (_, c) =>
            {
                ((MockTokenCredential)c).TokenFactory = (context, cancel) => { throw new CredentialUnavailableException("VisualStudioCodeCredential Unavailable"); };
            };

            var options = new DefaultAzureCredentialOptions
            {
                ExcludeEnvironmentCredential        = excludeEnvironmentCredential,
                ExcludeManagedIdentityCredential    = excludeManagedIdentityCredential,
                ExcludeSharedTokenCacheCredential   = excludeSharedTokenCacheCredential,
                ExcludeVisualStudioCredential       = excludeVisualStudioCredential,
                ExcludeVisualStudioCodeCredential   = excludeVisualStudioCodeCredential,
                ExcludeAzureCliCredential           = excludeCliCredential,
                ExcludeInteractiveBrowserCredential = excludeInteractiveBrowserCredential
            };

            var cred = new DefaultAzureCredential(credFactory, options);

            var ex = Assert.ThrowsAsync <CredentialUnavailableException>(async() => await cred.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));

            if (!excludeEnvironmentCredential)
            {
                Assert.True(ex.Message.Contains("EnvironmentCredential Unavailable"));
            }
            if (!excludeManagedIdentityCredential)
            {
                Assert.True(ex.Message.Contains("ManagedIdentityCredential Unavailable"));
            }
            if (!excludeSharedTokenCacheCredential)
            {
                Assert.True(ex.Message.Contains("SharedTokenCacheCredential Unavailable"));
            }
            if (!excludeCliCredential)
            {
                Assert.True(ex.Message.Contains("CliCredential Unavailable"));
            }
            if (!excludeInteractiveBrowserCredential)
            {
                Assert.True(ex.Message.Contains("InteractiveBrowserCredential Unavailable"));
            }
            if (!excludeVisualStudioCredential)
            {
                Assert.True(ex.Message.Contains("VisualStudioCredential Unavailable"));
            }
            if (!excludeVisualStudioCodeCredential)
            {
                Assert.True(ex.Message.Contains("VisualStudioCodeCredential Unavailable"));
            }
        }
Пример #14
0
        public void ValidateEnvironmentBasedOptionsPassedToCredentials([Values] bool clientIdSpecified, [Values] bool usernameSpecified, [Values] bool tenantIdSpecified)
        {
            var  expClientId               = clientIdSpecified ? Guid.NewGuid().ToString() : null;
            var  expUsername               = usernameSpecified ? Guid.NewGuid().ToString() : null;
            var  expTenantId               = tenantIdSpecified ? Guid.NewGuid().ToString() : null;
            bool onCreateSharedCalled      = false;
            bool onCreatedManagedCalled    = false;
            bool onCreateInteractiveCalled = false;
            bool onCreateVsCalled          = false;
            bool onCreateVsCodeCalled      = false;

            using (new TestEnvVar("AZURE_CLIENT_ID", expClientId))
                using (new TestEnvVar("AZURE_USERNAME", expUsername))
                    using (new TestEnvVar("AZURE_TENANT_ID", expTenantId))
                    {
                        var credFactory = new MockDefaultAzureCredentialFactory(CredentialPipeline.GetInstance(null));

                        credFactory.OnCreateManagedIdentityCredential = (clientId, _) =>
                        {
                            onCreatedManagedCalled = true;
                            Assert.AreEqual(expClientId, clientId);
                        };

                        credFactory.OnCreateSharedTokenCacheCredential = (tenantId, username, _) =>
                        {
                            onCreateSharedCalled = true;
                            Assert.AreEqual(expTenantId, tenantId);
                            Assert.AreEqual(expUsername, username);
                        };

                        credFactory.OnCreateInteractiveBrowserCredential = (tenantId, _) =>
                        {
                            onCreateInteractiveCalled = true;
                            Assert.AreEqual(expTenantId, tenantId);
                        };

                        credFactory.OnCreateVisualStudioCredential = (tenantId, _) =>
                        {
                            onCreateVsCalled = true;
                            Assert.AreEqual(expTenantId, tenantId);
                        };

                        credFactory.OnCreateVisualStudioCodeCredential = (tenantId, _) =>
                        {
                            onCreateVsCodeCalled = true;
                            Assert.AreEqual(expTenantId, tenantId);
                        };
                        var options = new DefaultAzureCredentialOptions
                        {
                            ExcludeEnvironmentCredential        = true,
                            ExcludeManagedIdentityCredential    = false,
                            ExcludeSharedTokenCacheCredential   = false,
                            ExcludeVisualStudioCredential       = false,
                            ExcludeVisualStudioCodeCredential   = false,
                            ExcludeAzureCliCredential           = true,
                            ExcludeInteractiveBrowserCredential = false
                        };

                        var cred = new DefaultAzureCredential(credFactory, options);

                        Assert.IsTrue(onCreateSharedCalled);
                        Assert.IsTrue(onCreatedManagedCalled);
                        Assert.IsTrue(onCreateInteractiveCalled);
                        Assert.IsTrue(onCreateVsCalled);
                        Assert.IsTrue(onCreateVsCodeCalled);
                    }
        }
Пример #15
0
        public async void Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
        {
            try
            {
                // After this is deployed, you need to turn the Managed Identity Status to "On",
                // Grab Object Id of the function and assigned "Azure Digital Twins Owner (Preview)" role
                // to this function identity in order for this function to be authorized on ADT APIs.
                //Authenticate with Digital Twins
                var credentials = new DefaultAzureCredential();
                log.LogInformation(credentials.ToString());
                DigitalTwinsClient client = new DigitalTwinsClient(
                    new Uri(adtServiceUrl), credentials, new DigitalTwinsClientOptions
                {
                    Transport = new HttpClientTransport(httpClient)
                });
                log.LogInformation($"ADT service client connection created.");
                if (eventGridEvent.Data.ToString().Contains("Alert"))
                {
                    JObject alertMessage = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString());
                    string  deviceId     = (string)alertMessage["systemProperties"]["iothub-connection-device-id"];
                    var     ID           = alertMessage["body"]["TurbineID"];
                    var     alert        = alertMessage["body"]["Alert"];
                    log.LogInformation($"Device:{deviceId} Device Id is:{ID}");
                    log.LogInformation($"Device:{deviceId} Alert Status is:{alert}");

                    var updateProperty = new JsonPatchDocument();
                    updateProperty.AppendReplace("/Alert", alert.Value <bool>());
                    updateProperty.AppendReplace("/TurbineID", ID.Value <string>());
                    log.LogInformation(updateProperty.ToString());
                    try
                    {
                        await client.UpdateDigitalTwinAsync(deviceId, updateProperty);
                    }
                    catch (Exception e)
                    {
                        log.LogInformation(e.Message);
                    }
                }
                else if (eventGridEvent != null && eventGridEvent.Data != null)
                {
                    JObject deviceMessage = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString());
                    string  deviceId      = (string)deviceMessage["systemProperties"]["iothub-connection-device-id"];
                    var     ID            = deviceMessage["body"]["TurbineID"];
                    var     TimeInterval  = deviceMessage["body"]["TimeInterval"];
                    var     Description   = deviceMessage["body"]["Description"];
                    var     Code          = deviceMessage["body"]["Code"];
                    var     WindSpeed     = deviceMessage["body"]["WindSpeed"];
                    var     Ambient       = deviceMessage["body"]["Ambient"];
                    var     Rotor         = deviceMessage["body"]["Rotor"];
                    var     Power         = deviceMessage["body"]["Power"];

                    log.LogInformation($"Device:{deviceId} Device Id is:{ID}");
                    log.LogInformation($"Device:{deviceId} Time interval is:{TimeInterval}");
                    log.LogInformation($"Device:{deviceId} Description is:{Description}");
                    log.LogInformation($"Device:{deviceId} CodeNumber is:{Code}");
                    log.LogInformation($"Device:{deviceId} WindSpeed is:{WindSpeed}");
                    log.LogInformation($"Device:{deviceId} Ambient Temperature is:{Ambient}");
                    log.LogInformation($"Device:{deviceId} Rotor RPM is:{Rotor}");
                    log.LogInformation($"Device:{deviceId} Power is:{Power}");
                    var updateProperty   = new JsonPatchDocument();
                    var turbineTelemetry = new Dictionary <string, Object>()
                    {
                        ["TurbineID"]    = ID,
                        ["TimeInterval"] = TimeInterval,
                        ["Description"]  = Description,
                        ["Code"]         = Code,
                        ["WindSpeed"]    = WindSpeed,
                        ["Ambient"]      = Ambient,
                        ["Rotor"]        = Rotor,
                        ["Power"]        = Power
                    };
                    updateProperty.AppendAdd("/TurbineID", ID.Value <string>());

                    log.LogInformation(updateProperty.ToString());
                    try
                    {
                        await client.PublishTelemetryAsync(deviceId, Guid.NewGuid().ToString(), JsonConvert.SerializeObject(turbineTelemetry));
                    }
                    catch (Exception e)
                    {
                        log.LogInformation(e.Message);
                    }
                }
            }
            catch (Exception e)
            {
                log.LogInformation(e.Message);
            }
        }
Пример #16
0
        public static async Task Run([IoTHubTrigger("messages/events", Connection = "IoTHubBuiltInConnection", ConsumerGroup = "function")] EventData message, ILogger log)
        {
            DigitalTwinsClient client;

            try
            {
                //Authenticate with Digital Twins
                var credentials = new DefaultAzureCredential();
                client = new DigitalTwinsClient(
                    new Uri(adtServiceUrl),
                    credentials,
                    new DigitalTwinsClientOptions {
                    Transport = new HttpClientTransport(httpClient)
                }
                    );

                log.LogInformation($"ADT service client connection created.");
            }
            catch (Exception e)
            {
                log.LogError($"ADT service client connection failed. {e}");
                return;
            }

            if (client != null)
            {
                if (message != null && message.Body != null)
                {
                    var msg = Encoding.UTF8.GetString(message.Body.Array);
                    log.LogInformation($"C# IoT Hub trigger function processed a message: {msg}");

                    // Get device Id
                    string deviceId = (string)message.SystemProperties["iothub-connection-device-id"];

                    try
                    {
                        var sensordata = JsonConvert.DeserializeObject <SensorMessage>(msg);

                        JsonPatchDocument updateTwinData = new JsonPatchDocument();
                        updateTwinData.AppendReplace <string>("/Name", sensordata.SensorName);
                        updateTwinData.AppendReplace <float>("/Value", (float)sensordata.SensorValue);

                        await client.UpdateDigitalTwinAsync(deviceId, updateTwinData);   //deviceId == dtid
                    }
                    catch (JsonException jex)
                    {
                        log.LogError("Message parsing error.", jex);
                    }
                    catch (RequestFailedException exc)
                    {
                        log.LogInformation($"{deviceId}*** Error:{exc.Status}/{exc.Message}");

                        // 최초 Update 할 경우 Replace를 쓰면 오류발생. Add를 써야함.
                        var sensordata = JsonConvert.DeserializeObject <SensorMessage>(msg);

                        JsonPatchDocument addTwinData = new JsonPatchDocument();
                        addTwinData.AppendAdd <string>("/Name", sensordata.SensorName);
                        addTwinData.AppendAdd <float>("/Value", (float)sensordata.SensorValue);

                        await client.UpdateDigitalTwinAsync(deviceId, addTwinData);
                    }
                    catch (Exception ex)
                    {
                        log.LogError("Update Twin error.", ex);
                    }
                }
            }
        }
Пример #17
0
        async Task IAzureTableStoreClient.AddRecordAsync <T>(string tableName, string partitionKey, string rowKey, T record, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(tableName))
            {
                throw new ArgumentNullException(nameof(tableName));
            }
            if (string.IsNullOrWhiteSpace(partitionKey))
            {
                throw new ArgumentNullException(nameof(partitionKey));
            }
            if (string.IsNullOrWhiteSpace(rowKey))
            {
                throw new ArgumentNullException(nameof(rowKey));
            }
            if (record is null)
            {
                throw new ArgumentNullException(nameof(record));
            }
            if (0 >= record.Count)
            {
                throw new ArgumentOutOfRangeException("The record does not contain any data");
            }
            if (record.ContainsKey("PartitionKey"))
            {
                throw new ArgumentOutOfRangeException("The record cannot contain a key called PartitionKey");
            }
            if (record.ContainsKey("RowKey"))
            {
                throw new ArgumentOutOfRangeException("The record cannot contain a key called RowKey");
            }

            cancellationToken.ThrowIfCancellationRequested();

            var managedIdentityCredential = new DefaultAzureCredential();

            var tableClientOptions = GetTableClientOptions(_geoRedundantServiceUrl);

            var tableServiceClient = new TableServiceClient(_primaryServiceUrl, managedIdentityCredential, tableClientOptions);

            var tableClient = tableServiceClient.GetTableClient(tableName);

            var entity = new TableEntity(partitionKey, rowKey);

            foreach (var kvp in record)
            {
                entity.Add(kvp.Key, kvp.Value);
            }

            try
            {
                using var response = await tableClient.AddEntityAsync(entity, cancellationToken);

                if (!IsSuccessStatusCode(response?.Status ?? int.MinValue))
                {
                    Debug.Assert(response is not null);

                    _logger?.LogDebug("Unable to write a record to table storage '{TableName}'.  {ClientRequestId} - Reported '{ReasonPhrase}' with status code: '{StatusCode} {StatusCodeName}'", response.ClientRequestId, tableName, response.ReasonPhrase, response.Status, Enum.Parse(typeof(HttpStatusCode), Convert.ToString(response.Status, CultureInfo.InvariantCulture)));

                    // TODO - Add custom table storage exception

                    throw new ApplicationException($"{response.ClientRequestId}: Unable to write the record to table storage '{tableName}'.  Please consult log files for more information");
                }
            }
            catch (AuthenticationFailedException ex)
            {
                _logger?.LogError(ex, "Unable to authenticate with the Azure Table Storage service using the default credentials.  Please ensure the user account this application is running under has permissions to access the Blob Storage account we are targeting");

                throw;
            }
            catch (RequestFailedException ex)
            {
                _logger?.LogError(ex, "Unable to access the Table storage endpoint as the Add request failed: '{StatusCode} {StatusCodeName}'", ex.Status, Enum.Parse(typeof(HttpStatusCode), Convert.ToString(ex.Status, CultureInfo.InvariantCulture)));

                throw;
            }
        }
Пример #18
0
        static async Task Main()
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                int width  = Math.Min(Console.LargestWindowWidth, 150);
                int height = Math.Min(Console.LargestWindowHeight, 40);
                Console.SetWindowSize(width, height);
            }
            try
            {
                // Read configuration data from the
                IConfiguration config = new ConfigurationBuilder()
                                        .AddJsonFile("serviceConfig.json", true, true)
                                        .Build();
                //clientId = config["clientId"];
                tenantId       = config["tenantId"];
                adtInstanceUrl = config["instanceUrl"];
            } catch (Exception e)
            {
                Log.Error($"Could not read service configuration file serviceConfig.json");
                Log.Alert($"Please copy serviceConfig.json.TEMPLATE to serviceConfig.json");
                Log.Alert($"and edit to reflect your service connection settings");
                Environment.Exit(0);
            }

            Log.Ok("Authenticating...");
            try
            {
                //var credential = new InteractiveBrowserCredential(tenantId, clientId);
                var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions()
                {
                    SharedTokenCacheTenantId = tenantId
                });
                client = new DigitalTwinsClient(new Uri(adtInstanceUrl), credential);


                //var tokenProvider = new AzureServiceTokenProvider("RunAs=Developer; DeveloperTool=AzureCli");
                //TokenCredentials tk = new TokenCredentials(await tokenProvider.GetAccessTokenAsync("0b07f429-9f4b-4714-9392-cc5e8e80c8b0"));
                //var t1 = await tokenProvider.GetAccessTokenAsync("0b07f429-9f4b-4714-9392-cc5e8e80c8b0");
                // force authentication to happen here
                // (for some reason this only happens on first call)
                try
                {
                    client.GetDigitalTwin("MilleniumF");
                }
                catch (RequestFailedException rex)
                {
                }
                catch (Exception e)
                {
                    Log.Error($"Authentication or client creation error: {e.Message}");
                    Environment.Exit(0);
                }
            } catch (Exception e)
            {
                Log.Error($"Authentication or client creation error: {e.Message}");
                Environment.Exit(0);
            }

            Log.Ok($"Service client created – ready to go");

            CommandLoop CommandLoopInst = new CommandLoop(client);
            await CommandLoopInst.CliCommandInterpreter();
        }
Пример #19
0
        static async Task Main(string[] args)
        {
            var appConfigurationName = Environment.GetEnvironmentVariable("APP_CONFIG_NAME") ?? "cloudscale-app-config";
            var sentinelKey          = "LearnAppConfig:Sentinel";

            IConfigurationRefresher configurationRefresher = null;

            var credential = new DefaultAzureCredential();

            IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
                                                         .SetBasePath(Directory.GetCurrentDirectory())
                                                         .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                                                         .AddJsonFile("appsettings.local.json", optional: true, reloadOnChange: true)
                                                         .AddJsonFile("appsettings.development.json", optional: true, reloadOnChange: true)
                                                         .AddAzureAppConfiguration(
                p =>
            {
                if (!string.IsNullOrEmpty(appConfigurationName))
                {
                    p.Connect(new Uri($"https://{appConfigurationName}.azconfig.io"), credential)
                    .ConfigureKeyVault(kv => { kv.SetCredential(credential); })
                    .ConfigureRefresh(refresh =>
                    {
                        refresh.Register(sentinelKey, refreshAll: true)
                        .SetCacheExpiration(new TimeSpan(0, 0, 30));
                    })
                    .UseFeatureFlags();

                    configurationRefresher = p.GetRefresher();
                }
            },
                optional: true)
                                                         .AddUserSecrets <Program>(optional: true)
                                                         .AddEnvironmentVariables()
                                                         .AddCommandLine(args);

            IConfiguration configuration = configurationBuilder.Build();

            Log.Logger = new LoggerConfiguration()
                         .MinimumLevel.Debug()
                         .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
                         .Enrich.FromLogContext()
                         .ReadFrom.Configuration(configuration)
                         .WriteTo.LiterateConsole()
                         .CreateLogger();

            var serviceBuilder = new ServiceCollection();

            serviceBuilder
            .AddOptions()
            .AddOptions <LearnAppConfigOptions>()
            .Bind(configuration.GetSection(LearnAppConfigOptions.SectionName))
            .ValidateDataAnnotations();

            serviceBuilder.AddTransient <IConfiguration>(p => configuration);
            serviceBuilder.AddLogging(builder => builder.AddSerilog(dispose: false));
            serviceBuilder.AddSingleton <IConfigurationRefresher>(configurationRefresher);
            serviceBuilder.AddAzureAppConfiguration();
            serviceBuilder.AddFeatureManagement().AddFeatureFilter <PercentageFilter>();

            var serviceProvider = serviceBuilder.BuildServiceProvider();

            var logger         = serviceProvider.GetRequiredService <ILogger <Program> >();
            var options        = serviceProvider.GetRequiredService <IOptionsMonitor <LearnAppConfigOptions> >();
            var refresher      = serviceProvider.GetRequiredService <IConfigurationRefresher>();
            var featureManager = serviceProvider.GetRequiredService <IFeatureManager>();

            for (int i = 0; i < 1000; i++)
            {
                await refresher.RefreshAsync();

                logger.LogInformation("Options SampleString = {Value}", options.CurrentValue.SampleString);
                logger.LogInformation("Options SampleSecret = {Value}", options.CurrentValue.SampleSecret);

                if (await featureManager.IsEnabledAsync(nameof(LearnAppConfigFeatureFlags.FeatureA)))
                {
                    logger.LogInformation("Feature A is Enabled");
                }

                if (await featureManager.IsEnabledAsync(nameof(LearnAppConfigFeatureFlags.FeatureB)))
                {
                    logger.LogInformation("Feature B is Enabled");
                }

                if (await featureManager.IsEnabledAsync(nameof(LearnAppConfigFeatureFlags.FeatureC)))
                {
                    logger.LogInformation("Feature C is Enabled");
                }

                Thread.Sleep(5000);
            }

            Log.CloseAndFlush();
        }
Пример #20
0
        public async Task ConnectionStringParse()
        {
            await using var eventHubScope = await EventHubScope.CreateAsync(1);

            await using var storageScope = await StorageScope.CreateAsync();

            #region Snippet:EventHubs_Processor_Sample05_ConnectionStringParse

            TokenCredential credential = new DefaultAzureCredential();

            var storageConnectionString = "<< CONNECTION STRING FOR THE STORAGE ACCOUNT >>";
            var blobContainerName       = "<< NAME OF THE BLOB CONTAINER >>";
            /*@@*/
            /*@@*/ storageConnectionString = StorageTestEnvironment.Instance.StorageConnectionString;
            /*@@*/ blobContainerName       = storageScope.ContainerName;

            var eventHubsConnectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>";
            var eventHubName  = "<< NAME OF THE EVENT HUB >>";
            var consumerGroup = "<< NAME OF THE EVENT HUB CONSUMER GROUP >>";
            /*@@*/
            /*@@*/ eventHubsConnectionString = EventHubsTestEnvironment.Instance.EventHubsConnectionString;
            /*@@*/ eventHubName  = eventHubScope.EventHubName;
            /*@@*/ consumerGroup = eventHubScope.ConsumerGroups.First();
            /*@@*/ credential    = EventHubsTestEnvironment.Instance.Credential;

            var storageEndpoint = new BlobServiceClient(storageConnectionString).Uri;
            var blobUriBuilder  = new BlobUriBuilder(storageEndpoint);
            blobUriBuilder.BlobContainerName = blobContainerName;

            var storageClient = new BlobContainerClient(
                blobUriBuilder.ToUri(),
                credential);

            EventHubsConnectionStringProperties properties =
                EventHubsConnectionStringProperties.Parse(eventHubsConnectionString);

            var processor = new EventProcessorClient(
                storageClient,
                consumerGroup,
                properties.FullyQualifiedNamespace,
                properties.EventHubName ?? eventHubName,
                credential);

            try
            {
                using var cancellationSource = new CancellationTokenSource();
                cancellationSource.CancelAfter(TimeSpan.FromSeconds(30));

                // The event handlers are not relevant for this sample; for
                // illustration, they're delegating the implementation to the
                // host application.

                processor.ProcessEventAsync += Application.ProcessorEventHandler;
                processor.ProcessErrorAsync += Application.ProcessorErrorHandler;

                try
                {
                    await processor.StartProcessingAsync(cancellationSource.Token);

                    await Task.Delay(Timeout.Infinite, cancellationSource.Token);
                }
                catch (TaskCanceledException)
                {
                    // This is expected if the cancellation token is
                    // signaled.
                }
                finally
                {
                    // This may take up to the length of time defined
                    // as part of the configured TryTimeout of the processor;
                    // by default, this is 60 seconds.

                    await processor.StopProcessingAsync();
                }
            }
            catch
            {
                // If this block is invoked, then something external to the
                // processor was the source of the exception.
            }
            finally
            {
                // It is encouraged that you unregister your handlers when you have
                // finished using the Event Processor to ensure proper cleanup.

                processor.ProcessEventAsync -= Application.ProcessorEventHandler;
                processor.ProcessErrorAsync -= Application.ProcessorErrorHandler;
            }

            #endregion
        }
Пример #21
0
        private async Task RunReceiveLoopAsync()
        {
            var  cred         = new DefaultAzureCredential();
            var  client       = new ServiceBusClient(NamespaceName, cred);
            long messageCount = 0;
            var  sw           = Stopwatch.StartNew();
            var  bagStart     = sw.ElapsedMilliseconds;

            Console.WriteLine($"Receiving from entity '{EntityName}' in namespace '{NamespaceName}'");

            var timer = new Timer(state =>
            {
                var snapshot    = Interlocked.Exchange(ref messageCount, 0);
                var bagDuration = sw.ElapsedMilliseconds - bagStart;
                bagStart        = sw.ElapsedMilliseconds;

                Console.ResetColor();
                Console.WriteLine($"\nReceived {snapshot / (bagDuration / 1000.0)} msg/sec,  {snapshot} in {bagDuration} ms");
            }, null, 10000, 10000);


            var receiver = client.CreateReceiver(EntityName, new ServiceBusReceiverOptions()
            {
                PrefetchCount = this.PrefetchCount,
                ReceiveMode   = this.ReceiveDelete ? ServiceBusReceiveMode.ReceiveAndDelete : ServiceBusReceiveMode.PeekLock,
            });

            CancellationTokenSource cts = new CancellationTokenSource();

            Console.CancelKeyPress += (a, o) => { cts.Cancel(); };

            do
            {
                var message = await receiver.ReceiveMessageAsync(cancellationToken : cts.Token);

                if (message != null)
                {
                    try
                    {
                        if (!string.IsNullOrEmpty(message.SessionId) ||
                            !string.IsNullOrEmpty(message.Subject))
                        {
                            int color = Math.Abs(string.IsNullOrEmpty(message.SessionId) ? message.Subject.GetHashCode() : message.SessionId.GetHashCode());
                            Console.BackgroundColor = ConsoleColor.Black;
                            Console.ForegroundColor = (ConsoleColor)((color % 14) + 1);
                        }
                        Console.Write("[]");
                        Interlocked.Increment(ref messageCount);
                        if (!this.ReceiveDelete)
                        {
                            await receiver.CompleteMessageAsync(message, cts.Token);
                        }
                    }
                    catch
                    {
                        if (!this.ReceiveDelete)
                        {
                            await receiver.AbandonMessageAsync(message, cancellationToken : cts.Token);
                        }
                    }
                }
            }while (!cts.IsCancellationRequested);

            timer.Dispose();
            await receiver.CloseAsync();

            await client.DisposeAsync();
        }
Пример #22
0
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.Replace(ServiceDescriptor.Transient(typeof(IOptionsFactory <>), typeof(OptionsFactory <>)));

            builder.Services.AddHttpClient();

            builder.Services.AddSingleton(new LookupClient(new LookupClientOptions {
                UseCache = false
            }));

            builder.Services.AddSingleton <IAzureEnvironment>(provider =>
            {
                var options = provider.GetRequiredService <IOptions <AcmebotOptions> >();

                return(AzureEnvironment.Get(options.Value.Environment));
            });

            builder.Services.AddSingleton(provider =>
            {
                var options     = provider.GetRequiredService <IOptions <AcmebotOptions> >();
                var environment = provider.GetRequiredService <IAzureEnvironment>();

                var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
                {
                    AuthorityHost = new Uri(environment.ActiveDirectory)
                });

                return(new CertificateClient(new Uri(options.Value.VaultBaseUrl), credential));
            });

            builder.Services.AddSingleton <IAcmeProtocolClientFactory, AcmeProtocolClientFactory>();

            builder.Services.AddSingleton <WebhookClient>();
            builder.Services.AddSingleton <ILifeCycleNotificationHelper, WebhookLifeCycleNotification>();

            builder.Services.AddSingleton <IDnsProvider>(provider =>
            {
                var options     = provider.GetRequiredService <IOptions <AcmebotOptions> >().Value;
                var environment = provider.GetRequiredService <IAzureEnvironment>();

                if (options.Cloudflare != null)
                {
                    return(new CloudflareProvider(options.Cloudflare));
                }

                if (options.GratisDns != null)
                {
                    return(new GratisDnsProvider(options.GratisDns));
                }

                if (options.AzureDns != null)
                {
                    return(new AzureDnsProvider(options.AzureDns, environment));
                }

                if (options.SubscriptionId != null)
                {
                    return(new AzureDnsProvider(new AzureDnsOptions {
                        SubscriptionId = options.SubscriptionId
                    }, environment));
                }

                throw new NotSupportedException();
            });

            var context = builder.GetContext();

            var section = context.Configuration.GetSection("Acmebot");

            builder.Services.AddOptions <AcmebotOptions>()
            .Bind(section.Exists() ? section : context.Configuration.GetSection("LetsEncrypt"))
            .ValidateDataAnnotations();
        }
Пример #23
0
        private static async Task HandleDeviceMessage(DeviceMessage deviceCommandMessage,
                                                      DeviceClient primaryClient, DeviceClient secondaryClient,
                                                      string firstHubName, string secondHubName)
        {
            // this section demonstrates how to parse a non-binary DeviceCommandMessage that was sent down.
            // Later more advanced kits will discuss using binary payloads as another possibility.
            string rawContent;

            using (StreamReader reader = new StreamReader(deviceCommandMessage.BodyStream))
            {
                rawContent = await reader.ReadToEndAsync();
            }

            //DeviceCommandMessage parsedMessage = JsonConvert.DeserializeObject<DeviceCommandMessage>(rawContent);
            DeviceCommandMessage parsedMessage = System.Text.Json.JsonSerializer.Deserialize <DeviceCommandMessage>(rawContent);

            // Create a secret client using the DefaultAzureCredential
            DefaultAzureCredential cred  = new DefaultAzureCredential();
            DigitalTwinsClient     dtcli = new DigitalTwinsClient(new Uri("https://mobility-vss.api.wus2.digitaltwins.azure.net"), cred);

            BasicDigitalTwin twinData = new BasicDigitalTwin();

            JsonElement ele = (JsonElement)parsedMessage.Payload;

            twinData.Id = ele.GetProperty("$dtId").ToString();
            twinData.Metadata.ModelId = ele.GetProperty("$metadata").GetProperty("$model").ToString();

            await dtcli.CreateDigitalTwinAsync(twinData.Id, System.Text.Json.JsonSerializer.Serialize(twinData));

            await primaryClient.CompleteAsync(deviceCommandMessage);

            Console.WriteLine("The received command name is: " + parsedMessage.CommandName);

            Console.Write("Enter a response string:\n>");
            string responseString = Console.ReadLine();

            // construct a basic Device Telemetry Message with a minimal set of fields.  This will be used to respond to the command.
            DeviceTelemetryMessage telemetryMessage = new DeviceTelemetryMessage
            {
                TelemetryName = parsedMessage.CommandName,
                Payload       = new { rawContent },
                Priority      = MessagePriority.Normal,
                CorrelationId = parsedMessage.CorrelationId // setting the correlation ID allows the platform to recognize this is a response to the previous device command message.
            };

            // construct the actual IoT message.  Setting the content type is necessary for prioritization to function properly within CVS.
            using (DeviceMessage deviceMessage = new DeviceMessage(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(telemetryMessage))))
            {
                deviceMessage.ContentType = "application/json";

                // enqueues the event within IoTHub.  The completion of this event means that it has been enqueued to the cloud, but
                // does not imply that the cloud has actually processed the telemetry message yet.
                try
                {
                    await primaryClient.SendEventAsync(deviceMessage);

                    Console.WriteLine($"Sent telemetry message to {firstHubName} IoTHub in response!");
                }
                catch (Exception)
                {
                    await secondaryClient.SendEventAsync(deviceMessage);

                    Console.WriteLine($"Sent telemetry message to {secondHubName} IoTHub in response!");
                }
            }
        }
        // <Async_signature>
        static async Task Main(string[] args)
        {
            // </Async_signature>
            Console.WriteLine("Hello World!");
            // <Authentication_code>
            string adtInstanceUrl = "https://<your-Azure-Digital-Twins-instance-hostName>";

            var credential = new DefaultAzureCredential();
            var client     = new DigitalTwinsClient(new Uri(adtInstanceUrl), credential);

            Console.WriteLine($"Service client created – ready to go");
            // </Authentication_code>

            // <Model_code>
            Console.WriteLine();
            Console.WriteLine("Upload a model");
            string dtdl   = File.ReadAllText("SampleModel.json");
            var    models = new List <string> {
                dtdl
            };

            // Upload the model to the service
            // <Model_try_catch>
            try
            {
                await client.CreateModelsAsync(models);

                Console.WriteLine("Models uploaded to the instance:");
            }
            catch (RequestFailedException e)
            {
                Console.WriteLine($"Upload model error: {e.Status}: {e.Message}");
            }
            // </Model_try_catch>

            // <Print_model>
            // Read a list of models back from the service
            AsyncPageable <DigitalTwinsModelData> modelDataList = client.GetModelsAsync();

            await foreach (DigitalTwinsModelData md in modelDataList)
            {
                Console.WriteLine($"Model: {md.Id}");
            }
            // </Print_model>
            // </Model_code>

            // <Initialize_twins>
            var twinData = new BasicDigitalTwin();

            twinData.Metadata.ModelId = "dtmi:example:SampleModel;1";
            twinData.Contents.Add("data", $"Hello World!");

            string prefix = "sampleTwin-";

            for (int i = 0; i < 3; i++)
            {
                try
                {
                    twinData.Id = $"{prefix}{i}";
                    await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(twinData.Id, twinData);

                    Console.WriteLine($"Created twin: {twinData.Id}");
                }
                catch (RequestFailedException e)
                {
                    Console.WriteLine($"Create twin error: {e.Status}: {e.Message}");
                }
            }
            // </Initialize_twins>

            // <Use_create_relationship>
            // Connect the twins with relationships
            await CreateRelationshipAsync(client, "sampleTwin-0", "sampleTwin-1");
            await CreateRelationshipAsync(client, "sampleTwin-0", "sampleTwin-2");

            // </Use_create_relationship>

            // <Use_list_relationships>
            //List the relationships
            await ListRelationshipsAsync(client, "sampleTwin-0");

            // </Use_list_relationships>

            // <Query_twins>
            // Run a query for all twins
            string query = "SELECT * FROM digitaltwins";
            AsyncPageable <BasicDigitalTwin> queryResult = client.QueryAsync <BasicDigitalTwin>(query);

            await foreach (BasicDigitalTwin twin in queryResult)
            {
                Console.WriteLine(JsonSerializer.Serialize(twin));
                Console.WriteLine("---------------");
            }
            // </Query_twins>
        }
 public static TokenCredential[] _sources(this DefaultAzureCredential credential)
 {
     return(typeof(DefaultAzureCredential).GetField("_sources", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(credential) as TokenCredential[]);
 }
        /// <summary>
        /// Run the sample async.
        /// </summary>
        /// <param name="config">The param is of type ConfigWrapper. This class reads values from local configuration file.</param>
        /// <returns></returns>
        private static async Task RunAsync(ConfigWrapper config)
        {
            IAzureMediaServicesClient client;

            try
            {
                client = await Authentication.CreateMediaServicesClientAsync(config, UseInteractiveAuth);
            }
            catch (Exception e)
            {
                Console.Error.WriteLine("TIP: Make sure that you have filled out the appsettings.json or .env file before running this sample.");
                Console.Error.WriteLine($"{e.Message}");
                return;
            }

            // Set the polling interval for long running operations to 2 seconds.
            // The default value is 30 seconds for the .NET client SDK
            client.LongRunningOperationRetryTimeout = 2;

            // Creating a unique suffix so that we don't have name collisions if you run the sample
            // multiple times without cleaning up.
            string uniqueness      = Guid.NewGuid().ToString("N");
            string jobName         = $"job-{uniqueness}";
            string outputAssetName = $"output-{uniqueness}";
            string inputAssetName  = $"input-{uniqueness}";

            // Create an AudioAnalyzer preset with audio insights and Basic audio mode.
            Preset preset = new AudioAnalyzerPreset(
                audioLanguage: "en-US",
                //
                // There are two modes available, Basic and Standard
                // Basic : This mode performs speech-to-text transcription and generation of a VTT subtitle/caption file.
                //         The output of this mode includes an Insights JSON file including only the keywords, transcription,and timing information.
                //         Automatic language detection and speaker diarization are not included in this mode.
                // Standard : Performs all operations included in the Basic mode, additionally performing language detection and speaker diarization.
                //
                mode: AudioAnalysisMode.Standard
                );

            // Ensure that you have the desired encoding Transform. This is really a one time setup operation.
            // Once it is created, we won't delete it.
            Transform audioAnalyzerTransform = await GetOrCreateTransformAsync(client, config.ResourceGroup, config.AccountName, AudioAnalyzerTransformName, preset);

            // Create a new input Asset and upload the specified local media file into it.
            await CreateInputAssetAsync(client, config.ResourceGroup, config.AccountName, inputAssetName, InputMP4FileName);

            // Output from the encoding Job must be written to an Asset, so let's create one
            Asset outputAsset = await CreateOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAssetName);

            // Use a preset override to change the language or mode on the Job level.
            // Above we created a Transform with a preset that was set to a specific audio language and mode.
            // If we want to change that language or mode before submitting the job, we can modify it using the PresetOverride property
            // on the JobOutput.

            #region PresetOverride
            // First we re-define the preset that we want to use for this specific Job...
            var presetOverride = new AudioAnalyzerPreset
            {
                AudioLanguage = "en-US",
                Mode          = AudioAnalysisMode.Basic /// Switch this job to use Basic mode instead of standard
            };

            // Then we use the PresetOverride property of the JobOutput to pass in the override values to use on this single Job
            // without the need to create a completely separate and new Transform with another langauge code or Mode setting.
            // This can save a lot of complexity in your AMS account and reduce the number of Transforms used.
            JobOutput jobOutput = new JobOutputAsset()
            {
                AssetName      = outputAsset.Name,
                PresetOverride = presetOverride
            };

            Job job = await SubmitJobAsync(client, config.ResourceGroup, config.AccountName, AudioAnalyzerTransformName, jobName, inputAssetName, jobOutput);

            #endregion PresetOverride

            // In this sample, we use Event Grid to listen to the notifications through an Azure Event Hub.
            // If you do not provide an Event Hub config in the settings, the sample will fall back to polling the job for status.
            // For production ready code, it is always recommended to use Event Grid instead of polling on the Job status.

            EventProcessorClient        processorClient     = null;
            BlobContainerClient         storageClient       = null;
            MediaServicesEventProcessor mediaEventProcessor = null;
            try
            {
                // First we will try to process Job events through Event Hub in real-time. If this fails for any reason,
                // we will fall-back on polling Job status instead.

                // Please refer README for Event Hub and storage settings.
                // A storage account is required to process the Event Hub events from the Event Grid subscription in this sample.

                // Create a new host to process events from an Event Hub.
                Console.WriteLine("Creating a new client to process events from an Event Hub...");
                var credential = new DefaultAzureCredential();
                var storageConnectionString = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}",
                                                            config.StorageAccountName, config.StorageAccountKey);
                var blobContainerName         = config.StorageContainerName;
                var eventHubsConnectionString = config.EventHubConnectionString;
                var eventHubName  = config.EventHubName;
                var consumerGroup = config.EventHubConsumerGroup;

                storageClient = new BlobContainerClient(
                    storageConnectionString,
                    blobContainerName);

                processorClient = new EventProcessorClient(
                    storageClient,
                    consumerGroup,
                    eventHubsConnectionString,
                    eventHubName);

                // Create an AutoResetEvent to wait for the job to finish and pass it to EventProcessor so that it can be set when a final state event is received.
                AutoResetEvent jobWaitingEvent = new(false);

                // Create a Task list, adding a job waiting task and a timer task. Other tasks can be added too.
                IList <Task> tasks = new List <Task>();

                // Add a task to wait for the job to finish. The AutoResetEvent will be set when a final state is received by EventProcessor.
                Task jobTask = Task.Run(() =>
                                        jobWaitingEvent.WaitOne());
                tasks.Add(jobTask);

                // 30 minutes timeout.
                var cancellationSource = new CancellationTokenSource();
                var timeout            = Task.Delay(30 * 60 * 1000, cancellationSource.Token);

                tasks.Add(timeout);
                mediaEventProcessor = new MediaServicesEventProcessor(jobName, jobWaitingEvent, null);
                processorClient.ProcessEventAsync += mediaEventProcessor.ProcessEventsAsync;
                processorClient.ProcessErrorAsync += mediaEventProcessor.ProcessErrorAsync;

                await processorClient.StartProcessingAsync(cancellationSource.Token);

                // Wait for tasks.
                if (await Task.WhenAny(tasks) == jobTask)
                {
                    // Job finished. Cancel the timer.
                    cancellationSource.Cancel();
                    // Get the latest status of the job.
                    job = await client.Jobs.GetAsync(config.ResourceGroup, config.AccountName, AudioAnalyzerTransformName, jobName);
                }
                else
                {
                    // Timeout happened, Something might be wrong with job events. Fall-back on polling instead.
                    jobWaitingEvent.Set();
                    throw new Exception("Timeout occurred.");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Warning: Failed to connect to Event Hub, please refer README for Event Hub and storage settings.");
                Console.WriteLine(e.Message);

                // Polling is not a recommended best practice for production applications because of the latency it introduces.
                // Overuse of this API may trigger throttling. Developers should instead use Event Grid and listen for the status events on the jobs
                Console.WriteLine("Polling job status...");
                job = await WaitForJobToFinishAsync(client, config.ResourceGroup, config.AccountName, AudioAnalyzerTransformName, jobName);
            }
            finally
            {
                if (processorClient != null)
                {
                    Console.WriteLine("Job final state received, Stopping the event processor...");
                    await processorClient.StopProcessingAsync();

                    Console.WriteLine();

                    // It is encouraged that you unregister your handlers when you have
                    // finished using the Event Processor to ensure proper cleanup.  This
                    // is especially important when using lambda expressions or handlers
                    // in any form that may contain closure scopes or hold other references.
                    processorClient.ProcessEventAsync -= mediaEventProcessor.ProcessEventsAsync;
                    processorClient.ProcessErrorAsync -= mediaEventProcessor.ProcessErrorAsync;
                }
            }

            if (job.State == JobState.Finished)
            {
                Console.WriteLine("Job finished.");
                if (!Directory.Exists(OutputFolderName))
                {
                    Directory.CreateDirectory(OutputFolderName);
                }

                await DownloadOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAsset.Name, OutputFolderName);
            }

            await CleanUpAsync(client, config.ResourceGroup, config.AccountName, AudioAnalyzerTransformName, inputAssetName, outputAssetName, jobName);
        }
Пример #27
0
        public override void Configure(IFunctionsHostBuilder builder)
        {
            var context = builder.GetContext();

            var section = context.Configuration.GetSection("Acmebot");

            // Add Options
            builder.Services.AddOptions <AcmebotOptions>()
            .Bind(section.Exists() ? section : context.Configuration.GetSection("LetsEncrypt"))
            .ValidateDataAnnotations()
            .PostConfigure(options =>
            {
                // Backward compatibility
                if (options.Endpoint == "https://acme-v02.api.letsencrypt.org/")
                {
                    options.PreferredChain ??= "DST Root CA X3";
                }
            });

            // Add Services
            builder.Services.Replace(ServiceDescriptor.Transient(typeof(IOptionsFactory <>), typeof(OptionsFactory <>)));

            builder.Services.AddHttpClient();

            builder.Services.AddSingleton <ITelemetryInitializer, ApplicationVersionInitializer <Startup> >();

            builder.Services.AddSingleton(new LookupClient(new LookupClientOptions(NameServer.GooglePublicDns, NameServer.GooglePublicDns2)
            {
                UseCache            = false,
                UseRandomNameServer = true
            }));

            builder.Services.AddSingleton(provider =>
            {
                var options = provider.GetRequiredService <IOptions <AcmebotOptions> >();

                return(AzureEnvironment.Get(options.Value.Environment));
            });

            builder.Services.AddSingleton(provider =>
            {
                var options     = provider.GetRequiredService <IOptions <AcmebotOptions> >();
                var environment = provider.GetRequiredService <AzureEnvironment>();

                var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
                {
                    AuthorityHost = environment.ActiveDirectory
                });

                return(new CertificateClient(new Uri(options.Value.VaultBaseUrl), credential));
            });

            builder.Services.AddSingleton <AcmeProtocolClientFactory>();

            builder.Services.AddSingleton <WebhookInvoker>();
            builder.Services.AddSingleton <ILifeCycleNotificationHelper, WebhookLifeCycleNotification>();

            builder.Services.AddSingleton <IDnsProvider>(provider =>
            {
                var options     = provider.GetRequiredService <IOptions <AcmebotOptions> >().Value;
                var environment = provider.GetRequiredService <AzureEnvironment>();

                if (options.Cloudflare != null)
                {
                    return(new CloudflareProvider(options.Cloudflare));
                }

                if (options.DnsMadeEasy != null)
                {
                    return(new DnsMadeEasyProvider(options.DnsMadeEasy));
                }

                if (options.Google != null)
                {
                    return(new GoogleDnsProvider(options.Google));
                }

                if (options.GratisDns != null)
                {
                    return(new GratisDnsProvider(options.GratisDns));
                }

                if (options.TransIp != null)
                {
                    return(new TransIpProvider(options, options.TransIp, environment));
                }

                if (options.AzureDns != null)
                {
                    return(new AzureDnsProvider(options.AzureDns, environment));
                }

                // Backward compatibility
                if (options.SubscriptionId != null)
                {
                    return(new AzureDnsProvider(new AzureDnsOptions {
                        SubscriptionId = options.SubscriptionId
                    }, environment));
                }

                throw new NotSupportedException("DNS Provider is not configured. Please check the documentation and configure it.");
            });
        }
Пример #28
0
        async Task <BlobDownloadDetails> IAzureBlobStoreClient.FetchBlobAndWriteToStream(string containerName, string blobName, string blobVersion, string contentHash, Stream streamToWriteTo, CancellationToken cancellationToken)
        {
            // https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad-msi
            // https://docs.microsoft.com/en-gb/dotnet/api/overview/azure/identity-readme

            if (string.IsNullOrWhiteSpace(containerName))
            {
                throw new ArgumentNullException(nameof(containerName));
            }
            if (string.IsNullOrWhiteSpace(blobName))
            {
                throw new ArgumentNullException(nameof(blobName));
            }
            if (string.IsNullOrWhiteSpace(blobVersion))
            {
                throw new ArgumentNullException(nameof(blobVersion));
            }
            if (string.IsNullOrWhiteSpace(contentHash))
            {
                throw new ArgumentNullException(nameof(contentHash));
            }

            if (streamToWriteTo is null)
            {
                throw new ArgumentNullException(nameof(streamToWriteTo));
            }

            cancellationToken.ThrowIfCancellationRequested();

            var managedIdentityCredential = new DefaultAzureCredential();

            var blobClientOptions = GetBlobClientOptions(_geoRedundantServiceUrl);

            var blobRequestConditions = new BlobRequestConditions()
            {
            };

            var blobServiceClient = new BlobServiceClient(_primaryServiceUrl, managedIdentityCredential, blobClientOptions);

            var containerClient = blobServiceClient.GetBlobContainerClient(containerName);

            var blobClient = containerClient.GetBlobClient(blobName).WithVersion(blobVersion);

            try
            {
                var result = await blobClient.DownloadStreamingAsync(conditions : blobRequestConditions, cancellationToken : cancellationToken);

                using var response = result.GetRawResponse();

                if (!IsSuccessStatusCode(response.Status))
                {
                    _logger?.LogDebug($"Unable to download file from blob storage.  {response.ClientRequestId} - Reported '{ response.ReasonPhrase }' with status code: '{ response.Status } { Enum.Parse(typeof(HttpStatusCode), Convert.ToString(response.Status, CultureInfo.InvariantCulture)) }'");

                    throw new IrretrievableFileException($"{response.ClientRequestId}: Unable to download file from storage.  Please consult log files for more information");
                }

                var details = result.Value.Details;

                // TODO - Seems odd I can't supply the expected hash (Content-MD5) in the request for blob storage to validate before
                //        starting the download (unless properties come back to us before stream is opened) so would be good to confirm
                //        things are working as we need with minimal overhead (given almost always likely to match)
                //        Need to test this works with larger files that might be chunked

                var blobContentHash = Convert.ToBase64String(details.BlobContentHash ?? details.ContentHash);

                if (0 != string.CompareOrdinal(blobContentHash, contentHash))
                {
                    throw new IrretrievableFileException($"{response.ClientRequestId}: Unable to share the file with the user as the content hash stored during upload does not match that of the downloaded file - '{blobName}' + '{blobVersion}'");
                }

                await result.Value.Content.CopyToAsync(streamToWriteTo, cancellationToken);

                return(details);
            }
            catch (AuthenticationFailedException ex)
            {
                _logger?.LogError(ex, "Unable to authenticate with the Azure Blob Storage service using the default credentials");

                throw;
            }
            catch (Azure.RequestFailedException ex)
            {
                _logger?.LogError(ex, $"Unable to access the storage endpoint as the download request failed: '{ ex.Status } { Enum.Parse(typeof(HttpStatusCode), Convert.ToString(ex.Status, CultureInfo.InvariantCulture)) }'");

                throw;
            }
        }
Пример #29
0
        async Task <Uri> IAzureBlobStoreClient.GenerateEphemeralDownloadLink(string containerName, string blobName, string blobVersion, string publicFacingBlobName, CancellationToken cancellationToken)
        {
            // We will secure the link by creating a user delegate sas token signed by the managed identity of this application, thus
            // only the intersection of allowed permissions are applicable.   In this case, we only want to assign the read
            // permission to the token, and for such access to be limited to a set period of time after which the token will expire
            //
            // If running local, note that the azure credentials resolved are those you are logged in as (for example the Visual Studio
            // azure account)

            if (string.IsNullOrWhiteSpace(containerName))
            {
                throw new ArgumentNullException(nameof(containerName));
            }
            if (string.IsNullOrWhiteSpace(blobName))
            {
                throw new ArgumentNullException(nameof(blobName));
            }
            if (string.IsNullOrWhiteSpace(blobVersion))
            {
                throw new ArgumentNullException(nameof(blobVersion));
            }
            if (string.IsNullOrWhiteSpace(publicFacingBlobName))
            {
                throw new ArgumentNullException(nameof(publicFacingBlobName));
            }

            cancellationToken.ThrowIfCancellationRequested();

            var managedIdentityCredential = new DefaultAzureCredential();

            var blobClientOptions = GetBlobClientOptions(_geoRedundantServiceUrl);

            var blobServiceClient = new BlobServiceClient(_primaryServiceUrl, managedIdentityCredential, blobClientOptions);

            var blobContainerClient = blobServiceClient.GetBlobContainerClient(containerName);

            var blobClient = blobContainerClient.GetBlobClient(blobName).WithVersion(blobVersion);

            var tokenStartsOn = _systemClock.UtcNow;

            var tokenExpiresOn = tokenStartsOn.AddMinutes(TOKEN_SAS_TIMEOUT_IN_MINUTES);

            var fileInfo = new FileInfo(publicFacingBlobName);

            var setContentDisposition = !string.IsNullOrWhiteSpace(fileInfo.Extension);

            var userDelegationKey = await _memoryCache.GetOrCreateAsync(
                $"{nameof(AzureBlobStoreClient)}:UserDelegationKey",
                async cacheEntry =>
            {
                cacheEntry.Priority = CacheItemPriority.High;
                cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1);

                try
                {
                    var azureResponse = await blobServiceClient.GetUserDelegationKeyAsync(tokenStartsOn, tokenExpiresOn, cancellationToken);

                    return(azureResponse.Value);
                }
                catch (RequestFailedException ex)
                {
                    _logger?.LogError(ex, "Unable to access the storage endpoint to generate a user delegation key: '{StatusCode} {StatusCodeName}'", ex.Status, Enum.Parse(typeof(HttpStatusCode), Convert.ToString(ex.Status, CultureInfo.InvariantCulture)));

                    throw;
                }
            });

            var readOnlyPermission = BlobSasPermissions.Read;

            var blobSasBuilder = new BlobSasBuilder(readOnlyPermission, tokenExpiresOn)
            {
                BlobContainerName  = blobContainerClient.Name,
                BlobName           = blobClient.Name,
                BlobVersionId      = blobVersion,
                Resource           = "b",
                StartsOn           = tokenStartsOn,
                ExpiresOn          = tokenExpiresOn,
                Protocol           = SasProtocol.Https,
                ContentDisposition = setContentDisposition ? $"attachment; filename*=UTF-8''{Uri.EscapeDataString(publicFacingBlobName)}" : default
                                     //PreauthorizedAgentObjectId = set this if we use AAD to authenticate our users,
            };

            var blobUriBuilder = new BlobUriBuilder(blobClient.Uri)
            {
                Sas = blobSasBuilder.ToSasQueryParameters(userDelegationKey, blobServiceClient.AccountName)
            };

            var uri = blobUriBuilder.ToUri();

            return(uri);
        }
        /// <summary>
        /// Load a certificate from Key Vault, including the private key.
        /// </summary>
        /// <param name="keyVaultUrl">URL of Key Vault.</param>
        /// <param name="certificateName">Name of the certificate.</param>
        /// <param name="x509KeyStorageFlags">Defines where and how to import the private key of an X.509 certificate.</param>
        /// <returns>An <see cref="X509Certificate2"/> certificate.</returns>
        /// <remarks>This code is inspired by Heath Stewart's code in:
        /// https://github.com/heaths/azsdk-sample-getcert/blob/master/Program.cs#L46-L82.
        /// </remarks>
        private static X509Certificate2?LoadFromKeyVault(
            string keyVaultUrl,
            string certificateName,
            X509KeyStorageFlags x509KeyStorageFlags)
        {
            Uri keyVaultUri = new Uri(keyVaultUrl);
            DefaultAzureCredentialOptions options = new DefaultAzureCredentialOptions
            {
                ManagedIdentityClientId = UserAssignedManagedIdentityClientId,
            };
            DefaultAzureCredential credential        = new DefaultAzureCredential(options);
            CertificateClient      certificateClient = new CertificateClient(keyVaultUri, credential);
            SecretClient           secretClient      = new SecretClient(keyVaultUri, credential);

            KeyVaultCertificateWithPolicy certificate = certificateClient.GetCertificate(certificateName);

            if (certificate.Properties.NotBefore == null || certificate.Properties.ExpiresOn == null)
            {
                return(null);
            }

            if (DateTimeOffset.UtcNow < certificate.Properties.NotBefore || DateTimeOffset.UtcNow > certificate.Properties.ExpiresOn)
            {
                return(null);
            }

            // Return a certificate with only the public key if the private key is not exportable.
            if (certificate.Policy?.Exportable != true)
            {
                return(new X509Certificate2(
                           certificate.Cer,
                           (string?)null,
                           x509KeyStorageFlags));
            }

            // Parse the secret ID and version to retrieve the private key.
            string[] segments = certificate.SecretId.AbsolutePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
            if (segments.Length != 3)
            {
                throw new InvalidOperationException(string.Format(
                                                        CultureInfo.InvariantCulture,
                                                        CertificateErrorMessage.IncorrectNumberOfUriSegments,
                                                        segments.Length,
                                                        certificate.SecretId));
            }

            string secretName    = segments[1];
            string secretVersion = segments[2];

            KeyVaultSecret secret = secretClient.GetSecret(secretName, secretVersion);

            // For PEM, you'll need to extract the base64-encoded message body.
            // .NET 5.0 preview introduces the System.Security.Cryptography.PemEncoding class to make this easier.
            if (CertificateConstants.MediaTypePksc12.Equals(secret.Properties.ContentType, StringComparison.OrdinalIgnoreCase))
            {
                return(LoadFromBase64Encoded(secret.Value, x509KeyStorageFlags));
            }

            throw new NotSupportedException(
                      string.Format(
                          CultureInfo.InvariantCulture,
                          CertificateErrorMessage.OnlyPkcs12IsSupported,
                          secret.Properties.ContentType));
        }