public static async Task <TResult> ProcessRequestAsync <TResult>(
            EastFive.Azure.Auth.Method method,
            IDictionary <string, string> values,
            AzureApplication application, HttpRequestMessage request,
            System.Web.Http.Routing.UrlHelper urlHelper,
            Func <Uri, TResult> onRedirect,
            Func <string, TResult> onBadCredentials,
            Func <string, TResult> onCouldNotConnect,
            Func <string, TResult> onFailure)
        {
            var authorizationRequestManager = application.AuthorizationRequestManager;

            var telemetry = application.Telemetry;

            telemetry.TrackEvent($"ResponseController.ProcessRequestAsync - Requesting credential manager.");

            var requestId   = Guid.NewGuid();
            var redirection = new Redirection
            {
                webDataRef     = requestId.AsRef <Redirection>(),
                method         = method.authenticationId,
                values         = values,
                redirectedFrom = request.Headers.Referrer,
            };

            return(await await redirection.StorageCreateAsync(
                       discard =>
            {
                var baseUri = request.RequestUri;
                return AuthenticationAsync(requestId,
                                           method, values, baseUri, application,
                                           onRedirect,
                                           () => onFailure("Authorization not found"),
                                           onCouldNotConnect,
                                           onFailure);
            },
                       () => onFailure("GUID NOT UNIQUE").AsTask()));
        }
 private static Task <TResult> UnmappedCredentialAsync <TResult>(
     string subject, IDictionary <string, string> extraParams,
     EastFive.Azure.Auth.Method authentication, Authorization authorization,
     IProvideAuthorization authorizationProvider,
     AzureApplication application,
     Uri baseUri,
     Func <Guid, TResult> createMapping,
     Func <TResult> onAllowSelfServe,
     Func <Uri, TResult> onInterceptProcess,
     Func <string, TResult> onFailure,
     TelemetryClient telemetry)
 {
     return(application.OnUnmappedUserAsync(subject, extraParams,
                                            authentication, authorization, authorizationProvider, baseUri,
                                            (accountId) => createMapping(accountId),
                                            () => onAllowSelfServe(),
                                            (callback) => onInterceptProcess(callback),
                                            () =>
     {
         var message = "Token is not connected to a user in this system";
         telemetry.TrackException(new ResponseException(message));
         return onFailure(message);
     }));
 }
        public static async Task <IHttpResponse> ProcessRequestAsync(
            EastFive.Azure.Auth.Method method,
            IDictionary <string, string> values,
            IAzureApplication application,
            IHttpRequest request,
            IInvokeApplication endpoints,
            IProvideUrl urlHelper,
            Func <Uri, Guid?, IHttpResponse> onRedirect,
            Func <string, IHttpResponse> onAuthorizationnotFound,
            Func <string, IHttpResponse> onCouldNotConnect,
            Func <string, IHttpResponse> onFailure)
        {
            //var authorizationRequestManager = application.AuthorizationRequestManager;

            var telemetry = application.Telemetry;

            telemetry.TrackEvent($"ResponseController.ProcessRequestAsync - Requesting credential manager.");

            var requestId = Guid.NewGuid();

            request.TryGetReferer(out Uri referer);
            var redirection = new Redirection
            {
                webDataRef     = requestId.AsRef <Redirection>(),
                method         = method.authenticationId,
                values         = values,
                redirectedFrom = referer,
            };

            return(await await redirection.StorageCreateAsync(
                       discard =>
            {
                return EastFive.Azure.AppSettings.Auth.PauseRedirections.ConfigurationBoolean(
                    async pauseRedirections =>
                {
                    if (pauseRedirections)
                    {
                        return request.CreateResponse(System.Net.HttpStatusCode.OK, $"All logins have been paused for this system.  Request ID `{requestId}`");
                    }
                    return await ContinueAsync();
                },
                    why => ContinueAsync(),
                    ContinueAsync);

                Task <IHttpResponse> ContinueAsync()
                {
                    var baseUri = request.RequestUri;
                    return AuthenticationAsync(
                        method, values, application, request, endpoints,
                        request.RequestUri,
                        RefOptional <Authorization> .Empty(),
                        (uri, accountIdMaybe, modifier) =>
                    {
                        var response = onRedirect(uri, accountIdMaybe);
                        return modifier(response);
                    },
                        () => onAuthorizationnotFound("Authorization not found"),
                        onCouldNotConnect,
                        onFailure);
                }
            },
                       () => onFailure("GUID NOT UNIQUE").AsTask()));
        }
        public async static Task <TResult> AuthenticationAsync <TResult>(
            EastFive.Azure.Auth.Method authentication, IDictionary <string, string> values,
            IAzureApplication application, IHttpRequest request,
            IInvokeApplication endpoints, Uri baseUri,
            IRefOptional <Authorization> authorizationRefToCreate,
            Func <Uri, Guid?, Func <IHttpResponse, IHttpResponse>, TResult> onRedirect,
            Func <TResult> onAuthorizationNotFound,
            Func <string, TResult> onCouldNotConnect,
            Func <string, TResult> onGeneralFailure)
        {
            var telemetry = application.Telemetry;

            return(await await authentication.RedeemTokenAsync(values, application,
                                                               async (externalAccountKey, authorizationRefMaybe, loginProvider, extraParams) =>
            {
                #region Handle case where there was a direct link or a POST

                if (!authorizationRefMaybe.HasValue)
                {
                    var authorization = new Authorization
                    {
                        authorizationRef = authorizationRefToCreate.HasValue?
                                           authorizationRefToCreate.Ref
                                :
                                           new Ref <Authorization>(Security.SecureGuid.Generate()),
                        Method = authentication.authenticationId,
                        parameters = extraParams,
                        authorized = true,
                    };
                    return await ProcessAsync(authorization,
                                              async(authorizationUpdated) =>
                    {
                        bool created = await authorizationUpdated.StorageCreateAsync(
                            authIdDiscard =>
                        {
                            return true;
                        },
                            () =>
                        {
                            //if(authorizationRefToCreate.HasValueNotNull())
                            //    throw new Exception("Authorization to create already exists.");
                            //throw new Exception("Duplicated update from ProcessAsync.");
                            return false;
                        });
                    },
                                              authentication, externalAccountKey, extraParams,
                                              application, request, endpoints, loginProvider, baseUri,
                                              onRedirect,
                                              onGeneralFailure,
                                              telemetry);
                }

                #endregion

                var authorizationRef = authorizationRefMaybe.Ref;
                return await authorizationRef.StorageUpdateAsync(
                    async(authorization, saveAsync) =>
                {
                    return await ProcessAsync(authorization,
                                              saveAsync,
                                              authentication, externalAccountKey, extraParams,
                                              application, request, endpoints, loginProvider, baseUri,
                                              onRedirect,
                                              onGeneralFailure,
                                              telemetry);
                },
                    () =>
                {
                    return onAuthorizationNotFound();
                });
            },
                                                               (authorizationRef, extraparams) => onGeneralFailure("Cannot use logout to authenticate").AsTask(),
                                                               (why) => onCouldNotConnect(why).AsTask(),
                                                               (why) => onGeneralFailure(why).AsTask()));
        }
        private async static Task <TResult> AuthenticationAsync <TResult>(Guid requestId,
                                                                          EastFive.Azure.Auth.Method authentication, IDictionary <string, string> values, Uri baseUri,
                                                                          AzureApplication application,
                                                                          Func <Uri, TResult> onRedirect,
                                                                          Func <TResult> onAuthorizationNotFound,
                                                                          Func <string, TResult> onCouldNotConnect,
                                                                          Func <string, TResult> onGeneralFailure)
        {
            var authorizationRequestManager = application.AuthorizationRequestManager;
            var telemetry = application.Telemetry;

            return(await await authentication.RedeemTokenAsync(values, application,
                                                               async (externalAccountKey, authorizationRefMaybe, loginProvider, extraParams) =>
            {
                #region Handle case where there was a direct link

                if (!authorizationRefMaybe.HasValue)
                {
                    var authorization = new Authorization
                    {
                        authorizationRef = new Ref <Authorization>(Security.SecureGuid.Generate()),
                        Method = authentication.authenticationId,
                        parameters = extraParams,
                        authorized = true,
                    };
                    return await ProcessAsync(authorization,
                                              async(authorizationUpdated) =>
                    {
                        bool created = await authorizationUpdated.StorageCreateAsync(
                            authIdDiscard =>
                        {
                            return true;
                        },
                            () => throw new Exception("Secure guid not unique"));
                    },
                                              authentication, externalAccountKey, extraParams,
                                              requestId, baseUri, application, loginProvider,
                                              onRedirect,
                                              onGeneralFailure,
                                              telemetry);
                }

                #endregion

                var authorizationRef = authorizationRefMaybe.Ref;
                return await authorizationRef.StorageUpdateAsync(
                    async(authorization, saveAsync) =>
                {
                    return await ProcessAsync(authorization,
                                              saveAsync,
                                              authentication, externalAccountKey, extraParams,
                                              requestId, baseUri, application, loginProvider,
                                              onRedirect,
                                              onGeneralFailure,
                                              telemetry);
                },
                    () =>
                {
                    return onAuthorizationNotFound();
                });
            },
                                                               (authorizationRef, extraparams) => onGeneralFailure("Cannot use logout to authenticate").AsTask(),
                                                               (why) => onCouldNotConnect(why).AsTask(),
                                                               (why) => onGeneralFailure(why).AsTask()));
        }