Ejemplo n.º 1
0
        public async Task ConfigureSecretStore_WithDuplicateNames_MakesSubsetOfDuplicateSecretProviderNames()
        {
            // Arrange
            var    name = $"duplicate-name-{Guid.NewGuid()}";
            string secretName1 = "MySecret-1", secretName2 = "My-Secret2", secretName3 = "My-Secret3", secretName4 = $"My-Secret4";
            string secretValue1 = $"secret-{Guid.NewGuid()}",
                   secretValue2 = $"secret-{Guid.NewGuid()}",
                   secretValue3 = $"secret-{Guid.NewGuid()}",
                   secretValue4 = $"secret-{Guid.NewGuid()}";
            var builder         = new HostBuilder();

            // Act
            builder.ConfigureSecretStore((config, stores) =>
            {
                stores.AddProvider(new InMemorySecretProvider((secretName1, secretValue1)), options => options.Name = name)
                .AddProvider(new InMemorySecretProvider((secretName3, secretValue3)), options => options.Name       = "some other name")
                .AddProvider(new InMemoryCachedSecretProvider((secretName2, secretValue2)), options => options.Name = name)
                .AddProvider(new InMemorySecretProvider((secretName4, secretValue4)));
            });

            // Assert
            using (IHost host = builder.Build())
            {
                var             store    = host.Services.GetRequiredService <ISecretStore>();
                ISecretProvider provider = store.GetProvider(name);
                Assert.IsNotType <InMemoryCachedSecretProvider>(provider);
                Assert.Equal(secretValue1, await provider.GetRawSecretAsync(secretName1));
                Assert.Equal(secretValue2, await provider.GetRawSecretAsync(secretName2));
                await Assert.ThrowsAsync <SecretNotFoundException>(() => provider.GetRawSecretAsync(secretName3));

                await Assert.ThrowsAsync <SecretNotFoundException>(() => provider.GetRawSecretAsync(secretName4));
            }
        }
Ejemplo n.º 2
0
        private async Task <string> GetAuthorizationSecretAsync(AuthorizationFilterContext context)
        {
            ISecretProvider userDefinedSecretProvider =
                context.HttpContext.RequestServices.GetService <ICachedSecretProvider>()
                ?? context.HttpContext.RequestServices.GetService <ISecretProvider>();

            if (userDefinedSecretProvider is null)
            {
                throw new KeyNotFoundException(
                          $"No configured {nameof(ICachedSecretProvider)} or {nameof(ISecretProvider)} implementation found in the request service container. "
                          + "Please configure such an implementation (ex. in the Startup) of your application");
            }

            Task <string> rawSecretAsync = userDefinedSecretProvider.GetRawSecretAsync(_secretName);

            if (rawSecretAsync is null)
            {
                throw new InvalidOperationException(
                          $"Configured {nameof(ISecretProvider)} is not implemented correctly as it returns 'null' for a {nameof(Task)} value when calling {nameof(ISecretProvider.GetRawSecretAsync)}");
            }

            string foundSecret = await rawSecretAsync;

            if (foundSecret is null)
            {
                throw new SecretNotFoundException(_secretName);
            }

            return(foundSecret);
        }
        /// <summary>
        /// Authenticates with to the previously specified Azure Service Bus resource.
        /// </summary>
        /// <returns>
        ///     An <see cref="IServiceBusManagementClient"/> instance that manages the previously specified Azure Service Bus resource.
        /// </returns>
        /// <exception cref="AuthenticationException">Thrown when the previously configured <see cref="ISecretProvider"/> isn't returning the client secret.</exception>
        public async Task <IServiceBusManagementClient> AuthenticateAsync()
        {
            Task <string> rawSecretAsync = _secretProvider.GetRawSecretAsync(_clientSecretKey);

            if (rawSecretAsync is null)
            {
                throw new AuthenticationException(
                          $"Could not authenticate with the Azure Service Bus because the '{nameof(ISecretProvider)}' that should have returned the client secret, returned 'null'");
            }

            string clientSecret = await rawSecretAsync;

            var context                 = new AuthenticationContext($"https://login.microsoftonline.com/{_tenantId}");
            var clientCredentials       = new ClientCredential(_clientId, clientSecret);
            AuthenticationResult result =
                await context.AcquireTokenAsync(
                    "https://management.azure.com/",
                    clientCredentials);

            var tokenCredentials = new TokenCredentials(result.AccessToken);
            var client           = new ServiceBusManagementClient(tokenCredentials)
            {
                SubscriptionId = _subscriptionId
            };

            return(client);
        }
Ejemplo n.º 4
0
        public async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest request,
            ILogger log)
        {
            string secretValue = await _secretProvider.GetRawSecretAsync("ArcusTestSecret");

            return(new OkObjectResult(secretValue));
        }
Ejemplo n.º 5
0
        private async Task <CloudStorageAccount> GetAccount()
        {
            if (_storageAccount == null)
            {
                var storageConnectionString = await _secretProvider.GetRawSecretAsync("HTC-Storage-Connectionstring");

                _storageAccount = CloudStorageAccount.Parse(storageConnectionString);
            }

            return(_storageAccount);
        }
        /// <summary>
        /// Retrieves the secret value, based on the given name
        /// </summary>
        /// <param name="secretName">The name of the secret key</param>
        /// <returns>Returns the secret key.</returns>
        /// <exception cref="ArgumentException">The <paramref name="secretName"/> must not be empty</exception>
        /// <exception cref="ArgumentNullException">The <paramref name="secretName"/> must not be null</exception>
        /// <exception cref="SecretNotFoundException">The secret was not found, using the given name</exception>
        public async Task <string> GetRawSecretAsync(string secretName)
        {
            Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name when mutating secret names");

            string secretValue = await SafeguardMutateSecretAsync(secretName, mutatedSecretName =>
            {
                return(_implementation.GetRawSecretAsync(mutatedSecretName));
            });

            return(secretValue);
        }
        private async Task <BlobServiceClient> GetStorageClient()
        {
            if (_blobServiceClient == null)
            {
                var storageConnectionString = await _secretProvider.GetRawSecretAsync("HTC-Storage-Connectionstring");

                _blobServiceClient = new BlobServiceClient(storageConnectionString);
            }

            return(_blobServiceClient);
        }
        public async Task <IEnumerable <WeatherForecast> > Get()
        {
            string secret = await _secretProvider.GetRawSecretAsync("Weather-API-Key");

            var rng = new Random();

            return(Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
                   .ToArray());
        }
        /// <summary>
        /// Uses an access token to authenticate with Azure.
        /// </summary>
        /// <param name="subscriptionId">The ID that identifies the subscription on Azure.</param>
        /// <param name="accessTokenSecretName">The secret key to use to fetch access token from the secret provider. This will be used to call the Azure management API.</param>
        /// <param name="secretProvider">The provider to get the client secret; using the <paramref name="accessTokenSecretName"/>.</param>
        /// <exception cref="ArgumentException">Thrown when the <paramref name="subscriptionId"/> or <paramref name="accessTokenSecretName"/> is blank.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="secretProvider"/> is blank.</exception>
        public static LogicAppAuthentication UsingAccessToken(string subscriptionId, string accessTokenSecretName, ISecretProvider secretProvider)
        {
            Guard.NotNullOrWhitespace(subscriptionId, nameof(subscriptionId), "Requires an ID that identifies the Azure subscription that has access to the Azure resources");
            Guard.NotNullOrWhitespace(accessTokenSecretName, nameof(accessTokenSecretName), "Requires an access token secret key that points to the access token of the client or application that is authorized to interact with the Logic Apps running on Azure");
            Guard.NotNull(secretProvider, nameof(secretProvider), "Requires an secret provider instance to retrieve the access token of the client or application that is authorized to interact with the Logic Apps running on Azure");

            return(new LogicAppAuthentication(async() =>
            {
                string accessToken = await secretProvider.GetRawSecretAsync(accessTokenSecretName);
                LogicManagementClient managementClient = AuthenticateLogicAppsManagement(subscriptionId, accessToken);

                return managementClient;
            }));
        }
        /// <summary>
        /// Attempts to find a value with the given key, returns true if one is found, false otherwise.
        /// </summary>
        /// <param name="key">The key to lookup.</param>
        /// <param name="value">The value found at key if one is found.</param>
        /// <returns>True if key has a value, false otherwise.</returns>
        public override bool TryGet(string key, out string value)
        {
            Task <string> getSecretValueAsync = _secretProvider.GetRawSecretAsync(key);

            if (getSecretValueAsync != null)
            {
                string secretValue = getSecretValueAsync.ConfigureAwait(false).GetAwaiter().GetResult();

                value = secretValue;
                return(secretValue != null);
            }

            value = null;
            return(false);
        }
        public async Task Run([TimerTrigger("0 */1 * * * *")] TimerInfo timer, ILogger logger)
        {
            logger.LogInformation($"C# Timer trigger function executed at: {DateTime.UtcNow}");

            var    metricName  = _configuration.GetValue <string>("Arcus:ApplicationInsights:MetricName");
            var    baseUrl     = _configuration.GetValue <string>("Arcus:Databricks:Url");
            string secretToken = await _secretProvider.GetRawSecretAsync("Arcus.Databricks.SecretToken");

            var startOfWindow = timer.ScheduleStatus.Last;
            var endOfWindow   = timer.ScheduleStatus.Next;

            using var client = DatabricksClient.CreateClient(baseUrl, secretToken);
            using (var provider = new DatabricksInfoProvider(client, logger))
            {
                await provider.MeasureJobOutcomesAsync(metricName, startOfWindow, endOfWindow);
            }
        }
        /// <summary>
        /// Uses the service principal to authenticate with Azure.
        /// </summary>
        /// <param name="tenantId">The ID where the resources are located on Azure.</param>
        /// <param name="subscriptionId">The ID that identifies the subscription on Azure.</param>
        /// <param name="clientId">The ID of the client or application that has access to the logic apps running on Azure.</param>
        /// <param name="clientSecretName">The secret of the client or application that has access to the logic apps running on Azure.</param>
        /// <param name="secretProvider">The provider to get the client secret; using the <paramref name="clientSecretName"/>.</param>
        /// <param name="cloud">The Azure cloud environment to use during authenticating and interacting with the Azure Logic Apps resources.</param>
        /// <exception cref="ArgumentException">Thrown when the <paramref name="tenantId"/>, <paramref name="subscriptionId"/>, <paramref name="clientId"/>, or <paramref name="clientSecretName"/> is blank.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="secretProvider"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Thrown when the <paramref name="cloud"/> is outside the bounds of the enumeration.</exception>
        public static LogicAppAuthentication UsingServicePrincipal(string tenantId, string subscriptionId, string clientId, string clientSecretName, ISecretProvider secretProvider, AzureCloud cloud = AzureCloud.Global)
        {
            Guard.NotNullOrWhitespace(tenantId, nameof(tenantId), "Requires an tenant ID where the Azure resources are located");
            Guard.NotNullOrWhitespace(subscriptionId, nameof(subscriptionId), "Requires an ID that identifies the Azure subscription that has access to the Azure resources");
            Guard.NotNullOrWhitespace(clientId, nameof(clientId), "Requires an client or application ID that is authorized to interact with the Logic Apps running on Azure");
            Guard.NotNullOrWhitespace(clientSecretName, nameof(clientSecretName), "Requires an client or application secret key that points to the secret of the client or application that is authorized to interact with the Logic Apps running on Azure");
            Guard.NotNull(secretProvider, nameof(secretProvider), "Requires an secret provider instance to retrieve the secret of the client or application that is authorized to interact with the Logic Apps running on Azure");
            Guard.For(() => !Enum.IsDefined(typeof(AzureCloud), cloud),
                      new ArgumentOutOfRangeException(nameof(cloud), cloud, "Requires the Azure cloud environment to be within the bounds of the enumeration"));

            return(new LogicAppAuthentication(async() =>
            {
                string clientSecret = await secretProvider.GetRawSecretAsync(clientSecretName);
                LogicManagementClient managementClient = await AuthenticateLogicAppsManagementAsync(subscriptionId, tenantId, clientId, clientSecret, cloud);

                return managementClient;
            }));
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Gets the expected value in a <see cref="X509Certificate2"/> for an <paramref name="configurationKey"/> using the specified <paramref name="services"/>.
        /// </summary>
        /// <param name="configurationKey">The configured key for which the expected certificate value is registered.</param>
        /// <param name="services">The services collections of the HTTP request pipeline to retrieve registered instances.</param>
        public async Task <string> GetExpectedCertificateValueForConfiguredKeyAsync(string configurationKey, IServiceProvider services)
        {
            Guard.NotNullOrWhitespace(configurationKey, nameof(configurationKey), "Configured key cannot be blank");
            Guard.NotNull(services, nameof(services), "Registered services cannot be 'null'");

            ISecretProvider userDefinedSecretProvider =
                services.GetService <ICachedSecretProvider>()
                ?? services.GetService <ISecretProvider>();

            if (userDefinedSecretProvider == null)
            {
                throw new KeyNotFoundException(
                          $"No configured {nameof(ICachedSecretProvider)} or {nameof(ISecretProvider)} implementation found in the request service container. "
                          + "Please configure such an implementation (ex. in the Startup) of your application");
            }

            Task <string> getValueAsync = userDefinedSecretProvider.GetRawSecretAsync(configurationKey);

            return(getValueAsync == null ? null : await getValueAsync);
        }
        private async Task <string> GetAuthorizationSecretAsync(AuthorizationFilterContext context)
        {
            ISecretProvider userDefinedSecretProvider =
                context.HttpContext.RequestServices.GetService <ICachedSecretProvider>()
                ?? context.HttpContext.RequestServices.GetService <ISecretProvider>();

            if (userDefinedSecretProvider == null)
            {
                throw new KeyNotFoundException(
                          $"No configured {nameof(ICachedSecretProvider)} or {nameof(ISecretProvider)} implementation found in the request service container. "
                          + "Please configure such an implementation (ex. in the Startup) of your application");
            }

            string foundSecret = await userDefinedSecretProvider.GetRawSecretAsync(_secretName);

            if (foundSecret == null)
            {
                throw new SecretNotFoundException(_secretName);
            }

            return(foundSecret);
        }
Ejemplo n.º 15
0
        private async Task <DeviceClient> CreateIoTHubDeviceClient()
        {
            var connectionString = await _secretProvider.GetRawSecretAsync($"IOTHUB_CONNECTIONSTRING_DEVICE_{DeviceId}");

            return(DeviceClient.CreateFromConnectionString(connectionString, TransportType.Amqp));
        }
 /// <summary>
 /// Retrieves the secret value, based on the given name.
 /// </summary>
 /// <param name="secretName">The name of the secret key</param>
 /// <returns>Returns the secret key.</returns>
 /// <exception cref="T:System.ArgumentException">The <paramref name="secretName" /> must not be empty</exception>
 /// <exception cref="T:System.ArgumentNullException">The <paramref name="secretName" /> must not be null</exception>
 /// <exception cref="T:Arcus.Security.Core.SecretNotFoundException">The secret was not found, using the given name</exception>
 public async Task <string> GetRawSecretAsync(string secretName)
 {
     Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to access the secret");
     return(await WhenAuthorized(() => _secretProvider.GetRawSecretAsync(secretName)));
 }
Ejemplo n.º 17
0
        private static void ConfigureServices(WebApplicationBuilder builder, IConfiguration configuration)
        {
#if CertificateAuth
            var certificateAuthenticationConfig =
                new CertificateAuthenticationConfigBuilder()
                .WithSubject(X509ValidationLocation.Configuration, "CertificateSubject")
                .Build();

            builder.Services.AddScoped(serviceProvider => new CertificateAuthenticationValidator(certificateAuthenticationConfig));
#endif
            builder.Services.AddRouting(options =>
            {
                options.LowercaseUrls         = true;
                options.LowercaseQueryStrings = true;
            });
            builder.Services.AddControllers(options =>
            {
                options.ReturnHttpNotAcceptable    = true;
                options.RespectBrowserAcceptHeader = true;

                RestrictToJsonContentType(options);
                ConfigureJsonFormatters(options);

#if SharedAccessKeyAuth
#warning Please provide a valid request header name and secret name to the shared access filter
                options.Filters.Add(new SharedAccessKeyAuthenticationFilter(headerName: SharedAccessKeyHeaderName, queryParameterName: null, secretName: "<your-secret-name>"));
#endif
#if CertificateAuth
                options.Filters.Add(new CertificateAuthenticationFilter());
#endif
#if JwtAuth
                AuthorizationPolicy policy =
                    new AuthorizationPolicyBuilder()
                    .RequireRole("Admin")
                    .RequireAuthenticatedUser()
                    .Build();

                options.Filters.Add(new AuthorizeFilter(policy));
#endif
            });
#if JwtAuth
#error Use previously registered secret provider, for example Azure Key Vault: https://security.arcus-azure.net/features/secrets/consume-from-key-vault
            ISecretProvider secretProvider = null;
            builder.Services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                string key = secretProvider.GetRawSecretAsync("JwtSigningKey").GetAwaiter().GetResult();

                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey         = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)),
                    ValidateIssuer           = true,
                    ValidIssuer      = configuration.GetValue <string>("Jwt:Issuer"),
                    ValidateAudience = true,
                    ValidAudience    = configuration.GetValue <string>("Jwt:Audience")
                };
            });
#endif
            builder.Services.AddHealthChecks();
#if (ExcludeCorrelation == false)
            builder.Services.AddHttpCorrelation();
#endif
#if (ExcludeOpenApi == false)
            #warning Be careful of exposing sensitive information with the OpenAPI document, only expose what's necessary and hide everything else.

            var openApiInformation = new OpenApiInfo
            {
                Title   = "Arcus.Templates.WebApi",
                Version = "v1"
            };

            builder.Services.AddSwaggerGen(swaggerGenerationOptions =>
            {
                swaggerGenerationOptions.SwaggerDoc("v1", openApiInformation);
                swaggerGenerationOptions.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Arcus.Templates.WebApi.Open-Api.xml"));

                swaggerGenerationOptions.ExampleFilters();
#if (ExcludeCorrelation == false)
                swaggerGenerationOptions.OperationFilter <AddHeaderOperationFilter>("X-Transaction-Id", "Transaction ID is used to correlate multiple operation calls. A new transaction ID will be generated if not specified.", false);
                swaggerGenerationOptions.OperationFilter <AddResponseHeadersFilter>();
#endif
#if SharedAccessKeyAuth
                swaggerGenerationOptions.AddSecurityDefinition("shared-access-key", new OpenApiSecurityScheme
                {
                    Type        = SecuritySchemeType.ApiKey,
                    In          = ParameterLocation.Header,
                    Name        = SharedAccessKeyHeaderName,
                    Description = "Authentication scheme based on shared access key"
                });
                swaggerGenerationOptions.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Description = "Globally authentication scheme based on shared access key",
                            Reference   = new OpenApiReference
                            {
                                Id   = "shared-access-key",
                                Type = ReferenceType.SecurityScheme
                            }
                        }, new List <string>()
                    }
                });
#endif
#if CertificateAuth
                swaggerGenerationOptions.AddSecurityDefinition("certificate", new OpenApiSecurityScheme
                {
                    Type        = SecuritySchemeType.ApiKey,
                    In          = ParameterLocation.Header,
                    Name        = "X-ARR-ClientCert",
                    Description = "Authentication scheme based on client certificate"
                });
                swaggerGenerationOptions.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Description = "Globally authentication scheme based on client certificate",
                            Reference   = new OpenApiReference
                            {
                                Id   = "certificate",
                                Type = ReferenceType.SecurityScheme
                            }
                        }, new List <string>()
                    }
                });
#endif
#if JwtAuth
                swaggerGenerationOptions.AddSecurityDefinition("jwt", new OpenApiSecurityScheme
                {
                    Type        = SecuritySchemeType.Http,
                    Description = "Authentication scheme based on JWT"
                });
                swaggerGenerationOptions.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Description = "Globally authentication scheme based on JWT",
                            Reference   = new OpenApiReference
                            {
                                Id   = "jwt",
                                Type = ReferenceType.SecurityScheme
                            }
                        }, new List <string>()
                    }
                });
#endif
            });

            builder.Services.AddSwaggerExamplesFromAssemblyOf <HealthReportResponseExampleProvider>();
#endif
        }