The next generation of the Teknik Services. Written in ASP.NET. https://www.teknik.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Startup.cs 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Security.Claims;
  6. using IdentityServer4.EntityFramework.DbContexts;
  7. using IdentityServer4.EntityFramework.Mappers;
  8. using Microsoft.AspNetCore.Builder;
  9. using Microsoft.AspNetCore.Hosting;
  10. using Microsoft.AspNetCore.Http;
  11. using Microsoft.AspNetCore.Identity;
  12. using Microsoft.AspNetCore.Mvc;
  13. using Microsoft.EntityFrameworkCore;
  14. using Microsoft.Extensions.Configuration;
  15. using Microsoft.Extensions.DependencyInjection;
  16. using Microsoft.Extensions.Logging;
  17. using Microsoft.Net.Http.Headers;
  18. using Teknik.Configuration;
  19. using Teknik.IdentityServer.Configuration;
  20. using Teknik.IdentityServer.Security;
  21. using Teknik.IdentityServer.Middleware;
  22. using Teknik.Logging;
  23. using Microsoft.AspNetCore.Authorization;
  24. using Teknik.IdentityServer.Models;
  25. using IdentityServer4.Services;
  26. using System.Collections.Generic;
  27. namespace Teknik.IdentityServer
  28. {
  29. public class Startup
  30. {
  31. public Startup(IConfiguration configuration, IHostingEnvironment env)
  32. {
  33. Configuration = configuration;
  34. Environment = env;
  35. }
  36. public IConfiguration Configuration { get; }
  37. public IHostingEnvironment Environment { get; }
  38. public void ConfigureServices(IServiceCollection services)
  39. {
  40. string dataDir = Configuration["ConfigDirectory"];
  41. AppDomain.CurrentDomain.SetData("DataDirectory", dataDir);
  42. var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
  43. // Create Configuration Singleton
  44. services.AddScoped<Config, Config>(opt => Config.Load(dataDir));
  45. // Build an intermediate service provider
  46. var sp = services.BuildServiceProvider();
  47. // Resolve the services from the service provider
  48. var config = sp.GetService<Config>();
  49. services.ConfigureApplicationCookie(options =>
  50. {
  51. options.Cookie.Name = "TeknikAuth";
  52. options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
  53. options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict;
  54. options.Cookie.Expiration = TimeSpan.FromDays(30);
  55. options.ExpireTimeSpan = TimeSpan.FromDays(30);
  56. });
  57. services.AddHttpsRedirection(options =>
  58. {
  59. options.RedirectStatusCode = StatusCodes.Status301MovedPermanently;
  60. });
  61. // Sessions
  62. services.AddResponseCaching();
  63. services.AddMemoryCache();
  64. services.AddSession();
  65. // Set the anti-forgery cookie name
  66. services.AddAntiforgery(options =>
  67. {
  68. options.Cookie.Name = "TeknikAuthAntiForgery";
  69. options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
  70. options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict;
  71. });
  72. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
  73. services.AddDbContext<ApplicationDbContext>(builder =>
  74. builder.UseSqlServer(config.DbConnection, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)));
  75. services.AddIdentity<ApplicationUser, IdentityRole>(options =>
  76. {
  77. options.Password = new PasswordOptions()
  78. {
  79. RequireDigit = false,
  80. RequiredLength = 4,
  81. RequiredUniqueChars = 1,
  82. RequireLowercase = false,
  83. RequireNonAlphanumeric = false,
  84. RequireUppercase = false
  85. };
  86. })
  87. .AddEntityFrameworkStores<ApplicationDbContext>()
  88. .AddDefaultTokenProviders();
  89. services.AddIdentityServer(options =>
  90. {
  91. options.Events.RaiseErrorEvents = true;
  92. options.Events.RaiseInformationEvents = true;
  93. options.Events.RaiseFailureEvents = true;
  94. options.Events.RaiseSuccessEvents = true;
  95. options.UserInteraction.ErrorUrl = "/Error/IdentityError";
  96. options.UserInteraction.ErrorIdParameter = "errorId";
  97. options.Cors.CorsPaths.Add(new PathString("/connect/authorize"));
  98. options.Cors.CorsPaths.Add(new PathString("/connect/endsession"));
  99. options.Cors.CorsPaths.Add(new PathString("/connect/checksession"));
  100. options.Cors.CorsPaths.Add(new PathString("/connect/introspect"));
  101. })
  102. .AddOperationalStore(options =>
  103. options.ConfigureDbContext = builder =>
  104. builder.UseSqlServer(config.DbConnection, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)))
  105. .AddConfigurationStore(options =>
  106. options.ConfigureDbContext = builder =>
  107. builder.UseSqlServer(config.DbConnection, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)))
  108. .AddAspNetIdentity<ApplicationUser>()
  109. .AddRedirectUriValidator<TeknikRedirectUriValidator>()
  110. .AddDeveloperSigningCredential();
  111. services.AddAuthorization(options =>
  112. {
  113. foreach (var policy in Policies.Get())
  114. {
  115. options.AddPolicy(policy.Name, p =>
  116. {
  117. foreach (var scope in policy.Scopes)
  118. {
  119. p.RequireScope(scope);
  120. }
  121. });
  122. }
  123. });
  124. services.AddAuthentication("Bearer")
  125. .AddIdentityServerAuthentication(options =>
  126. {
  127. options.Authority = config.UserConfig.IdentityServerConfig.Authority;
  128. options.RequireHttpsMetadata = true;
  129. options.ApiName = "auth-api";
  130. });
  131. services.AddTransient<IPasswordHasher<ApplicationUser>, TeknikPasswordHasher>();
  132. services.AddTransient<IProfileService, TeknikProfileService>();
  133. }
  134. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, Config config)
  135. {
  136. // Initiate Logging
  137. loggerFactory.AddLogger(config);
  138. // Setup the HttpContext
  139. app.UseHttpContextSetup();
  140. // HttpContext Session
  141. app.UseSession(new SessionOptions()
  142. {
  143. IdleTimeout = TimeSpan.FromMinutes(30),
  144. Cookie = new CookieBuilder()
  145. {
  146. Domain = null,
  147. Name = "TeknikAuthSession",
  148. SecurePolicy = CookieSecurePolicy.Always,
  149. SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict
  150. }
  151. });
  152. // Use Exception Handling
  153. app.UseErrorHandler(config);
  154. if (env.IsDevelopment())
  155. {
  156. app.UseDeveloperExceptionPage();
  157. }
  158. // Custom Middleware
  159. app.UseBlacklist();
  160. app.UseCORS();
  161. app.UseCSP();
  162. app.UseSecurityHeaders();
  163. // Cache Responses
  164. app.UseResponseCaching();
  165. // Force a HTTPS redirection (301)
  166. app.UseHttpsRedirection();
  167. // Setup static files anc cache them client side
  168. app.UseStaticFiles(new StaticFileOptions
  169. {
  170. OnPrepareResponse = ctx =>
  171. {
  172. ctx.Context.Response.Headers[HeaderNames.CacheControl] = "public,max-age=" + 31536000;
  173. }
  174. });
  175. InitializeDbTestDataAsync(app, config).Wait();
  176. app.UseIdentityServer();
  177. app.UseMvcWithDefaultRoute();
  178. }
  179. private static async System.Threading.Tasks.Task InitializeDbTestDataAsync(IApplicationBuilder app, Config config)
  180. {
  181. using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
  182. {
  183. scope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
  184. scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>().Database.Migrate();
  185. scope.ServiceProvider.GetRequiredService<ApplicationDbContext>().Database.Migrate();
  186. var context = scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
  187. if (!context.Clients.Any())
  188. {
  189. foreach (var client in Clients.Get(config))
  190. {
  191. context.Clients.Add(client.ToEntity());
  192. }
  193. context.SaveChanges();
  194. }
  195. if (!context.IdentityResources.Any())
  196. {
  197. foreach (var resource in Resources.GetIdentityResources())
  198. {
  199. context.IdentityResources.Add(resource.ToEntity());
  200. }
  201. context.SaveChanges();
  202. }
  203. if (!context.ApiResources.Any())
  204. {
  205. foreach (var resource in Resources.GetApiResources(config))
  206. {
  207. context.ApiResources.Add(resource.ToEntity());
  208. }
  209. context.SaveChanges();
  210. }
  211. }
  212. }
  213. }
  214. }