public async Task Invoke(HttpContext httpContext)
        {
            await _next.Invoke(httpContext);

            // Register the shell settings as a custom feature.
            var shellSettings = httpContext.Features.Get <ShellSettings>();

            // We only serve the next request if the tenant has been resolved.
            if (shellSettings != null)
            {
                var deferredTaskEngine = httpContext.RequestServices.GetService <IDeferredTaskEngine>();

                // Create a new scope only if there are pending tasks
                if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                {
                    // Dispose the scoped services for the current request, and create a new one
                    (httpContext.RequestServices as IDisposable).Dispose();

                    var shellContext = _orchardHost.GetOrCreateShellContext(shellSettings);

                    if (!shellContext.Released)
                    {
                        using (var scope = shellContext.EnterServiceScope())
                        {
                            var context = new DeferredTaskContext(scope.ServiceProvider);
                            await deferredTaskEngine.ExecuteTasksAsync(context);
                        }
                    }
                }
            }
        }
        public async Task Invoke(HttpContext httpContext)
        {
            // Ensure all ShellContext are loaded and available.
            _orchardHost.Initialize();

            var shellSetting = _runningShellTable.Match(httpContext);

            // Register the shell settings as a custom feature.
            httpContext.Features.Set(shellSetting);

            // We only serve the next request if the tenant has been resolved.
            if (shellSetting != null)
            {
                var shellContext = _orchardHost.GetOrCreateShellContext(shellSetting);

                var existingRequestServices = httpContext.RequestServices;
                var scope = shellContext.CreateServiceScope();

                try
                {
                    httpContext.RequestServices = scope.ServiceProvider;

                    if (!shellContext.IsActivated)
                    {
                        lock (shellContext)
                        {
                            // The tenant gets activated here
                            if (!shellContext.IsActivated)
                            {
                                var tenantEvents = scope.ServiceProvider
                                                   .GetServices <IModularTenantEvents>();

                                foreach (var tenantEvent in tenantEvents)
                                {
                                    tenantEvent.ActivatingAsync().Wait();
                                }

                                httpContext.Items["BuildPipeline"] = true;
                                shellContext.IsActivated           = true;

                                foreach (var tenantEvent in tenantEvents)
                                {
                                    tenantEvent.ActivatedAsync().Wait();
                                }
                            }
                        }
                    }

                    shellContext.RequestStarted();
                    await _next.Invoke(httpContext);
                }
                finally
                {
                    // We dispose httpContext.RequestServices and not a local reference in case another middleware changed it
                    (httpContext.RequestServices as IDisposable)?.Dispose();
                    shellContext.RequestEnded();
                    httpContext.RequestServices = existingRequestServices;
                }
            }
        }
Esempio n. 3
0
        public void Configure(string name, OpenIddictValidationOptions options)
        {
            // Ignore validation handler instances that don't correspond to the instance managed by the OpenID module.
            if (!string.Equals(name, OpenIddictValidationDefaults.AuthenticationScheme, StringComparison.Ordinal))
            {
                return;
            }

            var settings = GetValidationSettingsAsync().GetAwaiter().GetResult();

            if (settings == null)
            {
                return;
            }

            // If the tokens are issued by an authorization server located in a separate tenant,
            // resolve the isolated data protection provider associated with the specified tenant.
            if (!string.IsNullOrEmpty(settings.Tenant) &&
                !string.Equals(settings.Tenant, _shellSettings.Name, StringComparison.Ordinal))
            {
                var context = _shellHost.GetOrCreateShellContext(_shellSettingsManager.GetSettings(settings.Tenant));
                using (var scope = context.EnterServiceScope())
                {
                    // If the other tenant is released, ensure the current tenant is also restarted as it
                    // relies on a data protection provider whose lifetime is managed by the other tenant.
                    // To make sure the other tenant is not disposed before all the pending requests are
                    // processed by the current tenant, a tenant dependency is manually added.
                    context.AddDependentShell(_shellHost.GetOrCreateShellContext(_shellSettings));

                    // Note: the data protection provider is always registered as a singleton and thus will
                    // survive the current scope, which is mainly used to prevent the other tenant from being
                    // released before we have a chance to declare the current tenant as a dependent tenant.
                    options.DataProtectionProvider = scope.ServiceProvider.GetDataProtectionProvider();
                }
            }

            // Don't allow the current tenant to choose the valid audiences, as this would
            // otherwise allow it to introspect tokens meant to be used with another tenant.
            options.Audiences.Add(OpenIdConstants.Prefixes.Tenant + _shellSettings.Name);
        }
Esempio n. 4
0
        public async Task Invoke(HttpContext httpContext)
        {
            // Ensure all ShellContext are loaded and available.
            _orchardHost.Initialize();

            var shellSetting = _runningShellTable.Match(httpContext);

            // Register the shell settings as a custom feature.
            httpContext.Features.Set(shellSetting);

            // We only serve the next request if the tenant has been resolved.
            if (shellSetting != null)
            {
                var shellContext = _orchardHost.GetOrCreateShellContext(shellSetting);

                using (var scope = shellContext.CreateServiceScope())
                {
                    httpContext.RequestServices = scope.ServiceProvider;

                    if (!shellContext.IsActivated)
                    {
                        lock (shellContext)
                        {
                            // The tenant gets activated here
                            if (!shellContext.IsActivated)
                            {
                                var tenantEvents = scope.ServiceProvider
                                                   .GetServices <IModularTenantEvents>();

                                foreach (var tenantEvent in tenantEvents)
                                {
                                    tenantEvent.ActivatingAsync().Wait();
                                }

                                httpContext.Items["BuildPipeline"] = true;
                                shellContext.IsActivated           = true;

                                foreach (var tenantEvent in tenantEvents)
                                {
                                    tenantEvent.ActivatedAsync().Wait();
                                }
                            }
                        }
                    }

                    await _next.Invoke(httpContext);
                }
            }
        }
Esempio n. 5
0
        public async Task Invoke(HttpContext httpContext)
        {
            //_logger.LogInformation($"DeferredTaskMiddleware");

            await _next.Invoke(httpContext);

            //_logger.LogInformation($"httpContext.Features");
            // Register the shell settings as a custom feature.
            var shellSettings = httpContext.Features.Get <ShellSettings>();

            //_logger.LogInformation("eeewew2");

            // We only serve the next request if the tenant has been resolved.
            if (shellSettings != null)
            {
                var deferredTaskEngine = httpContext.RequestServices.GetService <IDeferredTaskEngine>();

                // Create a new scope only if there are pending tasks
                if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                {
                    // Dispose the scoped services for the current request, and create a new one
                    (httpContext.RequestServices as IDisposable).Dispose();

                    var shellContext = _OCoreHost.GetOrCreateShellContext(shellSettings);

                    if (!shellContext.Released)
                    {
                        //var scope = shellContext.CreateServiceScope();

                        //httpContext.RequestServices = scope.ServiceProvider;

                        //var context = new DeferredTaskContext(scope.ServiceProvider);
                        //await deferredTaskEngine.ExecuteTasksAsync(context);

                        //// We don't dispose the newly created request services scope as it will
                        //// be done by ModularTenantContainerMiddleware

                        using (var scope = shellContext.EnterServiceScope())
                        {
                            var context = new DeferredTaskContext(scope.ServiceProvider);
                            await deferredTaskEngine.ExecuteTasksAsync(context);
                        }
                    }
                }
            }
        }
        public async Task <IActionResult> Create(EditTenantViewModel model)
        {
            if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageTenants))
            {
                return(Unauthorized());
            }

            if (!IsDefaultShell())
            {
                return(Unauthorized());
            }

            if (ModelState.IsValid)
            {
                ValidateViewModel(model, true);
            }

            if (ModelState.IsValid)
            {
                var shellSettings = new ShellSettings
                {
                    Name             = model.Name,
                    RequestUrlPrefix = model.RequestUrlPrefix?.Trim(),
                    RequestUrlHost   = model.RequestUrlHost,
                    ConnectionString = model.ConnectionString,
                    TablePrefix      = model.TablePrefix,
                    DatabaseProvider = model.DatabaseProvider,
                    State            = TenantState.Uninitialized
                };

                _shellSettingsManager.SaveSettings(shellSettings);
                var shellContext = _orchardHost.GetOrCreateShellContext(shellSettings);

                return(RedirectToAction(nameof(Index)));
            }

            // If we got this far, something failed, redisplay form
            return(View(model));
        }
Esempio n. 7
0
        public override async Task <IDisplayResult> EditAsync(OpenIdValidationSettings settings, BuildEditorContext context)
        {
            var user = _httpContextAccessor.HttpContext?.User;

            if (user == null || !await _authorizationService.AuthorizeAsync(user, Permissions.ManageValidationSettings))
            {
                return(null);
            }

            return(Initialize <OpenIdValidationSettingsViewModel>("OpenIdValidationSettings_Edit", model =>
            {
                model.Authority = settings.Authority;
                model.Audience = settings.Audience;
                model.Tenant = settings.Tenant;

                model.AvailableTenants = (from tenant in _shellSettingsManager.LoadSettings().AsParallel()
                                          let provider = _shellHost.GetOrCreateShellContext(tenant).ServiceProvider
                                                         let descriptor = provider.GetRequiredService <ShellDescriptor>()
                                                                          where descriptor.Features.Any(feature => feature.Id == OpenIdConstants.Features.Server)
                                                                          select tenant.Name).ToList();
            }).Location("Content:2").OnGroup(SettingsGroupId));
        }
        public async Task Invoke(HttpContext httpContext)
        {
            await _next.Invoke(httpContext);

            // Register the shell settings as a custom feature.
            var shellSettings = httpContext.Features.Get <ShellSettings>();

            // We only serve the next request if the tenant has been resolved.
            if (shellSettings != null)
            {
                var shellContext = _orchardHost.GetOrCreateShellContext(shellSettings);

                using (var scope = shellContext.CreateServiceScope())
                {
                    var deferredTaskEngine = scope.ServiceProvider.GetService <IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var context = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(context);
                    }
                }
            }
        }
        private async Task ExecuteStepAsync(RecipeExecutionContext recipeStep)
        {
            var shellContext = _orchardHost.GetOrCreateShellContext(_shellSettings);

            using (var scope = shellContext.EnterServiceScope())
            {
                if (!shellContext.IsActivated)
                {
                    var tenantEvents = scope.ServiceProvider
                                       .GetServices <IModularTenantEvents>();

                    foreach (var tenantEvent in tenantEvents)
                    {
                        tenantEvent.ActivatingAsync().Wait();
                    }

                    shellContext.IsActivated = true;

                    foreach (var tenantEvent in tenantEvents)
                    {
                        tenantEvent.ActivatedAsync().Wait();
                    }
                }

                var recipeStepHandlers = scope.ServiceProvider.GetServices <IRecipeStepHandler>();
                var scriptingManager   = scope.ServiceProvider.GetRequiredService <IScriptingManager>();
                scriptingManager.GlobalMethodProviders.Add(_environmentMethodProvider);

                // Substitutes the script elements by their actual values
                EvaluateScriptNodes(recipeStep, scriptingManager);

                foreach (var recipeStepHandler in recipeStepHandlers)
                {
                    if (Logger.IsEnabled(LogLevel.Information))
                    {
                        Logger.LogInformation("Executing recipe step '{0}'.", recipeStep.Name);
                    }

                    await _recipeEventHandlers.InvokeAsync(e => e.RecipeStepExecutingAsync(recipeStep), Logger);

                    await recipeStepHandler.ExecuteAsync(recipeStep);

                    await _recipeEventHandlers.InvokeAsync(e => e.RecipeStepExecutedAsync(recipeStep), Logger);

                    if (Logger.IsEnabled(LogLevel.Information))
                    {
                        Logger.LogInformation("Finished executing recipe step '{0}'.", recipeStep.Name);
                    }
                }
            }

            // The recipe execution might have invalidated the shell by enabling new features,
            // so the deferred tasks need to run on an updated shell context if necessary.
            shellContext = _orchardHost.GetOrCreateShellContext(_shellSettings);
            using (var scope = shellContext.EnterServiceScope())
            {
                var deferredTaskEngine = scope.ServiceProvider.GetService <IDeferredTaskEngine>();

                // The recipe might have added some deferred tasks to process
                if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                {
                    var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                    await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                }
            }
        }
Esempio n. 10
0
        // NB: Async void should be avoided; it should only be used for event handlers.Timer.Elapsed is an event handler.So, it's not necessarily wrong here.
        // c.f. http://stackoverflow.com/questions/25007670/using-async-await-inside-the-timer-elapsed-event-handler-within-a-windows-servic
        private async void DoWorkAsync(object group)
        {
            // DoWork needs to be re-entrant as Timer may call the callback before the previous callback has returned.
            // So, because a task may take longer than the period itself, DoWork needs to check if it's still running.
            ShellContext shellContext = _orchardHost.GetOrCreateShellContext(_shellSettings);

            var groupName = group as string ?? "";

            foreach (var task in _tasks[groupName])
            {
                var taskName = task.GetType().FullName;

                using (var scope = shellContext.EnterServiceScope())
                {
                    try
                    {
                        if (_states[task] != BackgroundTaskState.Idle)
                        {
                            return;
                        }

                        lock (_states)
                        {
                            // Ensure Terminate() was not called before
                            if (_states[task] != BackgroundTaskState.Idle)
                            {
                                return;
                            }

                            _states[task] = BackgroundTaskState.Running;
                        }

                        if (Logger.IsEnabled(LogLevel.Information))
                        {
                            Logger.LogInformation("Start processing background task \"{0}\".", taskName);
                        }

                        await task.DoWorkAsync(scope.ServiceProvider, _applicationLifetime.ApplicationStopping);

                        if (Logger.IsEnabled(LogLevel.Information))
                        {
                            Logger.LogInformation("Finished processing background task \"{0}\".", taskName);
                        }
                    }
                    catch (Exception ex)
                    {
                        if (Logger.IsEnabled(LogLevel.Error))
                        {
                            Logger.LogError(ex, $"Error while processing background task \"{taskName}\"");
                        }
                    }
                    finally
                    {
                        lock (_states)
                        {
                            // Ensure Terminate() was not called during the task
                            if (_states[task] != BackgroundTaskState.Stopped)
                            {
                                _states[task] = BackgroundTaskState.Idle;
                            }
                        }
                    }
                }
            }
        }
        public async Task <ImmutableArray <ValidationResult> > ValidateSettingsAsync(OpenIdValidationSettings settings)
        {
            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings));
            }

            var results = ImmutableArray.CreateBuilder <ValidationResult>();

            if (!(string.IsNullOrEmpty(settings.Authority) ^ string.IsNullOrEmpty(settings.Tenant)))
            {
                results.Add(new ValidationResult(T["Either a tenant or an authority must be registered."], new[]
                {
                    nameof(settings.Authority),
                    nameof(settings.Tenant)
                }));
            }

            if (!string.IsNullOrEmpty(settings.Authority))
            {
                if (!Uri.TryCreate(settings.Authority, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
                {
                    results.Add(new ValidationResult(T["The specified authority is not valid."], new[]
                    {
                        nameof(settings.Authority)
                    }));
                }

                if (!string.IsNullOrEmpty(uri.Query) || !string.IsNullOrEmpty(uri.Fragment))
                {
                    results.Add(new ValidationResult(T["The authority cannot contain a query string or a fragment."], new[]
                    {
                        nameof(settings.Authority)
                    }));
                }
            }

            if (string.IsNullOrEmpty(settings.Authority) && !string.IsNullOrEmpty(settings.Audience))
            {
                results.Add(new ValidationResult(T["No audience can be set when using another tenant."], new[]
                {
                    nameof(settings.Audience)
                }));
            }

            if (!string.IsNullOrEmpty(settings.Authority) && string.IsNullOrEmpty(settings.Audience))
            {
                results.Add(new ValidationResult(T["An audience must be set when configuring the authority."], new[]
                {
                    nameof(settings.Audience)
                }));
            }

            if (!string.IsNullOrEmpty(settings.Audience) &&
                settings.Audience.StartsWith(OpenIdConstants.Prefixes.Tenant, StringComparison.OrdinalIgnoreCase))
            {
                results.Add(new ValidationResult(T["The audience cannot start with the special 'oct:' prefix."], new[]
                {
                    nameof(settings.Audience)
                }));
            }

            // If a tenant was specified, ensure it is valid, that the OpenID server feature
            // was enabled and that at least a scope linked with the current tenant exists.
            if (!string.IsNullOrEmpty(settings.Tenant) &&
                !string.Equals(settings.Tenant, _shellSettings.Name, StringComparison.Ordinal))
            {
                if (!_shellSettingsManager.TryGetSettings(settings.Tenant, out var tenant))
                {
                    results.Add(new ValidationResult(T["The specified tenant is not valid."]));
                }
                else
                {
                    var context = _shellHost.GetOrCreateShellContext(tenant);
                    using (var scope = context.EnterServiceScope())
                    {
                        var manager = scope.ServiceProvider.GetService <IOpenIdScopeManager>();
                        if (manager == null)
                        {
                            results.Add(new ValidationResult(T["The specified tenant is not valid."], new[]
                            {
                                nameof(settings.Tenant)
                            }));
                        }
                        else
                        {
                            var resource = OpenIdConstants.Prefixes.Tenant + _shellSettings.Name;
                            var scopes   = await manager.FindByResourceAsync(resource);

                            if (scopes.IsDefaultOrEmpty)
                            {
                                results.Add(new ValidationResult(T["No appropriate scope was found."], new[]
                                {
                                    nameof(settings.Tenant)
                                }));
                            }
                        }
                    }
                }
            }

            return(results.ToImmutable());
        }
Esempio n. 12
0
        public async Task Invoke(HttpContext httpContext)
        {
            // Ensure all ShellContext are loaded and available.
            _orchardHost.Initialize();

            var shellSettings = _runningShellTable.Match(httpContext);

            // We only serve the next request if the tenant has been resolved.
            if (shellSettings != null)
            {
                var shellContext = _orchardHost.GetOrCreateShellContext(shellSettings);

                var hasPendingTasks = false;
                using (var scope = shellContext.EnterServiceScope())
                {
                    // Register the shell context as a custom feature.
                    httpContext.Features.Set(shellContext);

                    if (!shellContext.IsActivated)
                    {
                        var semaphore = _semaphores.GetOrAdd(shellSettings.Name, (name) => new SemaphoreSlim(1));

                        await semaphore.WaitAsync();

                        try
                        {
                            // The tenant gets activated here
                            if (!shellContext.IsActivated)
                            {
                                using (var activatingScope = shellContext.EnterServiceScope())
                                {
                                    var tenantEvents = activatingScope.ServiceProvider.GetServices <IModularTenantEvents>();

                                    foreach (var tenantEvent in tenantEvents)
                                    {
                                        await tenantEvent.ActivatingAsync();
                                    }

                                    httpContext.Items["BuildPipeline"] = true;

                                    foreach (var tenantEvent in tenantEvents.Reverse())
                                    {
                                        await tenantEvent.ActivatedAsync();
                                    }
                                }

                                shellContext.IsActivated = true;
                            }
                        }
                        finally
                        {
                            semaphore.Release();
                            _semaphores.TryRemove(shellSettings.Name, out semaphore);
                        }
                    }

                    await _next.Invoke(httpContext);

                    var deferredTaskEngine = scope.ServiceProvider.GetService <IDeferredTaskEngine>();
                    hasPendingTasks = deferredTaskEngine?.HasPendingTasks ?? false;
                }

                // Create a new scope only if there are pending tasks
                if (hasPendingTasks)
                {
                    shellContext = _orchardHost.GetOrCreateShellContext(shellSettings);

                    using (var scope = shellContext.EnterServiceScope())
                    {
                        var deferredTaskEngine = scope.ServiceProvider.GetService <IDeferredTaskEngine>();
                        var context            = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(context);
                    }
                }
            }
        }
Esempio n. 13
0
        public async Task ProcessContentItemsAsync()
        {
            // TODO: Lock over the filesystem in case two instances get a command to rebuild the index concurrently.

            var allIndices = new Dictionary <string, int>();

            // Find the lowest task id to process
            int lastTaskId = int.MaxValue;

            foreach (var indexName in _indexManager.List())
            {
                var taskId = _indexingState.GetLastTaskId(indexName);
                lastTaskId = Math.Min(lastTaskId, taskId);
                allIndices.Add(indexName, taskId);
            }

            if (!allIndices.Any())
            {
                return;
            }

            IndexingTask[] batch;

            var shellContext = _shellHost.GetOrCreateShellContext(_shellSettings);

            do
            {
                // Create a scope for the content manager
                using (var scope = shellContext.EnterServiceScope())
                {
                    // Load the next batch of tasks
                    batch = (await _indexingTaskManager.GetIndexingTasksAsync(lastTaskId, BatchSize)).ToArray();

                    if (!batch.Any())
                    {
                        break;
                    }

                    foreach (var task in batch)
                    {
                        var contentManager = scope.ServiceProvider.GetRequiredService <IContentManager>();
                        var indexHandlers  = scope.ServiceProvider.GetServices <IContentItemIndexHandler>();

                        foreach (var index in allIndices)
                        {
                            // TODO: ignore if this index is not configured for the content type

                            if (index.Value < task.Id)
                            {
                                _indexManager.DeleteDocuments(index.Key, new string[] { task.ContentItemId });
                            }
                        }

                        if (task.Type == IndexingTaskTypes.Update)
                        {
                            var contentItem = await contentManager.GetAsync(task.ContentItemId);

                            var context = new BuildIndexContext(new DocumentIndex(task.ContentItemId), contentItem, contentItem.ContentType);

                            // Update the document from the index if its lastIndexId is smaller than the current task id.
                            await indexHandlers.InvokeAsync(x => x.BuildIndexAsync(context), Logger);

                            foreach (var index in allIndices)
                            {
                                if (index.Value < task.Id)
                                {
                                    _indexManager.StoreDocuments(index.Key, new DocumentIndex[] { context.DocumentIndex });
                                }
                            }
                        }
                    }


                    // Update task ids
                    lastTaskId = batch.Last().Id;

                    foreach (var index in allIndices)
                    {
                        if (index.Value < lastTaskId)
                        {
                            _indexingState.SetLastTaskId(index.Key, lastTaskId);
                        }
                    }

                    _indexingState.Update();
                }
            } while (batch.Length == BatchSize);
        }