diff --git a/GanjooRazor/GanjooRazor.csproj b/GanjooRazor/GanjooRazor.csproj index ea3dca9f..52211c15 100644 --- a/GanjooRazor/GanjooRazor.csproj +++ b/GanjooRazor/GanjooRazor.csproj @@ -4,16 +4,6 @@ net5.0-windows - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - diff --git a/GanjooRazor/Pages/Index.cshtml.cs b/GanjooRazor/Pages/Index.cshtml.cs index b857a99a..c0efadcc 100644 --- a/GanjooRazor/Pages/Index.cshtml.cs +++ b/GanjooRazor/Pages/Index.cshtml.cs @@ -479,7 +479,7 @@ namespace GanjooRazor.Pages if(!_memoryCache.TryGetValue(cacheKey, out List poets)) { var resPoets = await _ganjoorService.GetPoets(true, false); - if(!string.IsNullOrEmpty(resPoets.ExceptionString)) + if(string.IsNullOrEmpty(resPoets.ExceptionString)) { poets = new List(resPoets.Result); _memoryCache.Set(cacheKey, poets); @@ -518,7 +518,7 @@ namespace GanjooRazor.Pages if (!IsHomePage) { var pageRes = await _ganjoorService.GetPageByUrl(Request.Path, true); - if(!string.IsNullOrEmpty(pageRes.ExceptionString)) + if(string.IsNullOrEmpty(pageRes.ExceptionString)) { if(pageRes.Result == null) { diff --git a/GanjooRazor/Startup.cs b/GanjooRazor/Startup.cs index 537a77d1..2463187e 100644 --- a/GanjooRazor/Startup.cs +++ b/GanjooRazor/Startup.cs @@ -1,9 +1,30 @@ +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using RMuseum.DbContext; +using RMuseum.Models.Auth.Memory; +using RMuseum.Services; +using RMuseum.Services.Implementation; +using RMuseum.Services.Implementationa; +using RSecurityBackend.Authorization; +using RSecurityBackend.DbContext; +using RSecurityBackend.Models.Auth.Db; +using RSecurityBackend.Models.Auth.Memory; +using RSecurityBackend.Models.Mail; +using RSecurityBackend.Services; +using RSecurityBackend.Services.Implementation; +using RSecurityBackend.Utilities; +using System; +using System.Text; using System.Text.Encodings.Web; using System.Text.Unicode; +using System.Threading.Tasks; namespace GanjooRazor { @@ -18,6 +39,9 @@ namespace GanjooRazor public void ConfigureServices(IServiceCollection services) { + services.AddHttpClient(); + + services.AddSingleton( HtmlEncoder.Create(allowedRanges: new[] { UnicodeRanges.BasicLatin, UnicodeRanges.Arabic })); @@ -26,6 +50,159 @@ namespace GanjooRazor { options.Conventions.AddPageRoute("/index", "{*url}"); }); + + services.AddDbContext(); + + Audit.Core.Configuration.JsonSettings.ContractResolver = AuditNetEnvironmentSkippingContractResolver.Instance; + Audit.Core.Configuration.DataProvider = new RAuditDataProvider(Configuration.GetConnectionString("DefaultConnection")); + + services.AddIdentityCore( + options => + { + // Password settings. + options.Password.RequireDigit = true; + options.Password.RequireLowercase = true; + options.Password.RequireNonAlphanumeric = false; + options.Password.RequireUppercase = false; + options.Password.RequiredLength = 6; + options.Password.RequiredUniqueChars = 1; + + // Lockout settings. + options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); + options.Lockout.MaxFailedAccessAttempts = 5; + options.Lockout.AllowedForNewUsers = true; + + // User settings. + options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+"; + options.User.RequireUniqueEmail = false; + } + ).AddErrorDescriber(); + + + new IdentityBuilder(typeof(RAppUser), typeof(RAppRole), services) + .AddRoleManager>() + .AddSignInManager>() + .AddEntityFrameworkStores() + .AddErrorDescriber(); + + services.AddAuthentication(options => + { + options.DefaultScheme = "bearer"; + }).AddJwtBearer("bearer", options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateAudience = false, + ValidAudience = "Everyone", + ValidateIssuer = true, + ValidIssuer = "Ganjoor", + + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes($"{Configuration.GetSection("Security")["Secret"]}")), + + ValidateLifetime = true, //validate the expiration and not before values in the token + + ClockSkew = TimeSpan.Zero + }; + + options.Events = new JwtBearerEvents + { + OnAuthenticationFailed = context => + { + if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) + { + context.Response.Headers.Add("Token-Expired", "true"); + } + return Task.CompletedTask; + } + }; + + }); + + services.AddAuthorization(options => + { + //this is the default policy to make sure the use session has not yet been deleted by him/her from another client + //or by an admin (Authorize with no policy should fail on deleted sessions) + var defPolicy = new AuthorizationPolicyBuilder(); + defPolicy.Requirements.Add(new UserGroupPermissionRequirement("null", "null")); + options.DefaultPolicy = defPolicy.Build(); + + + foreach (SecurableItem Item in RMuseumSecurableItem.Items) + { + foreach (SecurableItemOperation Operation in Item.Operations) + { + options.AddPolicy($"{Item.ShortName}:{Operation.ShortName}", policy => policy.Requirements.Add(new UserGroupPermissionRequirement(Item.ShortName, Operation.ShortName))); + } + } + }); + + services.AddMemoryCache(); + + + + //security context maps to main db context + services.AddTransient, RMuseumDbContext>(); + + //captcha service + services.AddTransient(); + + + //generic image file service + services.AddTransient(); + + //app user services + services.AddTransient(); + + //user groups services + services.AddTransient(); + + //audit service + services.AddTransient(); + + //user permission checker + services.AddTransient(); + + //secret generator + services.AddTransient(); + + // email service + services.AddTransient(); + services.Configure(Configuration); + + //picture file service + services.AddTransient(); + + //messaging service + services.AddTransient(); + + //artifact service + services.AddTransient(); + + //audio service + services.AddTransient(); + + //ganjoor service + services.AddTransient(); + + //music catalogue service + services.AddTransient(); + + //long running job service + services.AddTransient(); + + //upload limit for IIS + services.Configure(options => + { + options.MaxRequestBodySize = int.Parse(Configuration.GetSection("IIS")["UploadLimit"]); + }); + + + services.AddHostedService(); + services.AddSingleton(); + + + } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -39,6 +216,8 @@ namespace GanjooRazor app.UseRouting(); + app.UseAuthentication(); + app.UseAuthorization(); app.UseEndpoints(endpoints => diff --git a/GanjooRazor/appsettings.json b/GanjooRazor/appsettings.json index 78465e88..3b0efb71 100644 --- a/GanjooRazor/appsettings.json +++ b/GanjooRazor/appsettings.json @@ -7,6 +7,9 @@ } }, "AllowedHosts": "*", + "GoogleAnalyticsCode": "", + "APIRoot": "https://ganjgah.ir", + "GlobalAPIRoot": "https://ganjgah.ir", "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=museum;Trusted_Connection=True;MultipleActiveResultSets=true" },