Example #1
0
        public DbSetup(
            cloudscribe.DbHelpers.SQLite.SqliteConnectionstringResolver connectionStringResolver,
            ILogger<DbSetup> logger,
            IVersionProviderFactory versionProviderFactory)
        {
            if (connectionStringResolver == null) { throw new ArgumentNullException(nameof(connectionStringResolver)); }
            if (logger == null) { throw new ArgumentNullException(nameof(logger)); }
            if (versionProviderFactory == null) { throw new ArgumentNullException(nameof(versionProviderFactory)); }

            versionProviders = versionProviderFactory;
            log = logger;
            connectionString = connectionStringResolver.Resolve();
            sqliteFilePath = connectionStringResolver.SqliteFilePath;

            // possibly will change this later to have SqliteFactory/DbProviderFactory injected
            AdoHelper = new AdoHelper(SqliteFactory.Instance);

        }
Example #2
0
        private void ConfigureLogging(
            ILoggerFactory loggerFactory, 
            IServiceProvider serviceProvider
            , cloudscribe.Logging.Web.ILogRepository logRepo
            )
        {
            
            // a customizable filter for logging
            LogLevel minimumLevel = LogLevel.Information;

            // add exclusions to remove noise in the logs
            var excludedLoggers = new List<string>
            {
                "Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware",
                "Microsoft.AspNetCore.Hosting.Internal.WebHost",
            };

            Func<string, LogLevel, bool> logFilter = (string loggerName, LogLevel logLevel) =>
            {
                if (logLevel < minimumLevel)
                {
                    return false;
                }

                if (excludedLoggers.Contains(loggerName))
                {
                    return false;
                }

                return true;
            };
            
            loggerFactory.AddDbLogger(serviceProvider, logFilter, logRepo);
        }
Example #3
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        // you can add things to this method signature and they will be injected as long as they were registered during 
        // ConfigureServices
        public void Configure(
            IApplicationBuilder app, 
            IHostingEnvironment env, 
            ILoggerFactory loggerFactory,
            IOptions<cloudscribe.Core.Models.MultiTenantOptions> multiTenantOptionsAccessor,
            IServiceProvider serviceProvider,
            IOptions<RequestLocalizationOptions> localizationOptionsAccessor
            ,cloudscribe.Logging.Web.ILogRepository logRepo
            )
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
            ConfigureLogging(loggerFactory, serviceProvider, logRepo);
            
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
                app.UseBrowserLink();
            }

            var storage = Configuration["DevOptions:DbPlatform"];
            
            switch (storage)
            {
                case "NoDb":
                    CoreNoDbStartup.InitializeDataAsync(app.ApplicationServices).Wait();

                    // you can use this hack to add clients and scopes into the db since
                    // there is currently no ui to do it
                    // you should not use this on the first run that actually creates the initial cloudscribe data
                    // you must wait until after that and then you can get the needed siteid from the database
                    // this will only run at startup time and only add data if no data exists for the given site.
                    // if you pass in an invalid siteid it will not fail, you will get data with a bad siteid
                    // make note of your siteid, don't use these, these are from my NoDb storage
                    // site1 05301194-da1d-43a8-9aa4-6c5f8959f37b
                    // site2 a9e2c249-90b4-4770-9e99-9702d89f73b6
                    // replace null with your siteid and run the app, then change it back to null since it can only be a one time task
                    string sId = null;

                    CloudscribeIdentityServerIntegrationNoDbStorage.InitializeDatabaseAsync(
                        app.ApplicationServices,
                        sId,
                        GetClients(),
                        GetScopes()
                        ).Wait();

                    break;

                case "ef":
                default:
                    // this creates ensures the database is created and initial data
                    CoreEFStartup.InitializeDatabaseAsync(app.ApplicationServices).Wait();

                    // this one is only needed if using cloudscribe Logging with EF as the logging storage
                    LoggingEFStartup.InitializeDatabaseAsync(app.ApplicationServices).Wait();

                    // you can use this hack to add clients and scopes into the db since
                    // there is currently no ui to do it
                    // you should not use this on the first run that actually creates the initial cloudscribe data
                    // you must wait until after that and then you can get the needed siteid from the database
                    // this will only run at startup time and only add data if no data exists for the given site.
                    // if you pass in an invalid siteid it will not fail, you will get data with a bad siteid
                    // make note of your siteid, don't use these, these are from my db
                    // site1 8f54733c-3f3a-4971-bb1f-8950cea42f1a
                    // site2 7c111db3-e270-497a-9a12-aed436c764c6
                    // replace null with your siteid and run the app, then change it back to null since it can only be a one time task
                    string siteId = null;

                    CloudscribeIdentityServerIntegrationEFCoreStorage.InitializeDatabaseAsync(
                        app.ApplicationServices,
                        siteId,
                        GetClients(),
                        GetScopes()
                        ).Wait();
                    
                    break;
            }

            app.UseForwardedHeaders();

            app.UseStaticFiles();
            
            app.UseSession();
            
            app.UseRequestLocalization(localizationOptionsAccessor.Value);

            app.UseMultitenancy<cloudscribe.Core.Models.SiteContext>();

            var multiTenantOptions = multiTenantOptionsAccessor.Value;

            app.UsePerTenant<cloudscribe.Core.Models.SiteContext>((ctx, builder) =>
            {
                // custom 404 and error page - this preserves the status code (ie 404)
                if(string.IsNullOrEmpty(ctx.Tenant.SiteFolderName))
                {
                    builder.UseStatusCodePagesWithReExecute("/Home/Error/{0}");
                }
                else
                {
                    builder.UseStatusCodePagesWithReExecute("/" + ctx.Tenant.SiteFolderName + "/Home/Error/{0}");
                }
                

                builder.UseCloudscribeCoreDefaultAuthentication(
                    loggerFactory,
                    multiTenantOptions,
                    ctx.Tenant);

                // to make this multi tenant for folders
                // using a fork of IdentityServer4 and hoping to get changes so we don't need a fork
                // https://github.com/IdentityServer/IdentityServer4/issues/19

                builder.UseIdentityServer();

                // this sets up the authentication for apis within this application endpoint
                // ie apis that are hosted in the same web app endpoint with the authority server
                // this is not needed here if you are only using separate api endpoints
                // it is needed in the startup of those separate endpoints
                builder.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
                {
                    Authority = "https://localhost:44399",
                    // using the site aliasid as the scope so each tenant has a different scope
                    // you can view the aliasid from site settings
                    // clients must be configured with the scope to have access to the apis for the tenant
                    ScopeName = ctx.Tenant.AliasId, 

                    RequireHttpsMetadata = true
                });


            });

            

            UseMvc(app, multiTenantOptions.Mode == cloudscribe.Core.Models.MultiTenantMode.FolderName);

            
        }
Example #4
0
        private CookieAuthenticationOptions SetupOtherCookies(
            string scheme,
            bool useRelatedSitesMode,
            cloudscribe.Core.Models.SiteSettings tenant
            )
        {
            var options = new CookieAuthenticationOptions();
            if(useRelatedSitesMode)
            {
                options.AuthenticationScheme = scheme;
                options.CookieName = scheme;
                options.CookiePath = "/";
            }
            else
            {
                options.AuthenticationScheme = $"{scheme}-{tenant.SiteFolderName}";
                options.CookieName = $"{scheme}-{tenant.SiteFolderName}";
                options.CookiePath = "/" + tenant.SiteFolderName;
            }
            
            return options;

        }
Example #5
0
        private CookieAuthenticationOptions SetupAppCookie(
            CookieAuthenticationEvents cookieEvents,
            cloudscribe.Core.Identity.SiteAuthCookieValidator siteValidator,
            string scheme, 
            bool useRelatedSitesMode,
            cloudscribe.Core.Models.SiteSettings tenant
            )
        {
            var options = new CookieAuthenticationOptions();
            if(useRelatedSitesMode)
            {
                options.AuthenticationScheme = scheme;
                options.CookieName = scheme;
                options.CookiePath = "/";
            }
            else
            {
                options.AuthenticationScheme = $"{scheme}-{tenant.SiteFolderName}";
                options.CookieName = $"{scheme}-{tenant.SiteFolderName}";
                options.CookiePath = "/" + tenant.SiteFolderName;
                cookieEvents.OnValidatePrincipal = siteValidator.ValidatePrincipal;
            }
            
            var tenantPathBase = string.IsNullOrEmpty(tenant.SiteFolderName)
                ? PathString.Empty
                : new PathString("/" + tenant.SiteFolderName);

            options.LoginPath = tenantPathBase + "/account/login";
            options.LogoutPath = tenantPathBase + "/account/logoff";
            
            options.Events = cookieEvents;

            options.AutomaticAuthenticate = true;
            options.AutomaticChallenge = true;
           

            return options;
        }