The next generation of the Teknik Services. Written in ASP.NET. https://www.teknik.io/
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

Startup.cs 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using Microsoft.AspNetCore.Builder;
  6. using Microsoft.AspNetCore.Identity;
  7. using Microsoft.AspNetCore.Hosting;
  8. using Microsoft.AspNetCore.Http;
  9. using Microsoft.AspNetCore.HttpsPolicy;
  10. using Microsoft.AspNetCore.Mvc;
  11. using Microsoft.EntityFrameworkCore;
  12. using Teknik.Data;
  13. using Teknik.Utilities;
  14. using Microsoft.Extensions.Configuration;
  15. using Microsoft.Extensions.DependencyInjection;
  16. using Teknik.Logging;
  17. using System.IO;
  18. using Microsoft.Extensions.Logging;
  19. using Teknik.Configuration;
  20. using Teknik.Middleware;
  21. using Microsoft.AspNetCore.ResponseCompression;
  22. using System.IO.Compression;
  23. using System.Text;
  24. using Microsoft.AspNetCore.Authentication.Cookies;
  25. using IdentityServer4.Models;
  26. using Microsoft.AspNetCore.Authentication.OpenIdConnect;
  27. using Teknik.Attributes;
  28. using Teknik.Filters;
  29. using Microsoft.Net.Http.Headers;
  30. using Teknik.Areas.Users.Models;
  31. using Microsoft.AspNetCore.Mvc.Infrastructure;
  32. using Microsoft.AspNetCore.Mvc.Routing;
  33. using Microsoft.AspNetCore.Http.Features;
  34. using Microsoft.IdentityModel.Tokens;
  35. using Microsoft.AspNetCore.Authentication;
  36. using IdentityModel;
  37. using Teknik.Security;
  38. using Microsoft.AspNetCore.Routing;
  39. using Microsoft.AspNetCore.Mvc.Internal;
  40. using Microsoft.AspNetCore.Authorization;
  41. using System.Text.Encodings.Web;
  42. using Teknik.Tracking;
  43. namespace Teknik
  44. {
  45. public class Startup
  46. {
  47. public Startup(IHostingEnvironment env)
  48. {
  49. Environment = env;
  50. }
  51. public IHostingEnvironment Environment { get; }
  52. // This method gets called by the runtime. Use this method to add services to the container.
  53. public void ConfigureServices(IServiceCollection services)
  54. {
  55. string baseDir = Environment.ContentRootPath;
  56. string dataDir = Path.Combine(baseDir, "App_Data");
  57. AppDomain.CurrentDomain.SetData("DataDirectory", dataDir);
  58. // Setup IIS
  59. services.Configure<IISOptions>(options =>
  60. {
  61. options.ForwardClientCertificate = false;
  62. options.AutomaticAuthentication = false;
  63. });
  64. // HTTP Context
  65. services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
  66. // Create Configuration Singleton
  67. services.AddScoped<Config, Config>(opt => Config.Load(dataDir));
  68. // Build an intermediate service provider
  69. var sp = services.BuildServiceProvider();
  70. // Resolve the services from the service provider
  71. var config = sp.GetService<Config>();
  72. if (config.DevEnvironment)
  73. {
  74. Environment.EnvironmentName = EnvironmentName.Development;
  75. }
  76. else
  77. {
  78. Environment.EnvironmentName = EnvironmentName.Production;
  79. }
  80. services.AddHttpsRedirection(options =>
  81. {
  82. options.RedirectStatusCode = (Environment.IsDevelopment()) ? StatusCodes.Status307TemporaryRedirect : StatusCodes.Status308PermanentRedirect;
  83. #if DEBUG
  84. options.HttpsPort = 5050;
  85. #else
  86. options.HttpsPort = 443;
  87. #endif
  88. });
  89. services.AddHostedService<TrackingService>();
  90. services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
  91. // Add Tracking Filter scopes
  92. //services.AddScoped<TrackDownload>();
  93. //services.AddScoped<TrackLink>();
  94. //services.AddScoped<TrackPageView>();
  95. // Create the Database Context
  96. services.AddDbContext<TeknikEntities>(options => options
  97. .UseLazyLoadingProxies()
  98. .UseSqlServer(config.DbConnection), ServiceLifetime.Transient);
  99. // Cookie Policies
  100. services.Configure<CookiePolicyOptions>(options =>
  101. {
  102. // This lambda determines whether user consent for non-essential cookies is needed for a given request.
  103. options.CheckConsentNeeded = context => false;
  104. options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.None;
  105. });
  106. services.ConfigureApplicationCookie(options =>
  107. {
  108. options.Cookie.Domain = CookieHelper.GenerateCookieDomain(config.Host, false, Environment.IsDevelopment());
  109. options.Cookie.Name = "TeknikWeb";
  110. options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
  111. options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict;
  112. options.Cookie.Expiration = TimeSpan.FromDays(30);
  113. options.ExpireTimeSpan = TimeSpan.FromDays(30);
  114. });
  115. // Compression Response
  116. services.Configure<GzipCompressionProviderOptions>(options => options.Level = CompressionLevel.Fastest);
  117. services.AddResponseCompression(options => {
  118. options.Providers.Add<BrotliCompressionProvider>();
  119. options.Providers.Add<GzipCompressionProvider>();
  120. });
  121. services.AddHttpsRedirection(options =>
  122. {
  123. options.RedirectStatusCode = StatusCodes.Status301MovedPermanently;
  124. });
  125. // Sessions
  126. //services.AddResponseCaching();
  127. services.AddMemoryCache();
  128. services.AddSession();
  129. // Set the anti-forgery cookie name
  130. services.AddAntiforgery(options =>
  131. {
  132. options.Cookie.Domain = CookieHelper.GenerateCookieDomain(config.Host, false, Environment.IsDevelopment());
  133. options.Cookie.Name = "TeknikWebAntiForgery";
  134. options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
  135. options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict;
  136. });
  137. // Core MVC
  138. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
  139. services.AddTransient<CookieEventHandler>();
  140. services.AddAuthentication(options =>
  141. {
  142. options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
  143. options.DefaultChallengeScheme = "oidc";
  144. })
  145. .AddIdentityServerAuthentication(options =>
  146. {
  147. options.Authority = config.UserConfig.IdentityServerConfig.Authority;
  148. options.RequireHttpsMetadata = true;
  149. options.ApiName = config.UserConfig.IdentityServerConfig.APIName;
  150. options.ApiSecret = config.UserConfig.IdentityServerConfig.APISecret;
  151. options.NameClaimType = "username";
  152. options.RoleClaimType = JwtClaimTypes.Role;
  153. })
  154. .AddCookie(options =>
  155. {
  156. options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
  157. options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict;
  158. options.Cookie.Expiration = TimeSpan.FromDays(30);
  159. options.ExpireTimeSpan = TimeSpan.FromDays(30);
  160. options.Cookie.Name = "TeknikWebAuth";
  161. options.Cookie.Domain = CookieHelper.GenerateCookieDomain(config.Host, false, Environment.IsDevelopment());
  162. options.EventsType = typeof(CookieEventHandler);
  163. })
  164. .AddOpenIdConnect("oidc", options =>
  165. {
  166. options.SignInScheme = "Cookies";
  167. options.Authority = config.UserConfig.IdentityServerConfig.Authority;
  168. options.RequireHttpsMetadata = true;
  169. options.ClientId = config.UserConfig.IdentityServerConfig.ClientId;
  170. options.ClientSecret = config.UserConfig.IdentityServerConfig.ClientSecret;
  171. options.ResponseType = "code id_token";
  172. // Set the scopes to listen to
  173. options.Scope.Clear();
  174. options.Scope.Add("openid");
  175. options.Scope.Add("role");
  176. options.Scope.Add("account-info");
  177. options.Scope.Add("teknik-api.read");
  178. options.Scope.Add("teknik-api.write");
  179. options.Scope.Add("offline_access");
  180. // Let's clear the claim actions and make our own mappings
  181. options.ClaimActions.Clear();
  182. options.ClaimActions.MapUniqueJsonKey("sub", "sub");
  183. options.ClaimActions.MapUniqueJsonKey("username", "username");
  184. options.ClaimActions.MapUniqueJsonKey("role", "role");
  185. options.ClaimActions.MapUniqueJsonKey("creation-date", "creation-date");
  186. options.ClaimActions.MapUniqueJsonKey("last-seen", "last-seen");
  187. options.ClaimActions.MapUniqueJsonKey("account-type", "account-type");
  188. options.ClaimActions.MapUniqueJsonKey("account-status", "account-status");
  189. options.ClaimActions.MapUniqueJsonKey("recovery-email", "recovery-email");
  190. options.ClaimActions.MapUniqueJsonKey("recovery-verified", "recovery-verified");
  191. options.ClaimActions.MapUniqueJsonKey("2fa-enabled", "2fa-enabled");
  192. options.ClaimActions.MapUniqueJsonKey("pgp-public-key", "pgp-public-key");
  193. options.GetClaimsFromUserInfoEndpoint = true;
  194. options.SaveTokens = true;
  195. options.TokenValidationParameters = new TokenValidationParameters
  196. {
  197. NameClaimType = "username",
  198. RoleClaimType = JwtClaimTypes.Role
  199. };
  200. options.Events.OnRemoteFailure = HandleOnRemoteFailure;
  201. });
  202. services.AddAuthorization(options =>
  203. {
  204. options.AddPolicy("FullAPI", p =>
  205. {
  206. p.AddAuthenticationSchemes("Bearer");
  207. p.RequireScope("teknik-api.read");
  208. p.RequireScope("teknik-api.write");
  209. });
  210. options.AddPolicy("ReadAPI", p =>
  211. {
  212. p.AddAuthenticationSchemes("Bearer");
  213. p.RequireScope("teknik-api.read");
  214. });
  215. options.AddPolicy("WriteAPI", p =>
  216. {
  217. p.AddAuthenticationSchemes("Bearer");
  218. p.RequireScope("teknik-api.write");
  219. });
  220. options.AddPolicy("AnyAPI", p =>
  221. {
  222. p.AddAuthenticationSchemes("Bearer");
  223. p.RequireScope("teknik-api.read", "teknik-api.write");
  224. });
  225. });
  226. services.Configure<FormOptions>(x =>
  227. {
  228. x.ValueLengthLimit = int.MaxValue;
  229. x.MultipartBodyLengthLimit = long.MaxValue; // In case of multipart
  230. });
  231. }
  232. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  233. public void Configure(IApplicationBuilder app, TeknikEntities dbContext, Config config)
  234. {
  235. // Create and Migrate the database
  236. dbContext.Database.Migrate();
  237. // Setup the HttpContext
  238. app.UseHttpContextSetup();
  239. // HttpContext Session
  240. app.UseSession(new SessionOptions()
  241. {
  242. IdleTimeout = TimeSpan.FromMinutes(30),
  243. Cookie = new CookieBuilder()
  244. {
  245. Domain = CookieHelper.GenerateCookieDomain(config.Host, false, Environment.IsDevelopment()),
  246. Name = "TeknikWebSession",
  247. SecurePolicy = CookieSecurePolicy.SameAsRequest,
  248. SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict
  249. }
  250. });
  251. // Compress Reponse
  252. app.UseResponseCompression();
  253. // Cache Responses
  254. //app.UseResponseCaching();
  255. // Force a HTTPS redirection (301)
  256. app.UseHttpsRedirection();
  257. // Use Exception Handling
  258. app.UseErrorHandler(config);
  259. // Performance Monitor the entire request
  260. app.UsePerformanceMonitor();
  261. // Custom Middleware
  262. app.UseBlacklist();
  263. app.UseCORS();
  264. app.UseCSP();
  265. app.UseSecurityHeaders();
  266. // Setup static files and cache them client side
  267. app.UseStaticFiles(new StaticFileOptions
  268. {
  269. OnPrepareResponse = ctx =>
  270. {
  271. ctx.Context.Response.Headers[HeaderNames.CacheControl] = "public,max-age=" + 31536000;
  272. }
  273. });
  274. // Enable Cookie Policy
  275. app.UseCookiePolicy();
  276. // Authorize all the things!
  277. app.UseAuthentication();
  278. // And finally, let's use MVC
  279. app.UseMvc(routes =>
  280. {
  281. routes.BuildRoutes(config);
  282. });
  283. }
  284. private async Task HandleOnRemoteFailure(RemoteFailureContext context)
  285. {
  286. if (context.Failure.Message.Contains("access_denied"))
  287. context.Response.StatusCode = 403;
  288. context.HandleResponse();
  289. }
  290. }
  291. }