public static async Task <AuthOutput> ValidateTokenAsync(string accessToken) { var idSrvTokenBearerOpts = IdSrvTokenBearerOpts.InitDefault(); //using IdentityModel for token introspection //it provides anice functionality extension set over http client using (var client = new HttpClient()) { var response = await client.IntrospectTokenAsync(new TokenIntrospectionRequest { Address = $"{idSrvTokenBearerOpts.Authority}/connect/introspect", ClientId = idSrvTokenBearerOpts.ApiName, ClientSecret = idSrvTokenBearerOpts.ApiSecret, Token = accessToken }); return(new AuthOutput { Success = !response.IsError && response.IsActive, AccessToken = accessToken, //Note: expiration in seconds since epoch. //Code below should give time in UTC AccessTokenExpirationTimeUtc = !response.IsError && response.IsActive ? new DateTime(1970, 01, 01, 0, 0, 0, DateTimeKind.Utc).AddSeconds( long.Parse(response.Claims.FirstOrDefault(x => x.Type == "exp")?.Value ?? "0")) : (DateTime?)null }); } }
/// <summary> /// Configures maphive api services /// </summary> /// <param name="services"></param> /// <param name="settings"></param> public static void ConfigurMapHiveApiServices(this IServiceCollection services, ApiConfigurationSettings settings) { services .AddMvc(opts => { var authSchemes = new List <string> { "Bearer" }; if (settings.AllowApiTokenAccess) { authSchemes.Add(MapHiveTokenAuthenticationHandler.Scheme); } //by default enforce auth on all controllers! var globalAuthorizePolicy = new AuthorizationPolicyBuilder() .AddAuthenticationSchemes(authSchemes.ToArray()) .RequireAuthenticatedUser() .Build(); opts.Filters.Add(new AuthorizeFilter(globalAuthorizePolicy)); //so can keep on using Cartomatic.Utils.Identity... //a bit not in line with aspnet core though, but these utils are used in many places and passing identity explicitly doesn't seem to be a viable option. at least at this stage... opts.Filters.Add(new OldSchoolUserImpersonationViaClaimsPrincipalAttribute()); //user cfg depends on the org context so this attribute must kick in earlier //this way org context is exrtracted before dependant code kicks in opts.Filters.Add(new OrganizationContextActionFilterAttribute()); //use a default or customised user cfg filter opts.Filters.Add( settings?.UserConfigurationActionFilterAtribute ?? new UserConfigurationActionFilterAtribute() ); //used to work nicely up to 2.2, stopped working in 3.0 - using middleware instead now //if (settings.EnableCompression) //{ // //allow reading gzip/json // opts.InputFormatters.Insert(0,new GZippedJsonInputFormatter()); //} //when auto migrators are specified wire them up via MapHive.Core.Api.DbMigratorActionFilterAtribute if (settings?.DbMigrator != null || settings?.OrganizationDbMigrator != null) { opts.Filters.Add(new DbMigratorActionFilterAtribute( settings?.OrganizationDbMigrator, settings?.DbMigrator ) ); } }) .AddJsonOptions(opts => { }) //in 3.x using newtonsoft so far, so need to opt in! .AddNewtonsoftJson(opts => { opts.SerializerSettings.Formatting = Formatting.None; #if DEBUG opts.SerializerSettings.Formatting = Formatting.Indented; #endif //make the json props be camel case! opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); //ignore nulls, no point in outputting them! opts.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; //ensure dates are handled as ISO 8601 opts.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; } ); var bearerCfg = IdSrvTokenBearerOpts.InitDefault(); //by default do Bearer auth. it fallsback for token auth when required var authBuilder = services.AddAuthentication("Bearer"); //always plug in idsrv auth! authBuilder.AddIdentityServerAuthentication(options => { options.Authority = bearerCfg.Authority; options.RequireHttpsMetadata = true; options.ApiName = bearerCfg.ApiName; options.ApiSecret = bearerCfg.ApiSecret; options.TokenRetriever = request => { //first try to obtain the bearer token off the header var authToken = IdentityModel.AspNetCore.OAuth2Introspection.TokenRetrieval.FromAuthorizationHeader()(request); //if no token in header, try to grab it off the url if (string.IsNullOrEmpty(authToken)) { authToken = IdentityModel.AspNetCore.OAuth2Introspection.TokenRetrieval.FromQueryString()(request); } return(authToken); }; }); //should investigate tokens??? if (settings?.AllowApiTokenAccess == true) { //services.Add<IAuthorizationHandler, MapHiveTokenAuthenticationHandler>(); authBuilder.AddScheme <MapHiveTokenAuthenticationOptions, MapHiveTokenAuthenticationHandler>( MapHiveTokenAuthenticationHandler.Scheme, opts => { } ); } services.Configure <IISOptions>(opts => { opts.ForwardClientCertificate = false; }); services.Configure <IISServerOptions>(options => { options.AllowSynchronousIO = true; options.MaxRequestBodySize = null; }); //auto swagger documentation if (!string.IsNullOrEmpty(settings.XmlCommentsPath)) { services.AddSwaggerGen(c => { c.SwaggerDoc(settings.UseGitVersion ? Cartomatic.Utils.Git.GetRepoVersion() : settings.ApiVersion, new OpenApiInfo { Title = settings?.ApiTitle ?? "unknown-api", Version = settings.UseGitVersion ? Cartomatic.Utils.Git.GetRepoVersion() : settings.ApiVersion }); c.IncludeXmlComments( settings.XmlCommentsPath.IsAbsolute() ? settings.XmlCommentsPath : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, settings.XmlCommentsPath) ); // UseFullTypeNameInSchemaIds replacement for .NET Core c.CustomSchemaIds(x => x.FullName); }); } if (settings.EnableCompression) { services.Configure <GzipCompressionProviderOptions>(cfgOpts => cfgOpts.Level = System.IO.Compression.CompressionLevel.Optimal); services.AddResponseCompression(opts => { //custom brotli compression provider //MapHive.Core.Api.Compression.BrotliCompressionProvider - used prior to 3.x when brotli was not provided by the framework opts.Providers.Add <Microsoft.AspNetCore.ResponseCompression.BrotliCompressionProvider>(); //add customized mime opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(settings.CompressedMimeTypes ?? new string[0]); opts.EnableForHttps = true; }); } if (settings.UsesIdentityUserManagerUtils) { MapHive.Core.Identity.UserManagerUtils.Configure(services, "MapHiveIdentity"); } //customize cors settings - example using cors policy //services.AddCors(opts => //{ // opts.AddPolicy("MapHiveCors", builder => builder.CustomizeCors()); //}); }