protected override async Task <bool> GetHtmlAsync(IOwinEnvironment context, IClient client, CancellationToken cancellationToken)
        {
            var queryString = QueryStringParser.Parse(context.Request.QueryString, _logger);

            var stateToken       = queryString.GetString("state");
            var parsedStateToken = new StateTokenParser(client, _configuration.Client.ApiKey, stateToken, _logger);

            if (!parsedStateToken.Valid)
            {
                _logger.Warn("State token was invalid", nameof(GithubCallbackRoute));
                return(await HttpResponse.Redirect(context, SocialExecutor.CreateErrorUri(_configuration.Web.Login, stateToken: null)));
            }

            var code = queryString.GetString("code");

            if (string.IsNullOrEmpty(code))
            {
                _logger.Warn("Social code was empty", nameof(GithubCallbackRoute));
                return(await HttpResponse.Redirect(context, SocialExecutor.CreateErrorUri(_configuration.Web.Login, stateToken)));
            }

            var accessToken = await ExchangeCodeAsync(code, cancellationToken);

            if (string.IsNullOrEmpty(accessToken))
            {
                _logger.Warn("Exchanged access token was null", source: nameof(GithubCallbackRoute));
                return(await HttpResponse.Redirect(context, SocialExecutor.CreateErrorUri(_configuration.Web.Login, stateToken)));
            }

            var application = await client.GetApplicationAsync(_configuration.Application.Href, cancellationToken);

            var socialExecutor = new SocialExecutor(client, _configuration, _handlers, _logger);

            try
            {
                var providerRequest = client.Providers()
                                      .Github()
                                      .Account()
                                      .SetAccessToken(accessToken)
                                      .Build();

                var loginResult =
                    await socialExecutor.LoginWithProviderRequestAsync(context, providerRequest, cancellationToken);

                await socialExecutor.HandleLoginResultAsync(
                    context,
                    application,
                    loginResult,
                    cancellationToken);

                return(await socialExecutor.HandleRedirectAsync(client, context, loginResult, parsedStateToken.Path, cancellationToken));
            }
            catch (Exception ex)
            {
                _logger.Warn($"Got '{ex.Message}' during social login request", source: nameof(GithubCallbackRoute));
                return(await HttpResponse.Redirect(context, SocialExecutor.CreateErrorUri(_configuration.Web.Login, stateToken)));
            }
        }
Exemple #2
0
        private async Task <bool> HandleSocialLogin(IOwinEnvironment context, IClient client, LoginPostModel model,
                                                    CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(model.ProviderData.ProviderId))
            {
                return(await Error.Create(context, new BadRequest("No provider specified"), cancellationToken));
            }

            var application = await client.GetApplicationAsync(_configuration.Application.Href, cancellationToken);

            var socialExecutor = new SocialExecutor(client, _configuration, _handlers, _logger);

            try
            {
                IProviderAccountRequest providerRequest;

                switch (model.ProviderData.ProviderId)
                {
                case "facebook":
                {
                    providerRequest = client.Providers()
                                      .Facebook()
                                      .Account()
                                      .SetAccessToken(model.ProviderData.AccessToken)
                                      .Build();
                    break;
                }

                case "google":
                {
                    providerRequest = client.Providers()
                                      .Google()
                                      .Account()
                                      .SetCode(model.ProviderData.Code)
                                      .Build();
                    break;
                }

                case "github":
                {
                    providerRequest = client.Providers()
                                      .Github()
                                      .Account()
                                      .SetAccessToken(model.ProviderData.AccessToken)
                                      .Build();
                    break;
                }

                case "linkedin":
                {
                    providerRequest = client.Providers()
                                      .LinkedIn()
                                      .Account()
                                      .SetAccessToken(model.ProviderData.AccessToken)
                                      .Build();
                    break;
                }

                default:
                    providerRequest = null;
                    break;
                }

                if (providerRequest == null)
                {
                    return(await Error.Create(context,
                                              new BadRequest($"Unknown provider '{model.ProviderData.ProviderId}'"), cancellationToken));
                }

                var loginResult =
                    await socialExecutor.LoginWithProviderRequestAsync(context, providerRequest, cancellationToken);

                await socialExecutor.HandleLoginResultAsync(
                    context,
                    application,
                    loginResult,
                    cancellationToken);

                var sanitizer     = new AccountResponseSanitizer();
                var responseModel = new
                {
                    account = sanitizer.Sanitize(loginResult.Account)
                };

                return(await JsonResponse.Ok(context, responseModel));
            }
            catch (ResourceException rex)
            {
                // TODO improve error logging (include request id, etc)
                _logger.Error(rex.DeveloperMessage, source: nameof(HandleSocialLogin));
                return(await Error.Create(context, new BadRequest("An error occurred while processing the login"), cancellationToken));
            }
            catch (Exception ex)
            {
                _logger.Error(ex, source: nameof(HandleSocialLogin));
                return(await Error.Create(context, new BadRequest("An error occurred while processing the login"), cancellationToken));
            }
        }