public Task <HttpResponseMessage> HandleRouteAsync(Type controllerType,
                                                           IApplication httpApp, HttpRequestMessage request, string routeName,
                                                           RouteHandlingDelegate continueExecution)
        {
            return(EastFive.Azure.AppSettings.TableInformationToken.ConfigurationString(
                       async headerToken =>
            {
                if (!request.Headers.Contains(HeaderKey))
                {
                    return await continueExecution(controllerType, httpApp, request, routeName);
                }

                if (request.Headers.GetValues(HeaderKey).First() != headerToken)
                {
                    return request.CreateResponse(System.Net.HttpStatusCode.Unauthorized);
                }

                if (request.Headers.Contains("Migrate"))
                {
                    var tableData = await controllerType.StorageGetAll().ToArrayAsync();
                    return request.CreateResponse(System.Net.HttpStatusCode.OK, tableData);
                }

                var tableInformation = await controllerType.StorageTableInformationAsync();
                return request.CreateResponse(System.Net.HttpStatusCode.OK, tableInformation);
            },
                       why => continueExecution(controllerType, httpApp, request, routeName)));
        }
        public Task <IHttpResponse> HandleRouteAsync(Type controllerType, IInvokeResource resourceInvoker,
                                                     IApplication httpApp, IHttpRequest request,
                                                     RouteHandlingDelegate continueExecution)
        {
            if (!request.Headers.ContainsKey(HeaderKey))
            {
                return(continueExecution(controllerType, httpApp, request));
            }
            return(EastFive.Azure.AppSettings.TableInformationToken.ConfigurationString(
                       async headerToken =>
            {
                if (request.Headers[HeaderKey].First() != headerToken)
                {
                    return request.CreateResponse(System.Net.HttpStatusCode.Unauthorized);
                }

                if (request.Headers.ContainsKey("X-StorageTableInformation-List"))
                {
                    var tableData = await controllerType.StorageGetAll().ToArrayAsync();
                    return request.CreateExtrudedResponse(
                        System.Net.HttpStatusCode.OK, tableData);
                }

                if (request.Headers.ContainsKey("X-StorageTableInformation-RepairModifiers"))
                {
                    var query = request.Headers
                                .Where(hdr => "X-StorageTableInformation-Query".Equals(hdr.Key, StringComparison.OrdinalIgnoreCase))
                                .First(
                        (hdr, next) => hdr.Value.First(
                            (hdrValue, next) => hdrValue,
                            () => string.Empty),
                        () => string.Empty);
                    return new WriteStreamAsyncHttpResponse(request, System.Net.HttpStatusCode.OK,
                                                            $"{controllerType.FullName}.repair.txt", "text/text", true,
                                                            async stream =>
                    {
                        string [] repairs = await controllerType
                                            .StorageRepairModifiers(query)
                                            .Select(
                            async line =>
                        {
                            var bytes = line.GetBytes(Encoding.UTF8);
                            await stream.WriteAsync(bytes, 0, bytes.Length);
                            return line;
                        })
                                            .Await(readAhead: 100)
                                            .ToArrayAsync();
                    });
                }

                var tableInformation = await controllerType.StorageTableInformationAsync();
                return request.CreateResponse(System.Net.HttpStatusCode.OK, tableInformation);
            },
                       why => continueExecution(controllerType, httpApp, request)));
        }
예제 #3
0
        public Task <IHttpResponse> HandleRouteAsync(Type controllerType, IInvokeResource resourceInvoker,
                                                     IApplication httpApp, IHttpRequest request,
                                                     RouteHandlingDelegate continueExecution)
        {
            Func <Task <IHttpResponse> > skip =
                () => continueExecution(controllerType, httpApp, request);

            if (!AppSettings.CorsCorrection.ConfigurationBoolean(s => s, onNotSpecified: () => false))
            {
                return(skip());
            }

            // Configs to set:
            //
            // EastFive.Api.CorsCorrection=true
            // cors:Origins=https://myserver.com,etc.  (localhost included by default so this app setting can remain absent/unconfigured if just need localhost)
            // cors:MaxAgeSeconds=60                   (default is 5 seconds if not set)
            //
            return(GetResponse());

            string GetAllowedOrigin()
            {
                // accept localhost (all ports)
                // accept request server
                // accept any additional servers in config
                request.Headers.TryGetValue("Origin", out string[] reqOrigins);
                var localhostAuthorities = reqOrigins
                                           .NullToEmpty()
                                           .SelectMany(reqOrigin => reqOrigin.Split(','.AsArray(), StringSplitOptions.RemoveEmptyEntries))
                                           .Where(
                    (reqOrigin) =>
                {
                    if (!Uri.TryCreate(reqOrigin, UriKind.Absolute, out Uri reqOriginUri))
                    {
                        return(false);
                    }

                    return(reqOriginUri.GetLeftPart(UriPartial.Authority).IndexOf("localhost", StringComparison.OrdinalIgnoreCase) != -1);
                });
                var requestAuthority = request.RequestUri.GetLeftPart(UriPartial.Authority);
                var corsAuthorities  = "cors:Origins".ConfigurationString(
                    (v) => v.Split(','.AsArray(), StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToArray(),
                    (why) => new string[] { });
                var allowableOriginValues = localhostAuthorities
                                            .Append(requestAuthority)
                                            .Concat(corsAuthorities)
                                            .Distinct()
                                            .ToArray();
                var allowedOrigin = allowableOriginValues
                                    .NullToEmpty()
                                    .First(
                    (allowed, next) =>
                {
                    if (!reqOrigins.NullToEmpty().Contains(allowed, StringComparer.OrdinalIgnoreCase))
                    {
                        return(next());
                    }

                    return(allowed);
                },
                    () => default(string));

                return(allowedOrigin);
            }

            string GetAllowedMethods()
            {
                // accept OPTIONS
                // accept any additional methods in config
                request.Headers.TryGetValue("Access-Control-Request-Method", out string[] reqMethod);
                return(reqMethod
                       .NullToEmpty()
                       .Append("OPTIONS")
                       .Distinct()
                       .Join(","));
            }

            string GetAllowedHeaders()
            {
                // accept any headers requested
                request.Headers.TryGetValue("Access-Control-Request-Headers", out string[] reqHeaders);
                return(reqHeaders
                       .NullToEmpty()
                       .Distinct()
                       .Join(","));
            }

            string GetMaxAgeSeconds()
            {
                return("cors:MaxAgeSeconds"
                       .ConfigurationLong(
                           (v) => v,
                           (why) => 5,
                           () => 5)
                       .ToString());
            }

            Task <IHttpResponse> GetResponse()
            {
                if (request.Method.Method.ToLower() != HttpMethod.Options.Method.ToLower())
                {
                    return(skip());
                }

                var allowedOrigin = GetAllowedOrigin();

                if (allowedOrigin == default)
                {
                    return(request.CreateResponse(System.Net.HttpStatusCode.Forbidden).AddReason("origin not allowed").AsTask());
                }

                var response = request.CreateResponse(System.Net.HttpStatusCode.OK);

                response.SetHeader("Access-Control-Allow-Origin", allowedOrigin);
                response.SetHeader("Access-Control-Allow-Methods", GetAllowedMethods());
                response.SetHeader("Access-Control-Allow-Headers", GetAllowedHeaders());
                response.SetHeader("Vary", "origin");
                response.SetHeader("Access-Control-Max-Age", GetMaxAgeSeconds());
                return(response.AsTask());
            }
        }
        public async Task <IHttpResponse> HandleRouteAsync(Type controllerType, IInvokeResource resourceInvoker,
                                                           IApplication httpApp, IHttpRequest request,
                                                           RouteHandlingDelegate continueExecution)
        {
            var response = await continueExecution(controllerType, httpApp, request);

            if (deactivated)
            {
                return(response);
            }

            string teamsNotifyParam = GetTeamsNotifyParameter();

            if (!ShouldNotify(out string collectionFolder))
            {
                return(response);
            }

            try
            {
                string messageId = await TeamsNotifyAsync(controllerType, resourceInvoker,
                                                          httpApp, request, response,
                                                          teamsNotifyParam, collectionFolder);
            } catch (HttpRequestException)
            {
            } catch (Exception)
            {
            }
            return(response);

            string GetTeamsNotifyParameter()
            {
                return(request.Headers
                       .Where(kvp => kvp.Key.Equals("X-Teams-Notify", StringComparison.OrdinalIgnoreCase))
                       .First(
                           (teamsNotifyParams, next) =>
                {
                    return teamsNotifyParams.Value.First(
                        (teamsNotifyParam, next) => teamsNotifyParam,
                        () => default(string));
                },
                           () =>
                {
                    return default(string);
                }));
            }

            bool HasReportableError()
            {
                if (((int)response.StatusCode) < 400)
                {
                    return(false);
                }
                if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                {
                    return(false);
                }
                if (response.StatusCode == System.Net.HttpStatusCode.Conflict)
                {
                    return(false);
                }
                return(true);
            }

            bool RequestTeamsNotify() => teamsNotifyParam != default;

            bool ShouldNotify(out string collectionFolder)
            {
                collectionFolder = default;
                if (RequestTeamsNotify())
                {
                    return(true);
                }
                if (HasReportableError())
                {
                    return(true);
                }
                if (TeamsNotification.IsMatch(request, response, out collectionFolder))
                {
                    return(true);
                }

                return(false);
            }
        }
예제 #5
0
        public Task <IHttpResponse> HandleRouteAsync(Type controllerType, IInvokeResource resourceInvoker,
                                                     IApplication httpApp, IHttpRequest request,
                                                     RouteHandlingDelegate continueExecution)
        {
            if (!request.RequestUri.TryGetQueryParam(ParameterName, out string apiVoucher))
            {
                if (!request.TryGetHeader(ParameterName, out apiVoucher))
                {
                    return(continueExecution(controllerType, httpApp, request));
                }
            }

            if (request.TryGetAuthorization(out string auth))
            {
                return(continueExecution(controllerType, httpApp, request));
            }

            return(EastFive.Security.VoucherTools.ValidateUrlToken(apiVoucher,
                                                                   async(voucherTokenId) =>
            {
                return await await voucherTokenId.AsRef <VoucherToken>()
                .StorageGetAsync(
                    voucherToken =>
                {
                    return EastFive.Security.AppSettings.TokenScope.ConfigurationUri(
                        scope =>
                    {
                        var tokenExpiration = TimeSpan.FromMinutes(1.0);
                        request.RequestUri = request.RequestUri.RemoveQueryParameter("api-voucher");
                        var sessionId = apiVoucher.MD5HashGuid();
                        var claims = voucherToken.claims;
                        return JwtTools.CreateToken(sessionId,
                                                    scope, tokenExpiration, claims,
                                                    (tokenNew) =>
                        {
                            request.SetAuthorization(tokenNew);
                            return continueExecution(controllerType, httpApp, request);
                        },
                                                    (missingConfig) => continueExecution(controllerType, httpApp, request),
                                                    (configName, issue) => continueExecution(controllerType, httpApp, request));
                    },
                        (why) => continueExecution(controllerType, httpApp, request));
                },
                    () => request
                    .CreateResponse(System.Net.HttpStatusCode.Unauthorized)
                    .AddReason("Voucher token does not exist.")
                    .AsTask());
            },
                                                                   why => request
                                                                   .CreateResponse(System.Net.HttpStatusCode.Unauthorized)
                                                                   .AddReason(why)
                                                                   .AsTask(),
                                                                   why => request
                                                                   .CreateResponse(System.Net.HttpStatusCode.Unauthorized)
                                                                   .AddReason(why)
                                                                   .AsTask(),
                                                                   why => request
                                                                   .CreateResponse(System.Net.HttpStatusCode.Unauthorized)
                                                                   .AddReason(why)
                                                                   .AsTask(),
                                                                   why => request
                                                                   .CreateResponse(System.Net.HttpStatusCode.Unauthorized)
                                                                   .AddReason(why)
                                                                   .AsTask(),
                                                                   (name, why) => request
                                                                   .CreateResponse(System.Net.HttpStatusCode.Unauthorized)
                                                                   .AddReason(why)
                                                                   .AsTask()));
        }
        public async Task <IHttpResponse> HandleRouteAsync(Type controllerType, IInvokeResource resourceInvoker,
                                                           IApplication httpApp, IHttpRequest routeData,
                                                           RouteHandlingDelegate continueExecution)
        {
            var stopwatch = Stopwatch.StartNew();
            var requestId = Guid.NewGuid().ToString("N");
            var telemetry = new RequestTelemetry()
            {
                Id        = requestId,
                Source    = controllerType.Assembly.FullName,
                Timestamp = DateTimeOffset.UtcNow,
                Url       = routeData.GetAbsoluteUri(), // request.RequestUri,
            };

            #region User / Session

            var claims = routeData.GetClaims(
                claimsEnumerable => claimsEnumerable.ToArray(),
                () => new Claim[] { },
                (why) => new Claim[] { });
            var sessionIdClaimType = Api.Auth.ClaimEnableSessionAttribute.Type;
            var sessionIdMaybe     = SessionToken.GetClaimIdMaybe(claims, sessionIdClaimType);
            if (sessionIdMaybe.HasValue)
            {
                telemetry.Context.Session.Id = sessionIdMaybe.Value.ToString().ToUpper();
            }

            var accountIdClaimType = EastFive.Api.AppSettings.ActorIdClaimType.ConfigurationString(
                (accIdCT) => accIdCT,
                (why) => default);
            if (accountIdClaimType.HasBlackSpace())
            {
                var accountIdMaybe = SessionToken.GetClaimIdMaybe(claims, accountIdClaimType);
                if (accountIdMaybe.HasValue)
                {
                    var accountIdStr = accountIdMaybe.Value.ToString().ToUpper();
                    telemetry.Context.User.AccountId           = accountIdStr;
                    telemetry.Context.User.AuthenticatedUserId = accountIdStr;
                }
            }

            foreach (var claim in claims.Distinct(claim => claim.Type))
            {
                telemetry.Properties.Add($"claim[{claim.Type}]", claim.Value);
            }

            #endregion

            routeData.Properties.Add(HttpRequestMessagePropertyRequestTelemetryKey, telemetry);
            var response = await continueExecution(controllerType, httpApp, routeData);

            telemetry.ResponseCode = response.StatusCode.ToString();
            if (response.ReasonPhrase.HasBlackSpace())
            {
                telemetry.Properties.AddOrReplace("reason_phrase", response.ReasonPhrase);
            }
            telemetry.Success = response.StatusCode.IsSuccess();

            #region Method result identfiers

            if (response.Headers.TryGetValue(Middleware.HeaderStatusType, out string[] statusNames))
예제 #7
0
        public async Task <HttpResponseMessage> HandleRouteAsync(Type controllerType,
                                                                 IApplication httpApp, HttpRequestMessage request, string routeName,
                                                                 RouteHandlingDelegate continueExecution)
        {
            var stopwatch = Stopwatch.StartNew();
            var requestId = Guid.NewGuid().ToString("N");
            var telemetry = new RequestTelemetry()
            {
                Id        = requestId,
                Source    = "EastFive.Api",
                Timestamp = DateTimeOffset.UtcNow,
                Url       = request.RequestUri,
            };

            #region User / Session

            var claims = request.GetClaims(
                claimsEnumerable => claimsEnumerable.ToArray(),
                () => new Claim[] { },
                (why) => new Claim[] { });
            var sessionIdClaimType = BlackBarLabs.Security.ClaimIds.Session;
            var sessionIdMaybe     = SessionToken.GetClaimIdMaybe(claims, sessionIdClaimType);
            if (sessionIdMaybe.HasValue)
            {
                telemetry.Context.Session.Id = sessionIdMaybe.Value.ToString().ToUpper();
            }

            var accountIdClaimType = EastFive.Api.AppSettings.ActorIdClaimType.ConfigurationString(
                (accIdCT) => accIdCT,
                (why) => default);
            if (accountIdClaimType.HasBlackSpace())
            {
                var accountIdMaybe = SessionToken.GetClaimIdMaybe(claims, accountIdClaimType);
                if (accountIdMaybe.HasValue)
                {
                    var accountIdStr = accountIdMaybe.Value.ToString().ToUpper();
                    telemetry.Context.User.AccountId           = accountIdStr;
                    telemetry.Context.User.AuthenticatedUserId = accountIdStr;
                }
            }

            foreach (var claim in claims)
            {
                telemetry.Properties.Add($"claim[{claim.Type}]", claim.Value);
            }

            #endregion

            request.Properties.Add(HttpRequestMessagePropertyRequestTelemetryKey, telemetry);
            var response = await continueExecution(controllerType, httpApp, request, routeName);

            telemetry.ResponseCode = response.StatusCode.ToString();
            if (response.ReasonPhrase.HasBlackSpace())
            {
                telemetry.Properties.AddOrReplace("reason_phrase", response.ReasonPhrase);
            }
            telemetry.Success = response.IsSuccessStatusCode;

            #region Method result identfiers

            if (response.Headers.TryGetValues(HeaderStatusName, out IEnumerable <string> statusNames))
            {
                if (statusNames.Any())
                {
                    telemetry.Properties.Add(TelemetryStatusName, statusNames.First());
                }
            }
            if (response.Headers.TryGetValues(HeaderStatusInstance, out IEnumerable <string> statusInstances))
            {
                if (statusInstances.Any())
                {
                    telemetry.Properties.Add(TelemetryStatusInstance, statusInstances.First());
                }
            }

            #endregion

            var telemetryClient = AppSettings.ApplicationInsights.InstrumentationKey.LoadTelemetryClient();
            telemetry.Duration = stopwatch.Elapsed;
            telemetryClient.TrackRequest(telemetry);

            return(response);
        }
예제 #8
0
        public Task <IHttpResponse> HandleRouteAsync(Type controllerType, IInvokeResource resourceInvoker,
                                                     IApplication httpApp, IHttpRequest request,
                                                     RouteHandlingDelegate continueExecution)
        {
            if (!request.RequestUri.TryGetQueryParam(
                    AccessTokenAccountExtensions.QueryParameter,
                    out string accessToken))
            {
                return(continueExecution(controllerType, httpApp, request));
            }

            if (request.GetAuthorization().HasBlackSpace())
            {
                return(continueExecution(controllerType, httpApp, request));
            }

            return(request.RequestUri.ValidateAccessTokenAccount(
                       accessTokenInfo =>
            {
                return EastFive.Security.AppSettings.TokenScope.ConfigurationUri(
                    scope =>
                {
                    var tokenExpiration = TimeSpan.FromMinutes(1.0);
                    request.RequestUri = request.RequestUri.RemoveQueryParameter(
                        AccessTokenAccountExtensions.QueryParameter);
                    var sessionId = accessTokenInfo.sessionId;
                    var authId = accessTokenInfo.accountId;
                    var duration = accessTokenInfo.expirationUtc - DateTime.UtcNow;
                    return JwtTools.CreateToken(sessionId, authId, scope, duration,
                                                tokenCreated:
                                                (tokenNew) =>
                    {
                        request.SetAuthorization(tokenNew);
                        return continueExecution(controllerType, httpApp, request);
                    },
                                                missingConfigurationSetting:
                                                (configName) => continueExecution(controllerType, httpApp, request),
                                                invalidConfigurationSetting:
                                                (configName, issue) => continueExecution(controllerType, httpApp, request));
                },
                    (why) => continueExecution(controllerType, httpApp, request),
                    () => continueExecution(controllerType, httpApp, request));
            },
                       onAccessTokenNotProvided: () => continueExecution(controllerType, httpApp, request),
                       onAccessTokenInvalid:
                       () =>
            {
                return request
                .CreateResponse(System.Net.HttpStatusCode.Forbidden)
                .AddReason("Access token is invalid")
                .AsTask();
            },
                       onAccessTokenExpired:
                       () =>
            {
                return request
                .CreateResponse(System.Net.HttpStatusCode.Forbidden)
                .AddReason("Access token is expired")
                .AsTask();
            },
                       onInvalidSignature:
                       () =>
            {
                return request
                .CreateResponse(System.Net.HttpStatusCode.Forbidden)
                .AddReason("Access token has an invalid signature")
                .AsTask();
            },
                       onSystemNotConfigured: () => continueExecution(controllerType, httpApp, request)));
        }