Пример #1
0
        public async Task <UserInformation> GetUserInformation(
            string accessToken,
            CancellationToken cancellationToken = default)
        {
            _logger.LogInformation("Getting user information");
            return(await _cache.GetOrCreateAsync(new UserInfoKey(accessToken),
                                                 cacheEntry =>
            {
                cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15);
                return Execute();
            }));

            async Task <UserInformation> Execute()
            {
                _logger.LogInformation("Fetching fresh user info...");
                GitHubAuthenticationOptions options = _options.CurrentValue;
                IGitHubClient client = _gitHubClientFactory.CreateGitHubClient(accessToken);
                User          user   = await client.User.Current();

                _logger.LogInformation("Successfully fetched user data");

                ImmutableArray <Claim> .Builder claims = ImmutableArray.CreateBuilder <Claim>();

                void AddClaim(string type, string value)
                {
                    if (!string.IsNullOrEmpty(value))
                    {
                        claims.Add(new Claim(type, value, ClaimValueTypes.String, options.ClaimsIssuer));
                    }
                }

                AddClaim(ClaimTypes.NameIdentifier, user.Id.ToString());
                AddClaim(ClaimTypes.Name, user.Login);
                AddClaim(ClaimTypes.Email, user.Email);
                AddClaim("urn:github:name", user.Name);
                AddClaim("urn:github:url", user.Url);
                AddClaim(AccessTokenClaim, accessToken);

                var userInformation = new UserInformation(claims.ToImmutable(), user);

                return(userInformation);
            }
        }
Пример #2
0
        private async Task <T> GetResponseJsonPayloadAsync <T>(
            string url,
            string accessToken,
            GitHubAuthenticationOptions options,
            Func <HttpResponseMessage, Task <T> > parseResponse,
            CancellationToken cancellationToken)
        {
            using (var request = new HttpRequestMessage(HttpMethod.Get, url)
            {
                Headers =
                {
                    Accept        = { new MediaTypeWithQualityHeaderValue("application/json") },
                    Authorization = new AuthenticationHeaderValue("Bearer", accessToken)
                }
            })
            {
                using (HttpResponseMessage response = await options.Backchannel.SendAsync(
                           request,
                           HttpCompletionOption.ResponseHeadersRead,
                           cancellationToken))
                {
                    if (response.IsSuccessStatusCode)
                    {
                        return(await parseResponse(response));
                    }

                    string body = await response.Content.ReadAsStringAsync();

                    if (body.Length > 1024)
                    {
                        body = body.Substring(0, 1024);
                    }

                    _logger.LogError(
                        "An error occurred while retrieving the user profile: the remote server returned a {Status} response with the following payload: {Headers} {Body}.",
                        response.StatusCode,
                        response.Headers.ToString(),
                        body);
                    throw new HttpRequestException("An error occurred while retrieving the user org membership.");
                }
            }
        }
Пример #3
0
        public async Task <IEnumerable <Claim> > GetMembershipClaims(
            string accessToken,
            CancellationToken cancellationToken = default)
        {
            _logger.LogInformation("Getting user membership information...");
            return(await _cache.GetOrCreateAsync(new GroupInfoKey(accessToken),
                                                 cacheEntry =>
            {
                cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15);
                return Execute();
            }));

            async Task <ImmutableArray <Claim> > Execute()
            {
                _logger.LogInformation("Fetching fresh membership info...");
                GitHubAuthenticationOptions options = _options.CurrentValue;

                ImmutableArray <Claim> .Builder claims = ImmutableArray.CreateBuilder <Claim>();

                void AddClaim(string type, string value)
                {
                    if (!string.IsNullOrEmpty(value))
                    {
                        claims.Add(new Claim(type, value, ClaimValueTypes.String, options.ClaimsIssuer));
                    }
                }

                {
                    JArray orgPayload = await GetResponseJsonPayloadAsync("https://api.github.com/user/orgs",
                                                                          accessToken,
                                                                          options,
                                                                          async r => JArray.Parse(await r.Content.ReadAsStringAsync()),
                                                                          cancellationToken);

                    _logger.LogInformation("Fetched {orgCount} orgs", orgPayload.Count);

                    foreach (JToken org in orgPayload)
                    {
                        string orgLogin = org.Value <string>("login")?.ToLowerInvariant();
                        AddClaim(ClaimTypes.Role, "github:org:" + orgLogin);
                        AddClaim("urn:github:org", orgLogin);
                    }
                }

                {
                    JArray teamPayload = await GetResponseJsonPayloadAsync("https://api.github.com/user/teams",
                                                                           accessToken,
                                                                           options,
                                                                           async r => JArray.Parse(await r.Content.ReadAsStringAsync()),
                                                                           cancellationToken);

                    _logger.LogInformation("Fetched {teamCount} teams", teamPayload.Count);

                    foreach (JToken team in teamPayload)
                    {
                        string teamName = team.Value <string>("name")?.ToLowerInvariant();
                        string orgName  = team["organization"]?.Value <string>("login")?.ToLowerInvariant();
                        string fullName = orgName + "/" + teamName;
                        AddClaim(ClaimTypes.Role, "github:team:" + fullName);
                        AddClaim("urn:github:team", fullName);
                    }
                }

                return(claims.ToImmutable());
            }
        }