コード例 #1
0
        public static IHttpResponse ListFlows(
            [OptionalQueryParameter] string flow,
            [OptionalQueryParameter] string collections,
            [OptionalQueryParameter] bool?preferJson,
            //Security security,
            IInvokeApplication invokeApplication,
            HttpApplication httpApp, IHttpRequest request, IProvideUrl url,
            ContentTypeResponse <string []> onSuccess,
            NotFoundResponse onNotFound)
        {
            var lookups = httpApp
                          .GetResources()
                          .ToArray();

            var manifest = new EastFive.Api.Resources.Manifest(lookups, httpApp);

            var flows = manifest.Routes
                        .SelectMany(route => route.Methods)
                        .SelectMany(method => method.MethodPoco
                                    .GetAttributesInterface <IDefineFlow>(multiple: true)
                                    .Select(attr => (method, attr)))
                        .GroupBy(methodAndFlow => methodAndFlow.attr.FlowName)
                        .Where(grp => grp.Key.HasBlackSpace())
                        .Select(grp => grp.Key)
                        .ToArray();

            return(onSuccess(flows));
        }
コード例 #2
0
        public static async Task <IHttpResponse> PostAsync(
            [Property(Name = id_token)] string idToken,
            [Property(Name = state)] IRef <Authorization> authorization,
            IAzureApplication application, IProvideUrl urlHelper,
            IHttpRequest request, IInvokeApplication endpoints,
            RedirectResponse onRedirectResponse,
            ServiceUnavailableResponse onNoServiceResponse,
            BadRequestResponse onBadCredentials,
            GeneralConflictResponse onFailure)
        {
            var parameters = new Dictionary <string, string>
            {
                { id_token, idToken },
                { state, authorization.id.ToString("N") },
            };
            var method = EastFive.Azure.Auth.Method.ByMethodName(
                AzureADB2CProvider.IntegrationName, application);

            return(await EastFive.Azure.Auth.Redirection.ProcessRequestAsync(method, parameters,
                                                                             application, request, endpoints, urlHelper,
                                                                             (redirect, accountIdMaybe) => onRedirectResponse(redirect),
                                                                             (why) => onBadCredentials().AddReason($"Bad credentials:{why}"),
                                                                             (why) => onNoServiceResponse().AddReason(why),
                                                                             (why) => onFailure(why)));
        }
コード例 #3
0
        public static Task <HttpResponseMessage> InvokeAsync(IRef <InvocationMessage> invocationMessageRef,
                                                             IInvokeApplication invokeApplication,
                                                             ILogger logging = default)
        {
            logging.Trace($"Processing message [{invocationMessageRef.id}].");
            return(invocationMessageRef.StorageUpdateAsync(
                       async(invocationMessage, saveAsync) =>
            {
                var httpRequest = new HttpRequestMessage(
                    new HttpMethod(invocationMessage.method),
                    invocationMessage.requestUri);
                var config = new HttpConfiguration();
                httpRequest.SetConfiguration(config);

                foreach (var headerKVP in invocationMessage.headers)
                {
                    httpRequest.Headers.Add(headerKVP.Key, headerKVP.Value);
                }

                if (!invocationMessage.content.IsDefaultOrNull())
                {
                    httpRequest.Content = new ByteArrayContent(invocationMessage.content);
                    httpRequest.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                }

                invocationMessage.lastExecuted = DateTime.UtcNow;
                var result = await invokeApplication.SendAsync(httpRequest);
                await saveAsync(invocationMessage);
                return result;
            },
                       ResourceNotFoundException.StorageGetAsync <HttpResponseMessage>));
        }
コード例 #4
0
 public StorageResourcesProvideQuery(IInvokeApplication invokeApplication)
     : base(
         (queryProvider, type) => (queryProvider is StorageResources <TResource>) ?
         (queryProvider as StorageResources <TResource>).From()
             :
         new StorageResources <TResource>(invokeApplication),
         (queryProvider, expression, type) => (queryProvider is StorageResources <TResource>) ?
         (queryProvider as StorageResources <TResource>).FromExpression(expression)
             :
         new StorageResources <TResource>(invokeApplication, expression))
 {
 }
コード例 #5
0
 public RequestMessageProvideQuery(IInvokeApplication invokeApplication)
     : base(
         (queryProvider, type) => (queryProvider is RequestMessage <TResource>)?
         (queryProvider as RequestMessage <TResource>).From()
             :
         new RequestMessage <TResource>(invokeApplication),
         (queryProvider, expression, type) => (queryProvider is RequestMessage <TResource>) ?
         (queryProvider as RequestMessage <TResource>).FromExpression(expression)
             :
         new RequestMessage <TResource>(invokeApplication, expression))
 {
 }
コード例 #6
0
        public static async Task <IHttpResponse> Post(
            [PropertyOptional(Name = StatePropertyName)] string state,
            [PropertyOptional(Name = CodePropertyName)] string code,
            [PropertyOptional(Name = TokenPropertyName)] string token,
            [PropertyOptional(Name = UserPropertyName)] string user,
            IAzureApplication application,
            IHttpRequest request,
            IProvideUrl urlHelper,
            IInvokeApplication endpoints,
            RedirectResponse onRedirectResponse,
            BadRequestResponse onBadCredentials,
            HtmlResponse onCouldNotConnect,
            HtmlResponse onGeneralFailure)
        {
            var method = EastFive.Azure.Auth.Method.ByMethodName(
                AppleProvider.IntegrationName, application);
            var requestParams = new Dictionary <string, string>();

            if (state.HasBlackSpace())
            {
                requestParams.Add(AppleProvider.responseParamState, state);
            }
            if (code.HasBlackSpace())
            {
                requestParams.Add(AppleProvider.responseParamCode, code);
            }
            if (token.HasBlackSpace())
            {
                requestParams.Add(AppleProvider.responseParamIdToken, token);
            }
            if (user.HasBlackSpace())
            {
                requestParams.Add(AppleProvider.responseParamUser, user);
            }

            return(await ProcessRequestAsync(method,
                                             requestParams,
                                             application, request, endpoints, urlHelper,
                                             (redirect, accountIdMaybe) =>
            {
                return onRedirectResponse(redirect);
            },
                                             (why) => onBadCredentials().AddReason(why),
                                             (why) =>
            {
                return onCouldNotConnect(why);
            },
                                             (why) =>
            {
                return onGeneralFailure(why);
            }));
        }
コード例 #7
0
        //private static Task<TResult> UnmappedCredentialAsync<TResult>(
        //        string subject, IDictionary<string, string> extraParams,
        //        EastFive.Azure.Auth.Method authentication, Authorization authorization,
        //        IProvideAuthorization authorizationProvider,
        //        IAuthApplication 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 <TResult> MapAccountAsync <TResult>(Authorization authorization,
                                                                     Guid internalAccountId, string externalAccountKey,
                                                                     IInvokeApplication endpoints,
                                                                     Uri baseUri,
                                                                     AzureApplication application, IHttpRequest request,
                                                                     Func <Uri, TResult> onRedirect,
                                                                     Func <string, TResult> onFailure,
                                                                     TelemetryClient telemetry)
        {
            // applies when intercept process is used
            if (authorization.accountIdMaybe.IsDefault())
            {
                authorization = await authorization.authorizationRef.StorageUpdateAsync(
                    async (a, saveAsync) =>
                {
                    a.accountIdMaybe = internalAccountId;
                    await saveAsync(a);
                    return(a);
                });
            }

            return(await await AccountMapping.CreateByMethodAndKeyAsync(authorization, externalAccountKey,
                                                                        internalAccountId,
                                                                        ProcessAsync,
                                                                        ProcessAsync));

            async Task <TResult> ProcessAsync()
            {
                return(await await Method.ById(authorization.Method, application,
                                               async method =>
                {
                    return await await method.GetLoginProviderAsync(application,
                                                                    (loginProviderMethodName, loginProvider) =>
                    {
                        return CreateLoginResponseAsync(
                            internalAccountId, authorization.parameters,
                            method, authorization,
                            application, request, endpoints, baseUri, loginProvider,
                            (url, modifier) => onRedirect(url),
                            onFailure,
                            telemetry);
                    },
                                                                    () =>
                    {
                        return onFailure("Login provider is no longer supported by the system").AsTask();
                    });
                },
                                               () => onFailure("Method no longer suppored.").AsTask()));
            }
        }
コード例 #8
0
        public static async Task <IHttpResponse> Post(
            [Property(Name = StatePropertyName)] string state,
            [PropertyOptional(Name = CodePropertyName)] string code,
            [Property(Name = TokenPropertyName)] string token,
            AzureApplication application,
            IHttpRequest request,
            IProvideUrl urlHelper,
            IInvokeApplication endpoints,
            RedirectResponse onRedirectResponse,
            BadRequestResponse onBadCredentials,
            HtmlResponse onCouldNotConnect,
            HtmlResponse onGeneralFailure)
        {
            var method = EastFive.Azure.Auth.Method.ByMethodName(
                AzureADB2CProvider.IntegrationName, application);
            var requestParams = request.RequestUri
                                .ParseQuery()
                                .Distinct(kvp => kvp.Key)
                                .ToDictionary();

            if (state.HasBlackSpace())
            {
                requestParams.Add(StatePropertyName, state);
            }
            if (code.HasBlackSpace())
            {
                requestParams.Add(CodePropertyName, code);
            }
            if (token.HasBlackSpace())
            {
                requestParams.Add(TokenPropertyName, token);
            }

            return(await ProcessRequestAsync(method,
                                             requestParams,
                                             application, request, endpoints, urlHelper,
                                             (redirect, accountIdMaybe) =>
            {
                return onRedirectResponse(redirect);
            },
                                             (why) => onBadCredentials().AddReason(why),
                                             (why) =>
            {
                return onCouldNotConnect(why);
            },
                                             (why) =>
            {
                return onGeneralFailure(why);
            }));
        }
コード例 #9
0
        public static async Task <IHttpResponse> ReplayAsync(
            [QueryId(Name = AuthorizationIdPropertyName)] IRef <Authorization> authorizationRef,
            Api.Azure.AzureApplication application,
            IInvokeApplication endpoints,
            IHttpRequest request,
            ContentTypeResponse <Session> onReplayed,
            NotFoundResponse onNotFound,
            ForbiddenResponse onAuthorizationFailed,
            ServiceUnavailableResponse onServericeUnavailable,
            ForbiddenResponse onInvalidMethod,
            GeneralConflictResponse onFailure)
        {
            return(await await authorizationRef.StorageGetAsync(
                       async (authorization) =>
            {
                var methodRef = authorization.Method;
                return await await Auth.Method.ById(methodRef, application,
                                                    async(method) =>
                {
                    var paramsUpdated = authorization.parameters
                                        .Append(authorizationRef.id.ToString().PairWithKey("state"))
                                        .ToDictionary();

                    //var authorizationRequestManager = application.AuthorizationRequestManager;
                    return await await Redirection.AuthenticationAsync(
                        method,
                        paramsUpdated,
                        application, request,
                        endpoints,
                        request.RequestUri,
                        authorizationRef.Optional(),
                        async(redirect, accountIdMaybe, modifier) =>
                    {
                        var sessionRef = Ref <Session> .SecureRef();
                        var session = new Session()
                        {
                            sessionId = sessionRef,
                            account = accountIdMaybe,
                            authorization = authorizationRef.Optional(),
                        };
                        var responseCreated = await Session.CreateAsync(sessionRef, authorizationRef.Optional(),
                                                                        session,
                                                                        application,
                                                                        (sessionCreated, contentType) =>
                        {
                            var response = onReplayed(sessionCreated, contentType: contentType);
                            response.SetLocation(redirect);
                            return response;
                        },
                                                                        onAlreadyExists: default,
コード例 #10
0
        public static async Task <TResult> ProcessAsync <TResult>(Authorization authorization,
                                                                  Func <Authorization, Task> saveAsync,
                                                                  Method authenticationMethod, string externalAccountKey,
                                                                  IDictionary <string, string> extraParams,
                                                                  IAzureApplication application, IHttpRequest request,
                                                                  IInvokeApplication endpoints, IProvideLogin loginProvider,
                                                                  Uri baseUri,
                                                                  Func <Uri, Guid?, Func <IHttpResponse, IHttpResponse>, TResult> onRedirect,
                                                                  Func <string, TResult> onGeneralFailure,
                                                                  TelemetryClient telemetry)
        {
            return(await await AuthorizeWithAccountAsync(
                       authorization, saveAsync,
                       authenticationMethod, externalAccountKey, extraParams,
                       application, request, loginProvider, baseUri,

                       onAccountLocated : (internalAccountId, authorizationUpdated) =>
            {
                return CreateLoginResponseAsync(
                    internalAccountId, extraParams,
                    authenticationMethod, authorizationUpdated,
                    application, request, endpoints, baseUri, loginProvider,
                    (url, modifier) =>
                {
                    // await saveAsync(authorization);
                    return onRedirect(url, internalAccountId, modifier);
                },
                    (why) =>
                {
                    //await saveAsync(authorization);
                    return onGeneralFailure(why);
                },
                    telemetry);
            },

                       onInterupted : (interceptionUrl, internalAccountId, authorizationUpdated) =>
            {
                return onRedirect(interceptionUrl, internalAccountId, m => m).AsTask();
            },

                       onGeneralFailure : (why, authorizationUpdated) =>
            {
                return onGeneralFailure(why).AsTask();
            },
                       telemetry : telemetry));
        }
コード例 #11
0
 public static IEnumerableAsync <HttpResponseMessage> InvokeAsync(
     byte [] invocationMessageIdsBytes,
     IApplication application,
     IInvokeApplication invokeApplication,
     EastFive.Analytics.ILogger analyticsLog = default)
 {
     return(invocationMessageIdsBytes
            .Split(index => 16)
            .Select(
                invocationMessageIdBytes =>
     {
         var idBytes = invocationMessageIdBytes.ToArray();
         var invocationMessageId = new Guid(idBytes);
         var invocationMessageRef = invocationMessageId.AsRef <InvocationMessage>();
         return InvokeAsync(invocationMessageRef, invokeApplication, analyticsLog);
     })
            .Parallel());
 }
コード例 #12
0
        //public static async Task<TResult> LegacyAccountMappingAsync<TResult>(Authorization authorization,
        //        Method authenticationMethod, string externalAccountKey,
        //        IDictionary<string, string> extraParams,
        //        IAzureApplication application,
        //        IProvideLogin loginProvider,
        //        Uri baseUri,
        //    Func<Guid, Func<bool, Task<TResult>>, TResult> onLocated,
        //    Func<Guid, TResult> onCreated,
        //    Func<TResult> onSelfServe,
        //    Func<Uri, TResult> onInterupted,
        //    Func<string, TResult> onGeneralFailure,
        //        TelemetryClient telemetry)
        //{
        //    return await await AccountMapping.FindByMethodAndKeyAsync(
        //            authenticationMethod.authenticationId, externalAccountKey,
        //            authorization,
        //            // Found
        //        internalAccountId =>
        //        {
        //            return onLocated(
        //                    internalAccountId,
        //                    (isAccountInvalid) => OnNotFound(isAccountInvalid))
        //                .AsTask();
        //        },
        //        () => OnNotFound(false));

        //    async Task<TResult> OnNotFound(bool isAccountInvalid)
        //    {
        //        return await await UnmappedCredentialAsync(externalAccountKey, extraParams,
        //                    authenticationMethod, authorization,
        //                    loginProvider, application, baseUri,

        //                // Create mapping
        //                (internalAccountId) =>
        //                {
        //                    return AccountMapping.CreateByMethodAndKeyAsync(
        //                            authorization, externalAccountKey, internalAccountId,
        //                        () =>
        //                        {
        //                            return onCreated(internalAccountId);
        //                        },
        //                        () =>
        //                        {
        //                            return onLocated(internalAccountId, default);
        //                        },
        //                            isAccountInvalid);
        //                },

        //                // Allow self serve
        //                () =>
        //                {
        //                    return onSelfServe().AsTask();
        //                },

        //                // Intercept process
        //                (interceptionUrl) =>
        //                {
        //                    return onInterupted(interceptionUrl).AsTask();
        //                },

        //                // Failure
        //                (why) =>
        //                {
        //                    return onGeneralFailure(why).AsTask();
        //                },
        //                telemetry);
        //    }
        //}

        private static Task <TResult> CreateLoginResponseAsync <TResult>(
            Guid?accountId, IDictionary <string, string> extraParams,
            Method method, Authorization authorization,
            IAuthApplication application,
            IHttpRequest request, IInvokeApplication endpoints,
            Uri baseUrl,
            IProvideAuthorization authorizationProvider,
            Func <Uri, Func <IHttpResponse, IHttpResponse>, TResult> onRedirect,
            Func <string, TResult> onBadResponse,
            TelemetryClient telemetry)
        {
            return(application.GetRedirectUriAsync(
                       accountId, extraParams,
                       method, authorization,
                       request, endpoints,
                       baseUrl,
                       authorizationProvider,
                       (redirectUrlSelected, modifier) =>
            {
                telemetry.TrackEvent($"CreateResponse - redirectUrlSelected1: {redirectUrlSelected.AbsolutePath}");
                telemetry.TrackEvent($"CreateResponse - redirectUrlSelected2: {redirectUrlSelected.AbsoluteUri}");
                return onRedirect(redirectUrlSelected, modifier);
            },
                       (paramName, why) =>
            {
                var message = $"Invalid parameter while completing login: {paramName} - {why}";
                telemetry.TrackException(new ResponseException(message));
                return onBadResponse(message);
            },
                       () =>
            {
                var message = $"Invalid account while completing login";
                telemetry.TrackException(new ResponseException(message));
                return onBadResponse(message);
            },
                       (why) =>
            {
                var message = $"General failure while completing login: {why}";
                telemetry.TrackException(new ResponseException(message));
                return onBadResponse(message);
            }));
        }
コード例 #13
0
        public async static Task <IHttpResponse> AuthorizeAsync(
            [QueryParameter(Name = "session")]
            IRef <Session> sessionRef,

            [UpdateId(Name = AuthorizationIdPropertyName)]
            IRef <Authorization> authorizationRef,

            [Property(Name = ParametersPropertyName)]
            IDictionary <string, string> parameters,

            Api.Azure.AzureApplication application,
            IInvokeApplication endpoints,
            IHttpRequest request,
            CreatedBodyResponse <Session> onCreated,
            NotFoundResponse onAuthorizationDoesNotExist,
            ForbiddenResponse onAuthorizationFailed,
            ServiceUnavailableResponse onServiceUnavailable,
            ForbiddenResponse onInvalidMethod,
            GeneralConflictResponse onFailure)
        {
            return(await await authorizationRef.StorageGetAsync(
                       (authorization) =>
            {
                return AuthenticateWithSessionAsync(authorizationRef, sessionRef,
                                                    authorization.Method, parameters,
                                                    application, endpoints, request,
                                                    onAuthorized: (sessionCreated, redirect) =>
                {
                    var response = onCreated(sessionCreated, contentType: "application/json");
                    response.SetLocation(redirect);
                    return response;
                },
                                                    onAuthorizationDoesNotExist: () => onAuthorizationDoesNotExist(),
                                                    onServiceUnavailable: (why) => onServiceUnavailable().AddReason(why),
                                                    onInvalidMethod: (why) => onInvalidMethod().AddReason(why),
                                                    onAuthorizationFailed: why => onAuthorizationFailed().AddReason(why));
            },
                       () => onAuthorizationDoesNotExist().AsTask()));
        }
コード例 #14
0
        public static async Task <IHttpResponse> Get(
            //[QueryParameter(Name = ProvideLoginMock.extraParamState)]IRefOptional<Authorization> authorizationRef,
            //[QueryParameter(Name = ProvideLoginMock.extraParamToken)]string token,
            IAzureApplication application, IProvideUrl urlHelper,
            IInvokeApplication endpoints,
            IHttpRequest request,
            RedirectResponse onRedirectResponse,
            ServiceUnavailableResponse onNoServiceResponse,
            BadRequestResponse onBadCredentials,
            GeneralConflictResponse onFailure)
        {
            var parameters = request.RequestUri.ParseQuery();
            var method     = EastFive.Azure.Auth.Method.ByMethodName(
                AzureADB2CProvider.IntegrationName, application);

            return(await EastFive.Azure.Auth.Redirection.ProcessRequestAsync(method, parameters,
                                                                             application, request, endpoints, urlHelper,
                                                                             (redirect, accountIdMaybe) => onRedirectResponse(redirect),
                                                                             (why) => onBadCredentials().AddReason($"Bad credentials:{why}"),
                                                                             (why) => onNoServiceResponse().AddReason(why),
                                                                             (why) => onFailure(why)));
        }
コード例 #15
0
        public async static Task <IHttpResponse> CreateAuthorizedAsync(
            [UpdateId(Name = AuthorizationIdPropertyName)] IRef <Authorization> authorizationRef,
            [Property(Name = MethodPropertyName)] IRef <Method> methodRef,
            [Property(Name = ParametersPropertyName)] IDictionary <string, string> parameters,
            [Resource] Authorization authorization,
            Api.Azure.AzureApplication application, IProvideUrl urlHelper,
            IInvokeApplication endpoints,
            IHttpRequest request,
            CreatedResponse onCreated,
            AlreadyExistsResponse onAlreadyExists,
            ForbiddenResponse onAuthorizationFailed,
            ServiceUnavailableResponse onServericeUnavailable,
            ForbiddenResponse onInvalidMethod)
        {
            authorization.accountIdMaybe = default;
            authorization.authorized     = false;
            return(await await Auth.Method.ById(methodRef, application,
                                                (method) =>
            {
                var paramsUpdated = parameters;
                //.Append(
                //    authorizationRef.id.ToString().PairWithKey("state"))
                //.ToDictionary();

                return Redirection.AuthenticationAsync(
                    method,
                    paramsUpdated,
                    application, request, endpoints, request.RequestUri,
                    authorizationRef.Optional(),
                    (redirect, accountIdMaybe, discardModifier) => onCreated(),
                    () => onAuthorizationFailed().AddReason("Authorization was not found"),     // Bad credentials
                    why => onServericeUnavailable().AddReason(why),
                    why => onAuthorizationFailed().AddReason(why));
            },
                                                () => onInvalidMethod().AddReason("The method was not found.").AsTask()));
        }
コード例 #16
0
        public static async Task <IHttpResponse> PatchAsync(
            IAzureApplication application, IProvideUrl urlHelper,
            IHttpRequest request,
            IInvokeApplication endpoints,
            RedirectResponse onRedirectResponse,
            ServiceUnavailableResponse onNoServiceResponse,
            BadRequestResponse onBadCredentials,
            GeneralConflictResponse onFailure)
        {
            var parameters = request.RequestUri.ParseQuery();

            parameters.Add(CredentialProvider.referrerKey, request.RequestUri.AbsoluteUri);
            var authentication = EastFive.Azure.Auth.Method.ByMethodName(
                CredentialProvider.IntegrationName, application);

            return(await EastFive.Azure.Auth.Redirection.ProcessRequestAsync(authentication,
                                                                             parameters,
                                                                             application,
                                                                             request, endpoints, urlHelper,
                                                                             (redirect, accountIdMaybe) => onRedirectResponse(redirect).AddReason("success"),
                                                                             (why) => onBadCredentials().AddReason($"Bad credentials:{why}"),
                                                                             (why) => onNoServiceResponse().AddReason(why),
                                                                             (why) => onFailure(why)));
        }
コード例 #17
0
        public async static Task <IHttpResponse> CreateAuthorizedAsync(
            [WorkflowNewId]
            [QueryParameter(Name = "session")]
            IRef <Session> sessionRef,

            [WorkflowParameterFromVariable(
                 Value = Workflows.PasswordLoginCreateAccount.Variables.Authorization)]
            [UpdateId(Name = AuthorizationIdPropertyName)]
            IRef <Authorization> authorizationRef,

            [WorkflowParameter(Value = "80a7de99-1307-9633-a7b8-ed70578ac6ae")]
            [Property(Name = MethodPropertyName)]
            IRef <Method> methodRef,

            [WorkflowObjectParameter(
                 Key0 = "state", Value0 = "{{InternalAuthState}}",
                 Key1 = "token", Value1 = "{{InternalAuthToken}}")]
            [Property(Name = ParametersPropertyName)]
            IDictionary <string, string> parameters,

            Api.Azure.AzureApplication application,
            IInvokeApplication endpoints,
            IHttpRequest request,
            [WorkflowVariable(Workflows.PasswordLoginCreateAccount.Variables.AccountId, PropertyName = Session.AccountPropertyName)]
            CreatedBodyResponse <Session> onCreated,

            AlreadyExistsResponse onAlreadyExists,
            ForbiddenResponse onAuthorizationFailed,
            ServiceUnavailableResponse onServiceUnavailable,
            ForbiddenResponse onInvalidMethod,
            GeneralConflictResponse onFailure)
        {
            return(await AuthenticateWithSessionAsync(authorizationRef, sessionRef,
                                                      methodRef, parameters,
                                                      application, endpoints, request,
                                                      onAuthorized : (sessionCreated, redirect) =>
            {
                var response = onCreated(sessionCreated, contentType: "application/json");
                response.SetLocation(redirect);
                return response;
            },
                                                      onAuthorizationDoesNotExist : () => onAuthorizationFailed()
                                                      .AddReason("Authorization does not exists"),
                                                      onServiceUnavailable : (why) => onServiceUnavailable().AddReason(why),
                                                      onInvalidMethod : (why) => onInvalidMethod().AddReason(why),
                                                      onAuthorizationFailed : why => onAuthorizationFailed().AddReason(why)));

            //return await await Auth.Method.ById(methodRef, application,
            //    async (method) =>
            //    {
            //        var paramsUpdated = parameters
            //            .Append(
            //                authorizationRef.id.ToString().PairWithKey("state"))
            //            .ToDictionary();
            //        //var authorizationRequestManager = application.AuthorizationRequestManager;
            //        return await await Redirection.AuthenticationAsync(
            //                method,
            //                paramsUpdated,
            //                application, request,
            //                endpoints,
            //                request.RequestUri,
            //                authorizationRef.Optional(),
            //            async (redirect, accountIdMaybe, modifier) =>
            //            {
            //                var session = new Session()
            //                {
            //                    sessionId = sessionRef,
            //                    account = accountIdMaybe,
            //                    authorization = authorizationRef.Optional(),
            //                };
            //                var responseCreated = await Session.CreateAsync(sessionRef, authorizationRef.Optional(),
            //                        session,
            //                        application,
            //                    (sessionCreated, contentType) =>
            //                    {
            //                        var response = onCreated(sessionCreated, contentType: contentType);
            //                        response.SetLocation(redirect);
            //                        return response;
            //                    },
            //                    onAlreadyExists,
            //                    onAuthorizationFailed,
            //                    (why1, why2) => onServericeUnavailable(),
            //                    onFailure);
            //                var modifiedResponse = modifier(responseCreated);
            //                return modifiedResponse;
            //            },
            //            () => onAuthorizationFailed()
            //                .AddReason("Authorization was not found")
            //                .AsTask(), // Bad credentials
            //            why => onServericeUnavailable()
            //                .AddReason(why)
            //                .AsTask(),
            //            why => onAuthorizationFailed()
            //                .AddReason(why)
            //                .AsTask());
            //    },
            //    () => onInvalidMethod().AddReason("The method was not found.").AsTask());
        }
コード例 #18
0
        public static async Task <IHttpResponse> Get(
            [OptionalQueryParameter(CheckFileName = true)] string tag,
            [QueryParameter(Name = TokenIdPropertyName)] string tokenId,
            [QueryParameter(Name = AgentIdPropertyName)] string agentId,
            AzureApplication application,
            IHttpRequest request,
            IProvideUrl urlHelper,
            IInvokeApplication endpoints,
            RedirectResponse onRedirectResponse,
            BadRequestResponse onBadCredentials,
            HtmlResponse onCouldNotConnect,
            HtmlResponse onGeneralFailure)
        {
            //The way this works...
            //1.  User clicks Third Party Applications\AffirmHealth over in Athena.
            //2.  Athena calls Ping
            //3.  Ping redirects to /PingResponseController with a token.
            //4.  This code validates the token, parses it out, and redirects to the interactive report matching the patient id.

            //To debug, you have to grab the token from Ping that comes in here.  If you don't, the token will get used and it won't work again
            //To do this, uncomment the commented line and comment out the call to ParsePingResponseAsync.  That way the token won't be used.
            //After the uncomment/comment, publish to dev and then click third party apps\Affirm Health in Athena.
            //Grab the token from the browser.
            //Then, switch the uncommented/commented lines back and run the server in debug.
            //Send the token via Postman to debug and see any errors that might come back from Ping.

            //return onRedirectResponse(new Uri("https://www.google.com"));

            if (tag.IsNullOrWhiteSpace())
            {
                tag = "OpioidTool";
            }

            var methodName = PingProvider.IntegrationName;
            var method     = EastFive.Azure.Auth.Method.ByMethodName(methodName, application);

            var failureHtml = "<html><title>{0}</title><body>{1} Please report:<code>{2}</code> to Affirm Health if the issue persists.</body></html>";

            return(await EastFive.Web.Configuration.Settings.GetString($"AffirmHealth.PDMS.PingRedirect.{tag}.PingAuthName",
                                                                       async pingAuthName =>
            {
                return await EastFive.Web.Configuration.Settings.GetGuid($"AffirmHealth.PDMS.PingRedirect.{tag}.PingReportSetId",
                                                                         async reportSetId =>
                {
                    var requestParams = request.RequestUri
                                        .ParseQuery()
                                        .Append("PingAuthName".PairWithValue(pingAuthName))
                                        .Append("ReportSetId".PairWithValue(reportSetId.ToString()))
                                        .ToDictionary();

                    return await Redirection.ProcessRequestAsync(method,
                                                                 requestParams,
                                                                 application, request, endpoints, urlHelper,
                                                                 (redirect, accountIdMaybe) =>
                    {
                        return onRedirectResponse(redirect);
                    },
                                                                 (why) => onBadCredentials().AddReason(why),
                                                                 (why) =>
                    {
                        var failureText = String.Format(failureHtml,
                                                        "PING/ATHENA credential service offline",
                                                        "Could not connect to PING (the authorization service used by Athena) to verify the provided link. Affirm Health will work with Athena/Ping to resolve this issue.",
                                                        why);
                        return onCouldNotConnect(why);
                    },
                                                                 (why) =>
                    {
                        var failureText = String.Format(failureHtml,
                                                        "Failed to authenticate",
                                                        "You could not be authenticated.",
                                                        why);
                        return onGeneralFailure(why);
                    });
                },
                                                                         why =>
                {
                    return onGeneralFailure(why).AsTask();
                });
            },
                                                                       why =>
            {
                return onGeneralFailure(why).AsTask();
            }));
        }
コード例 #19
0
        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()));
        }
コード例 #20
0
        public static IHttpResponse GetSchema(
            [OptionalQueryParameter] string collections,
            //Security security,
            IInvokeApplication invokeApplication,
            HttpApplication httpApp, IHttpRequest request, IProvideUrl url,
            TextResponse onSuccess)
        {
            var lookups = httpApp
                          .GetResources()
                          .Where(
                resource =>
            {
                if (collections.IsNullOrWhiteSpace())
                {
                    return(true);
                }
                var collection = resource.TryGetAttributeInterface(out IDocumentOpenApiRoute documentOpenApiRoute) ?
                                 documentOpenApiRoute.Collection
                            :
                                 resource.Namespace;
                return(collection.StartsWith(collections, StringComparison.OrdinalIgnoreCase));
            })
                          .ToArray();
            var manifest = new EastFive.Api.Resources.Manifest(lookups, httpApp);

            var sb             = new StringBuilder();
            var sw             = new StringWriter(sb);
            var jsonSerializer = new JsonSerializer();

            var server = new Server
            {
                url = invokeApplication.ServerLocation.AbsoluteUri.TrimEnd('/'),
            };
            var info = new Info
            {
                license = new License
                {
                    name = "Private"
                },
                title   = $"{httpApp.GetType().Namespace}",
                version = "1.2.3",
            };

            using (JsonWriter writer = new JsonTextWriter(sw))
            {
                writer.Formatting = Formatting.Indented;

                writer.WriteStartObject();
                writer.WritePropertyName("openapi");
                writer.WriteValue("3.0.0");
                writer.WritePropertyName("info");
                jsonSerializer.Serialize(writer, info);
                writer.WritePropertyName("servers");
                jsonSerializer.Serialize(writer, server.AsArray());
                writer.WritePropertyName("paths");
                writer.WriteStartObject();

                var schemas = new Dictionary <string, Resources.Parameter[]>();

                foreach (var route in manifest.Routes)
                {
                    foreach (var methodPathGrp in route.Methods.GroupBy(method => method.Path.OriginalString))
                    {
                        writer.WritePropertyName(methodPathGrp.Key);
                        writer.WriteStartObject();
                        foreach (var actionGrp in methodPathGrp.GroupBy(method => method.HttpMethod))
                        {
                            var action    = actionGrp.First();
                            var responses = action.Responses
                                            .Where(response => !response.StatusCode.IsDefault())
                                            .GroupBy(response => response.StatusCode);
                            if (!responses.Any())
                            {
                                continue;
                            }
                            writer.WritePropertyName(actionGrp.Key.ToLower());
                            writer.WriteStartObject();
                            writer.WritePropertyName("description");
                            writer.WriteValue(action.Description);
                            writer.WritePropertyName("operationId");
                            writer.WriteValue(action.Name);
                            var queryParams = action.Parameters
                                              .Where(p => "QUERY".Equals(p.Where, StringComparison.OrdinalIgnoreCase))
                                              .ToArray();
                            if (queryParams.Any())
                            {
                                writer.WritePropertyName("parameters");
                                writer.WriteStartArray();
                                foreach (var parameter in queryParams)
                                {
                                    writer.WriteStartObject();
                                    writer.WritePropertyName("name");
                                    writer.WriteValue(parameter.Name);
                                    writer.WritePropertyName("in");
                                    writer.WriteValue(parameter.Where.ToLower());
                                    if (parameter.Description.HasBlackSpace())
                                    {
                                        writer.WritePropertyName("description");
                                        writer.WriteValue(parameter.Description);
                                    }
                                    writer.WritePropertyName("required");
                                    writer.WriteValue(parameter.Required);
                                    //writer.WritePropertyName("style");
                                    //writer.WriteValue("form");
                                    writer.WritePropertyName("schema");
                                    writer.WriteStartObject();
                                    if (parameter.OpenApiType.array)
                                    {
                                        writer.WritePropertyName("type");
                                        writer.WriteValue("array");
                                        writer.WritePropertyName("items");
                                        writer.WriteStartObject();
                                        writer.WritePropertyName("type");
                                        writer.WriteValue(parameter.OpenApiType.type);
                                        writer.WriteEndObject();
                                    }
                                    else
                                    {
                                        writer.WritePropertyName("type");
                                        writer.WriteValue(parameter.OpenApiType.type);
                                        if (parameter.OpenApiType.format.HasBlackSpace())
                                        {
                                            writer.WritePropertyName("format");
                                            writer.WriteValue(parameter.OpenApiType.format);
                                        }
                                        if (parameter.OpenApiType.contentEncoding.HasBlackSpace())
                                        {
                                            writer.WritePropertyName("contentEncoding");
                                            writer.WriteValue(parameter.OpenApiType.contentEncoding);
                                        }
                                    }
                                    writer.WriteEndObject();
                                    writer.WriteEndObject();
                                }
                                writer.WriteEndArray();
                            }

                            var formParams = action.Parameters
                                             .Where(p => "BODY".Equals(p.Where, StringComparison.OrdinalIgnoreCase))
                                             .ToArray();
                            if (formParams.Any())
                            {
                                var key = $"{route.Name}{action.Name}";
                                writer.WritePropertyName("requestBody");
                                writer.WriteStartObject();
                                writer.WritePropertyName("content");
                                writer.WriteStartObject();
                                writer.WritePropertyName("application/json");
                                writer.WriteStartObject();
                                writer.WritePropertyName("schema");
                                writer.WriteStartObject();
                                writer.WritePropertyName("$ref");
                                writer.WriteValue($"#/components/schemas/{key}");
                                writer.WriteEndObject();
                                writer.WriteEndObject();
                                writer.WriteEndObject();
                                writer.WriteEndObject();
                                schemas.TryAdd(key, formParams);
                            }

                            writer.WritePropertyName("responses");
                            writer.WriteStartObject();
                            foreach (var responseGrp in responses)
                            {
                                writer.WritePropertyName($"{(int)responseGrp.Key}");
                                writer.WriteStartObject();
                                writer.WritePropertyName("description");
                                var description = responseGrp.Select(response => response.Name).Join(" or ");
                                writer.WriteValue(description);
                                writer.WriteEndObject();
                            }
                            writer.WriteEndObject();

                            writer.WriteEndObject();
                        }
                        writer.WriteEndObject();
                    }
                }

                writer.WriteEndObject();

                writer.WritePropertyName("components");
                writer.WriteStartObject();
                writer.WritePropertyName("schemas");
                writer.WriteStartObject();
                foreach (var schema in schemas)
                {
                    writer.WritePropertyName(schema.Key);
                    writer.WriteStartObject();
                    writer.WritePropertyName("type");
                    writer.WriteValue("object");
                    var properties = schema.Value
                                     .Distinct(s => s.Name)
                                     .ToArray();
                    var requiredArray = properties
                                        .Where(s => s.Required)
                                        .Select(s => s.Name)
                                        .ToArray();
                    if (requiredArray.Any())
                    {
                        writer.WritePropertyName("required");
                        jsonSerializer.Serialize(writer, requiredArray);
                    }
                    writer.WritePropertyName("properties");
                    writer.WriteStartObject();
                    foreach (var prop in properties)
                    {
                        writer.WritePropertyName(prop.Name);
                        writer.WriteStartObject();
                        writer.WritePropertyName("type");
                        writer.WriteValue(prop.OpenApiType.type);
                        if (prop.OpenApiType.format.HasBlackSpace())
                        {
                            writer.WritePropertyName("format");
                            writer.WriteValue(prop.OpenApiType.format);
                        }
                        if (prop.OpenApiType.contentEncoding.HasBlackSpace())
                        {
                            writer.WritePropertyName("contentEncoding");
                            writer.WriteValue(prop.OpenApiType.contentEncoding);
                        }
                        writer.WriteEndObject();
                    }
                    writer.WriteEndObject();
                    writer.WriteEndObject();
                }
                writer.WriteEndObject();
                writer.WriteEndObject();

                writer.WriteEndObject();
            }

            var json = sb.ToString();

            return(onSuccess(json, contentType: "application/json"));
        }
コード例 #21
0
        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()));
        }
コード例 #22
0
 private StorageResources(IInvokeApplication invokeApplication, Expression expr)
     : base(new StorageResourcesProvideQuery(invokeApplication), expr)
 {
     this.InvokeApplication = invokeApplication;
 }
コード例 #23
0
 public StorageResources(IInvokeApplication invokeApplication)
     : base(new StorageResourcesProvideQuery(invokeApplication))
 {
     this.InvokeApplication = invokeApplication;
 }
コード例 #24
0
        public static async Task <IHttpResponse> Redirected(
            [QueryParameter(Name = StatePropertyName)] string state,
            [QueryParameter(Name = CodePropertyName)] string code,
            [QueryParameter(Name = ScopePropertyName)] string scope,
            [OptionalQueryParameter(Name = AuthUserPropertyName)] string authUser,
            [OptionalQueryParameter(Name = PromptPropertyName)] string prompt,
            [OptionalQueryParameter(Name = HdPropertyName)] string hd,
            IAzureApplication application,
            IHttpRequest request,
            IProvideUrl urlHelper,
            IInvokeApplication endpoints,
            RedirectResponse onRedirectResponse,
            BadRequestResponse onBadCredentials,
            HtmlResponse onCouldNotConnect,
            HtmlResponse onGeneralFailure)
        {
            var method = EastFive.Azure.Auth.Method.ByMethodName(
                GoogleProvider.IntegrationName, application);
            var requestParams = new Dictionary <string, string>();

            if (state.HasBlackSpace())
            {
                requestParams.Add(GoogleProvider.responseParamState, state);
            }
            if (code.HasBlackSpace())
            {
                requestParams.Add(GoogleProvider.responseParamCode, code);
            }
            if (scope.HasBlackSpace())
            {
                requestParams.Add(GoogleProvider.responseParamScope, scope);
            }
            if (authUser.HasBlackSpace())
            {
                requestParams.Add(AuthUserPropertyName, authUser);
            }
            if (prompt.HasBlackSpace())
            {
                requestParams.Add(PromptPropertyName, prompt);
            }
            if (hd.HasBlackSpace())
            {
                requestParams.Add(HdPropertyName, hd);
            }

            var builder = new UriBuilder(request.RequestUri);

            builder.Query = string.Empty;
            requestParams.Add(GoogleProvider.responseParamRedirectUri, builder.Uri.AbsoluteUri);

            return(await ProcessRequestAsync(method,
                                             requestParams,
                                             application, request, endpoints, urlHelper,
                                             (redirect, accountIdMaybe) =>
            {
                return onRedirectResponse(redirect);
            },
                                             (why) => onBadCredentials().AddReason(why),
                                             (why) =>
            {
                return onCouldNotConnect(why);
            },
                                             (why) =>
            {
                return onGeneralFailure(why);
            }));
        }
コード例 #25
0
 private RequestMessage(IInvokeApplication invokeApplication, Expression expr)
     : base(new RequestMessageProvideQuery(invokeApplication), expr)
 {
     this.InvokeApplication = invokeApplication;
 }
コード例 #26
0
 public RequestMessage(IInvokeApplication invokeApplication)
     : base(new RequestMessageProvideQuery(invokeApplication))
 {
     this.InvokeApplication = invokeApplication;
 }
コード例 #27
0
        public static IHttpResponse GetSchema(
            [QueryParameter] string flow,
            [OptionalQueryParameter] string collections,
            [OptionalQueryParameter] bool?preferJson,
            //Security security,
            IInvokeApplication invokeApplication,
            HttpApplication httpApp, IHttpRequest request, IProvideUrl url,
            ContentTypeResponse <Resources.Collection.Collection> onSuccess,
            NotFoundResponse onNotFound)
        {
            var lookups = httpApp
                          .GetResources()
                          .Where(
                resource =>
            {
                if (collections.IsNullOrWhiteSpace())
                {
                    return(true);
                }
                var collection = resource.TryGetAttributeInterface(
                    out EastFive.Api.Meta.OpenApi.IDocumentOpenApiRoute documentOpenApiRoute) ?
                                 documentOpenApiRoute.Collection
                            :
                                 resource.Namespace;
                return(collection.StartsWith(collections, StringComparison.OrdinalIgnoreCase));
            })
                          .ToArray();
            var manifest = new EastFive.Api.Resources.Manifest(lookups, httpApp);

            return(manifest.Routes
                   .SelectMany(route => route.Methods)
                   .SelectMany(method => method.MethodPoco
                               .GetAttributesInterface <IDefineFlow>(multiple: true)
                               .Select(attr => (method, attr)))
                   .GroupBy(methodAndFlow => methodAndFlow.attr.FlowName)
                   .Where(grp => grp.Key.HasBlackSpace())
                   .Where(grp => grp.Key.Equals(flow, StringComparison.OrdinalIgnoreCase))
                   .First(
                       (methodAndFlowGrp, next) =>
            {
                var info = new Resources.Collection.Info
                {
                    _postman_id = Guid.NewGuid(),
                    name = methodAndFlowGrp.Key,
                    schema = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
                };

                var customItems = manifest.Routes
                                  .SelectMany(route => route.Type.GetAttributesInterface <IDefineFlow>(multiple: true))
                                  .Select(flowAttr => (flowAttr, flowAttr.GetItem(default(Api.Resources.Method),
                                                                                  preferJson.HasValue? preferJson.Value : false)))
                                  .Where(grp => grp.Item1.FlowName.Equals(flow, StringComparison.OrdinalIgnoreCase))
                                  .ToArray();

                var items = methodAndFlowGrp
                            .Select(
                    methodAndFlow => (methodAndFlow.attr, methodAndFlow.attr.GetItem(methodAndFlow.method,
                                                                                     preferJson.HasValue ? preferJson.Value : false)))
                            .Concat(customItems)
                            .OrderBy(methodAndFlow => methodAndFlow.Item1.Step)
                            .Select(tpl => tpl.Item2)
                            .ToArray();

                var collection = new Resources.Collection.Collection()
                {
                    info = info,
                    item = items,
                };
                return onSuccess(collection);
            },
                       () => onNotFound()));
        }