示例#1
0
        public async Task <IActionResult> LoginComplete([FromQuery] string code, [FromQuery] string state)
        {
            const string UserDataParam = "data";
            const string SuccessParam  = "successful";
            const string ErrorParam    = "error";
            const string CodeParam     = "code";

            var stateDe = StateData.Decrypt(stateEncAlgo, state);

            if (!stateDe.IsValid)
            {
                // state invalid; refuse to brew coffee
                return(this.ImATeapot());
            }

            var successCb = stateDe.SuccessCallback;

            if (stateDe.UserData != null)
            {
                successCb = QueryHelpers.AddQueryString(successCb, UserDataParam, stateDe.UserData);
            }

            var failureCb = stateDe.FailureCallback;

            if (failureCb != null && stateDe.UserData != null)
            {
                failureCb = QueryHelpers.AddQueryString(failureCb, UserDataParam, stateDe.UserData);
            }
            else if (failureCb == null)
            {
                failureCb = QueryHelpers.AddQueryString(successCb, SuccessParam, "false");
                successCb = QueryHelpers.AddQueryString(successCb, SuccessParam, "true");
            }

            OauthToken token;

            try
            {
                token = await client.Oauth.CreateAccessToken(
                    new OauthTokenRequest(githubAuthSettings.ClientId,
                                          githubAuthSettings.ClientSecret, code)
                {
                    RedirectUri = new Uri(Url.AbsoluteRouteUrl(LoginCallbackName))
                });
            } // will not catch NotFound, Validation, or LegalRestriction because those are hard errors
            catch (AuthorizationException e)
            {
                return(Redirect(QueryHelpers.AddQueryString(failureCb, ErrorParam,
                                                            $"GitHub returned Unauthorized: {e.Message}")));
            }
            catch (ForbiddenException e)
            {
                return(Redirect(QueryHelpers.AddQueryString(failureCb, ErrorParam,
                                                            $"GitHub returned Forbidden: {e.Message}")));
            }
            catch (ApiException e)
            {
                return(Redirect(QueryHelpers.AddQueryString(failureCb, ErrorParam,
                                                            $"GitHub returned error: {e.Message}")));
            }

            if (token.TokenType != "bearer") // don't know what to do with it
            {
                return(Redirect(QueryHelpers.AddQueryString(failureCb, ErrorParam,
                                                            $"API returned unknown token type {token.TokenType}")));
            }

            var newCode = Utils.GetCryptoRandomHexString(8);                     // keep it somewhat short

            while (await repoContext.AuthCodes.AnyAsync(s => s.Code == newCode)) // in the odd case that 2 exist at once
            {
                newCode = Utils.GetCryptoRandomHexString(8);
            }

            repoContext.AuthCodes.Add(new AuthCodeTempStore
            {
                Code         = newCode,
                GitHubBearer = token.AccessToken
            });

            await repoContext.SaveChangesAsync(); // these saves feel kinda gross ngl

            // TODO: will this ever cause a race condition?

            return(Redirect(QueryHelpers.AddQueryString(successCb, CodeParam, newCode)));
        }