예제 #1
0
        /// <inheritdoc/>
        public async Task <ITenant> CreateWellKnownChildTenantAsync(
            string parentTenantId,
            Guid wellKnownChildTenantGuid,
            string name)
        {
            ArgumentNullException.ThrowIfNull(parentTenantId);

            try
            {
                (ITenant parentTenant, CloudBlobContainer cloudBlobContainer) = await this.GetContainerAndTenantForChildTenantsOf(parentTenantId).ConfigureAwait(false);

                // We need to copy blob storage settings for the Tenancy container definition from the parent to the new child
                // to support the tenant blob store provider. We would expect this to be overridden by clients that wanted to
                // establish their own settings.
                BlobStorageConfiguration tenancyStorageConfiguration = parentTenant.GetBlobStorageConfiguration(ContainerDefinition);
                IPropertyBag             childProperties             = this.propertyBagFactory.Create(values =>
                                                                                                      values.AddBlobStorageConfiguration(ContainerDefinition, tenancyStorageConfiguration));
                var child = new Tenant(
                    parentTenantId.CreateChildId(wellKnownChildTenantGuid),
                    name,
                    childProperties);

                // As we create the new blob, we need to ensure there isn't already a tenant with the same Id. We do this by
                // providing an If-None-Match header passing a "*", which will cause a storage exception with a 409 status
                // code if a blob with the same Id already exists.
                CloudBlockBlob blob = GetLiveTenantBlockBlobReference(child.Id, cloudBlobContainer);
                string         text = JsonConvert.SerializeObject(child, this.serializerSettings);
                await blob.UploadTextAsync(
                    text,
                    null,
                    AccessCondition.GenerateIfNoneMatchCondition("*"),
                    null,
                    null).ConfigureAwait(false);

                child.ETag = blob.Properties.ETag;

                return(child);
            }
            catch (FormatException fex)
            {
                throw new TenantNotFoundException("Unsupported tenant ID", fex);
            }
            catch (StorageException ex) when(ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound)
            {
                throw new TenantNotFoundException();
            }
            catch (StorageException ex) when(ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict)
            {
                // This exception is thrown because there's already a tenant with the same Id. This should never happen when
                // this method has been called from CreateChildTenantAsync as the Guid will have been generated and the
                // chances of it matching one previously generated are miniscule. However, it could happen when calling this
                // method directly with a wellKnownChildTenantGuid that's already in use. In this case, the fault is with
                // the client code - creating tenants with well known Ids is something one would expect to happen under
                // controlled conditions, so it's only likely that a conflict will occur when either the client code has made
                // a mistake or someone is actively trying to cause problems.
                throw new ArgumentException(
                          $"A child tenant of '{parentTenantId}' with a well known Guid of '{wellKnownChildTenantGuid}' already exists.",
                          nameof(wellKnownChildTenantGuid));
            }
        }
예제 #2
0
        private static void CommonServiceInit(
            FeatureContext featureContext,
            IServiceCollection serviceCollection)
        {
            serviceCollection.AddSingleton(Configuration);
            serviceCollection.AddSingleton(Configuration.GetSection("TestSettings").Get <TestSettings>());

            serviceCollection.AddRequiredTenancyServices();

            if (featureContext.FeatureInfo.Tags.Any(t => t == "withBlobStorageTenantProvider"))
            {
                serviceCollection.AddTenantProviderBlobStore(_ =>
                {
                    var blobStorageConfiguration = new BlobStorageConfiguration();
                    Configuration.Bind("TENANCYBLOBSTORAGECONFIGURATIONOPTIONS", blobStorageConfiguration);
                    return(blobStorageConfiguration);
                });

                // Now replace the service for ITenantStore and ITenantProvider with a decorated TenantProviderBlobStore.
                serviceCollection.AddSingleton(sp => new TenantTrackingTenantProviderDecorator(
                                                   sp.GetRequiredService <TenantProviderBlobStore>()));
                serviceCollection.Remove(serviceCollection.First(x => x.ServiceType == typeof(ITenantProvider)));
                serviceCollection.AddSingleton <ITenantProvider>(
                    sp => sp.GetRequiredService <TenantTrackingTenantProviderDecorator>());
                serviceCollection.AddSingleton <ITenantStore>(
                    sp => sp.GetRequiredService <TenantTrackingTenantProviderDecorator>());
            }
            else
            {
                serviceCollection.AddSingleton <FakeTenantProvider>();
                serviceCollection.AddSingleton <ITenantProvider>(sp => sp.GetRequiredService <FakeTenantProvider>());
            }

            serviceCollection.AddServiceIdentityAzureTokenCredentialSourceFromLegacyConnectionString(Configuration["AzureServicesAuthConnectionString"]);
        }
 public BlobStore(BlobStorageConfiguration configuration)
 {
     containerClient = new BlobContainerClient(
         configuration.ConnectionString,
         configuration.ContainerName);
     this.configuration = configuration;
 }
예제 #4
0
        /// <summary>
        /// Adds services an Azure Blob storage-based implementation of <see cref="ITenantProvider"/>.
        /// </summary>
        /// <param name="services">The service collection.</param>
        /// <param name="getRootTenantStorageConfiguration">
        /// A function that returns the <see cref="BlobStorageConfiguration"/> that will be used for the root tenant to
        /// determine where to store its children.
        /// </param>
        /// <returns>The modified service collection.</returns>
        public static IServiceCollection AddTenantProviderBlobStore(
            this IServiceCollection services,
            Func <IServiceProvider, BlobStorageConfiguration> getRootTenantStorageConfiguration)
        {
            if (services.Any(s => typeof(ITenantProvider).IsAssignableFrom(s.ServiceType)))
            {
                return(services);
            }

            services.AddRequiredTenancyServices();

            services.AddSingleton(sp =>
            {
                BlobStorageConfiguration rootTenantStorageConfig = getRootTenantStorageConfiguration(sp);

                IPropertyBagFactory propertyBagFactory = sp.GetRequiredService <IPropertyBagFactory>();
                var rootTenant = new RootTenant(propertyBagFactory);

                rootTenant.UpdateProperties(
                    values => values.AddBlobStorageConfiguration(
                        TenantProviderBlobStore.ContainerDefinition, rootTenantStorageConfig));

                ITenantCloudBlobContainerFactory tenantCloudBlobContainerFactory = sp.GetRequiredService <ITenantCloudBlobContainerFactory>();
                IJsonSerializerSettingsProvider serializerSettingsProvider       = sp.GetRequiredService <IJsonSerializerSettingsProvider>();

                return(new TenantProviderBlobStore(rootTenant, propertyBagFactory, tenantCloudBlobContainerFactory, serializerSettingsProvider));
            });

            services.AddSingleton <ITenantStore>(sp => sp.GetRequiredService <TenantProviderBlobStore>());
            services.AddSingleton <ITenantProvider>(sp => sp.GetRequiredService <TenantProviderBlobStore>());
            return(services);
        }
예제 #5
0
        public void GivenIHaveAddedBlobStorageConfigurationToTheCurrentTenant(Table table)
        {
            ITenantProvider tenantProvider = this.serviceProvider.GetRequiredService <ITenantProvider>();

            var blobStorageConfiguration = new BlobStorageConfiguration();

            TenancyContainerScenarioBindings.Configuration.Bind("TESTBLOBSTORAGECONFIGURATIONOPTIONS", blobStorageConfiguration);

            blobStorageConfiguration.DisableTenantIdPrefix = bool.Parse(table.Rows[0]["DisableTenantIdPrefix"]);
            string overriddenContainerName = table.Rows[0]["Container"];

            if (!string.IsNullOrEmpty(overriddenContainerName))
            {
                // We can run into a problem when running tests multiple times: the container
                // name ends up being the same each time, and since we delete the container at
                // the end of the test, the next execution can fail because Azure Storage doesn't
                // let you create a container with the same name as one you've just deleted. (You
                // sometimes need to wait for a few minutes.) So we use a unique name.
                overriddenContainerName += Guid.NewGuid();

                blobStorageConfiguration.Container = overriddenContainerName;
            }

            tenantProvider.Root.UpdateProperties(values =>
                                                 values.AddBlobStorageConfiguration(this.blobStorageContainerDefinition, blobStorageConfiguration));
        }
예제 #6
0
        private static EnrollmentConfigurationItem[] GetClaimsConfig(FeatureContext featureContext)
        {
            IConfiguration configuration = ContainerBindings
                                           .GetServiceProvider(featureContext)
                                           .GetRequiredService <IConfiguration>();

            // Load the config items we need:
            BlobStorageConfiguration claimPermissionsStoreStorageConfiguration =
                configuration.GetSection("TestBlobStorageConfiguration").Get <BlobStorageConfiguration>()
                ?? new BlobStorageConfiguration();

            claimPermissionsStoreStorageConfiguration.Container = "claimpermissions";

            BlobStorageConfiguration resourceAccessRuleSetsStoreStorageConfiguration =
                configuration.GetSection("TestBlobStorageConfiguration").Get <BlobStorageConfiguration>()
                ?? new BlobStorageConfiguration();

            resourceAccessRuleSetsStoreStorageConfiguration.Container = "resourceaccessrulesets";

            return(new EnrollmentConfigurationItem[]
            {
                new EnrollmentBlobStorageConfigurationItem
                {
                    Key = "claimPermissionsStore",
                    Configuration = claimPermissionsStoreStorageConfiguration,
                },
                new EnrollmentBlobStorageConfigurationItem
                {
                    Key = "resourceAccessRuleSetsStore",
                    Configuration = resourceAccessRuleSetsStoreStorageConfiguration,
                },
            });
        }
        private static EnrollmentConfigurationItem[] GetOperationsConfig(FeatureContext featureContext)
        {
            IConfiguration configuration = ContainerBindings
                                           .GetServiceProvider(featureContext)
                                           .GetRequiredService <IConfiguration>();

            // Can't create a logger using the generic type of this class because it's static, so we'll do it using
            // the feature context instead.
            ILogger <FeatureContext> logger = ContainerBindings
                                              .GetServiceProvider(featureContext)
                                              .GetRequiredService <ILogger <FeatureContext> >();

            BlobStorageConfiguration blobStorageConfiguration =
                configuration.GetSection("TestBlobStorageConfiguration").Get <BlobStorageConfiguration>()
                ?? new BlobStorageConfiguration();

            if (string.IsNullOrEmpty(blobStorageConfiguration.AccountName))
            {
                logger.LogDebug("No configuration value 'TestBlobStorageConfiguration:AccountName' provided; using local storage emulator.");
            }

            return(new EnrollmentConfigurationItem[]
            {
                new EnrollmentBlobStorageConfigurationItem
                {
                    Key = "operationsStore",
                    Configuration = blobStorageConfiguration,
                },
            });
        }
예제 #8
0
        public void ThenTheTenantedCloudBlobContainerShouldBeNamedUsingAHashOfTheTenantIdAndTheNameSpecifiedInTheBlobConfiguration()
        {
            ITenantProvider          tenantProvider           = this.serviceProvider.GetRequiredService <ITenantProvider>();
            BlobStorageConfiguration blobStorageConfiguration = tenantProvider.Root.GetBlobStorageConfiguration(this.blobStorageContainerDefinition);

            string expectedNamePlain = string.Concat(RootTenant.RootTenantId, "-", blobStorageConfiguration.Container);
            string expectedName      = AzureStorageNameHelper.HashAndEncodeBlobContainerName(expectedNamePlain);

            Assert.AreEqual(expectedName, this.Container.Name);
        }
예제 #9
0
        public void RemoteConnectionString()
        {
            const string BlobStorageAccount = "account";
            const string BlobStorageKey     = "key";
            const string EndpointSuffix     = "suffix";

            var connectionString = new BlobStorageConfiguration(BlobStorageAccount, BlobStorageKey, EndpointSuffix).ConnectionString;

            Assert.Equal("DefaultEndpointsProtocol=https;AccountName=account;AccountKey=key;EndpointSuffix=suffix", connectionString);
        }
예제 #10
0
        /// <summary>
        ///     Creates the whitelist with the given configuration.
        /// </summary>
        /// <param name="configuration">The Azure Blob Storage configuration to use.</param>
        public FaceWhitelist(BlobStorageConfiguration configuration)
        {
            whitelistedUserIds = new ConcurrentBag <string>();
            var storageAccount = CloudStorageAccount.Parse(configuration.ConnectionString);

            blobClient = storageAccount.CreateCloudBlobClient();
            const string ContainerName = "whitelist";

            container = blobClient.GetContainerReference(ContainerName);
            container.CreateIfNotExists();
        }
예제 #11
0
        public SessionRepository(BlobStorageConfiguration configuration)
        {
            var storageAccount = new CloudStorageAccount(
                new Microsoft.Azure.Storage.Auth.StorageCredentials(
                    configuration.AccountName,
                    configuration.Key), true);

            var blobClient = storageAccount.CreateCloudBlobClient();

            _container = blobClient.GetContainerReference(configuration.ContainerName);

            if (_sessions == null)
            {
                var blockBlob = _container.GetBlockBlobReference("sessions");
                _sessions = new List <Session>(JsonConvert.DeserializeObject <Session[]>(blockBlob.DownloadTextAsync().Result));
            }
        }
예제 #12
0
        public void ThenTheTenantCalledShouldContainBlobStorageConfigurationForABlobStorageContainerDefinitionWithContainerName(
            string tenantName,
            string containerName)
        {
            InMemoryTenantProvider tenantProvider =
                ContainerBindings.GetServiceProvider(this.scenarioContext).GetRequiredService <InMemoryTenantProvider>();

            ITenant tenant = tenantProvider.GetTenantByName(tenantName)
                             ?? throw new TenantNotFoundException($"Could not find tenant with name '{tenantName}'");

            var containerDefinition = new BlobStorageContainerDefinition(containerName);

            BlobStorageConfiguration tenantConfigItem = tenant.GetBlobStorageConfiguration(containerDefinition);

            // GetBlobStorageConfiguration would have thrown an exception if the config didn't exist, but we'll do a
            // not null assertion anyway...
            Assert.IsNotNull(tenantConfigItem);
        }
        private static EnrollmentConfigurationItem[] GetWorkflowConfig(FeatureContext featureContext)
        {
            IConfiguration configuration = ContainerBindings
                                           .GetServiceProvider(featureContext)
                                           .GetRequiredService <IConfiguration>();

            // Note: this next part is using configuration types from the old (v2) Corvus.Tenancy
            // libraries. Unfortunately, this is currently unavoidable because the current version
            // of Marain.TenantManagement.Abstractions defines enrollment mechanism in terms of
            // those older types.

            // Load the config items we need:
            CosmosConfiguration cosmosConfiguration =
                configuration.GetSection("TestCosmosConfiguration").Get <CosmosConfiguration>()
                ?? new CosmosConfiguration();

            cosmosConfiguration.DatabaseName = "endjinspecssharedthroughput";

            BlobStorageConfiguration storageConfiguration =
                configuration.GetSection("TestBlobStorageConfiguration").Get <BlobStorageConfiguration>()
                ?? new BlobStorageConfiguration();

            return(new EnrollmentConfigurationItem[]
            {
                new EnrollmentBlobStorageConfigurationItem
                {
                    Key = "workflowStore",
                    Configuration = storageConfiguration,
                },
                new EnrollmentCosmosConfigurationItem
                {
                    Key = "workflowInstanceStore",
                    Configuration = cosmosConfiguration,
                },
                new EnrollmentBlobStorageConfigurationItem
                {
                    Key = "operationsStore",
                    Configuration = storageConfiguration,
                },
            });
        }
예제 #14
0
 public RystemCacheServiceProvider WithBlobStorage(BlobStorageConfiguration configuration = default, string serviceKey = default)
 => (RystemCacheServiceProvider)WithIntegration(ServiceProviderType.AzureBlockBlobStorage, configuration, serviceKey);
예제 #15
0
        static IServiceContainer CompositionRoot(string slackToken, SlackUser adminUser, FaceDetectionConfiguration faceDetectionConfiguration, BlobStorageConfiguration blobStorageConfiguration)
        {
            var serviceContainer = new ServiceContainer();

            serviceContainer.RegisterInstance(slackToken);
            serviceContainer.RegisterInstance(adminUser);

            if (string.IsNullOrEmpty(faceDetectionConfiguration.Key))
            {
                serviceContainer.Register <IFaceDetectionClient, FaceServiceClientDummy>();
                serviceContainer.Register <IFaceWhitelist, FaceWhitelistDummy>();
            }
            else
            {
                serviceContainer.RegisterInstance(faceDetectionConfiguration);
                serviceContainer.RegisterInstance <IFaceServiceClient>(new FaceServiceClient(faceDetectionConfiguration.Key, faceDetectionConfiguration.URL));
                serviceContainer.Register <IFaceDetectionClient, FaceDetectionClient>();
                serviceContainer.RegisterInstance <IFaceWhitelist>(new FaceWhitelist(blobStorageConfiguration));
            }

            serviceContainer.Register <ISlackProfileValidator, SlackProfileValidator>();
            serviceContainer.Register <ISlackConnector, SlackConnector.SlackConnector>();
            serviceContainer.Register <ISlackIntegration, SlackIntegration>();
            serviceContainer.Register <ProfilebotImplmentation>();

            return(serviceContainer);
        }
예제 #16
0
        public void Start(string slackToken, SlackUser adminUser, FaceDetectionConfiguration faceDetectionConfiguration, BlobStorageConfiguration blobStorageConfiguration)
        {
            if (string.IsNullOrEmpty(slackToken))
            {
                throw new ArgumentException(nameof(slackToken));
            }

            if (string.IsNullOrEmpty(adminUser.Id))
            {
                throw new ArgumentException(nameof(adminUser.Id));
            }

            var serviceContainer = CompositionRoot(slackToken, adminUser, faceDetectionConfiguration, blobStorageConfiguration);

            profilebot = serviceContainer.GetInstance <ProfilebotImplmentation>();
            profilebot
            .Connect()
            .ContinueWith(task => {
                if (!task.IsCompleted || task.IsFaulted)
                {
                    Console.WriteLine($"Error connecting to Slack: {task.Exception}");
                }
            });
        }
예제 #17
0
 public AzureBlobService(BlobStorageConfiguration configuration)
 {
     _blobClient = new BlobServiceClient(configuration.ConnectionString);
 }
예제 #18
0
 public RystemDataServiceProvider WithAppendBlob(BlobStorageConfiguration configuration = default, string serviceKey = default)
 => (RystemDataServiceProvider)WithIntegration(ServiceProviderType.AzureAppendBlobStorage, configuration, serviceKey);