Ejemplo n.º 1
0
        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());
            //});
        }