Beispiel #1
0
        private async Task OnClientAuthenticated(OpenIdAuthenticatedContext context)
        {
            var userManager = context.HttpContext.RequestServices.GetService <SteamUsersController>();

            var steamId = ulong.Parse(new Uri(context.Identifier).Segments.Last());

            if (userManager != null && !await userManager.IsRegisteredAsync(steamId.ToString()))
            {
                await userManager.RegisterUserAsync(steamId.ToString());
            }

            if (userManager != null && context.UserPayload != null)
            {
                await using var stream = new MemoryStream();
                var writer = new Utf8JsonWriter(stream, new JsonWriterOptions {
                    Indented = true
                });
                context.UserPayload.RootElement.GetProperty("response").GetProperty("players").WriteTo(writer);
                await writer.FlushAsync();

                var json     = Encoding.UTF8.GetString(stream.ToArray());
                var response = JsonConvert.DeserializeObject <SteamResponseModel>(json);
                foreach (var player in response.Players)
                {
                    await userManager.UpdateUserAsync(player);
                }
            }

            context.Identity.AddClaim(new Claim("steamID", steamId.ToString()));
            var identity = new ClaimsPrincipal(context.Identity);


            context.HttpContext.User = identity;
        }
Beispiel #2
0
        public static void RunClaimActions(this OpenIdAuthenticatedContext source, JObject model = null)
        {
            if (!ClaimMap.ContainsKey(source.Options))
            {
                return;
            }

            if (model == null)
            {
                model = source.User;
            }

            foreach (var claim in ClaimMap[source.Options])
            {
                var targetValue = model.SelectToken(claim.Value).ToString();
                if (targetValue != null)
                {
                    source.Identity.AddClaim(new Claim(claim.Type, targetValue, claim.ValueType, claim.Issuer));
                }
            }
        }
Beispiel #3
0
        protected override async Task <AuthenticationTicket> CreateTicketAsync(
            [NotNull] ClaimsIdentity identity, [NotNull] AuthenticationProperties properties,
            [NotNull] string identifier, [NotNull] IReadOnlyDictionary <string, string> attributes)
        {
            var principal = new ClaimsPrincipal(identity);
            var ticket    = new AuthenticationTicket(principal, properties, Scheme.Name);

            // Return the authentication ticket as-is if the user information endpoint has not been set.
            if (string.IsNullOrEmpty(Options.UserInformationEndpoint))
            {
                Logger.LogInformation("The userinfo request was skipped because no userinfo endpoint was configured.");

                return(await RunAuthenticatedEventAsync());
            }

            // Return the authentication ticket as-is if the application key has not been set.
            if (string.IsNullOrEmpty(Options.ApplicationKey))
            {
                Logger.LogInformation("The userinfo request was skipped because no application key was configured.");

                return(await RunAuthenticatedEventAsync());
            }

            // Note: prior to April 2018, the Steam identifier was prefixed with an HTTP base address.
            // Since then, the prefix is now an HTTPS address. The following logic supports both prefixes.
            if (identifier.StartsWith(SteamAuthenticationConstants.Namespaces.Identifier, StringComparison.Ordinal))
            {
                identifier = identifier.Substring(SteamAuthenticationConstants.Namespaces.Identifier.Length);
            }

            else if (identifier.StartsWith(SteamAuthenticationConstants.Namespaces.LegacyIdentifier, StringComparison.Ordinal))
            {
                identifier = identifier.Substring(SteamAuthenticationConstants.Namespaces.LegacyIdentifier.Length);
            }

            // Prevent the sign-in operation from completing if the claimed identifier is malformed.
            else
            {
                Logger.LogWarning("The userinfo request was skipped because an invalid identifier was received: {Identifier}.", identifier);

                throw new InvalidOperationException($"The OpenID claimed identifier '{identifier}' is not valid.");
            }

            var address = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, new Dictionary <string, string>
            {
                [SteamAuthenticationConstants.Parameters.Key]     = Options.ApplicationKey,
                [SteamAuthenticationConstants.Parameters.SteamId] = identifier
            });

            var request = new HttpRequestMessage(HttpMethod.Get, address);

            request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(OpenIdAuthenticationConstants.Media.Json));

            // Return the authentication ticket as-is if the userinfo request failed.
            var response = await Options.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);

            if (!response.IsSuccessStatusCode)
            {
                Logger.LogWarning("The userinfo request failed because an invalid response was received: the identity provider " +
                                  "returned returned a {Status} response with the following payload: {Headers} {Body}.",
                                  /* Status: */ response.StatusCode,
                                  /* Headers: */ response.Headers.ToString(),
                                  /* Body: */ await response.Content.ReadAsStringAsync());

                throw new HttpRequestException("An error occurred while retrieving the user profile from Steam.");
            }

            using var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync());

            // Try to extract the profile name of the authenticated user.
            var profile = payload.RootElement
                          .GetProperty(SteamAuthenticationConstants.Parameters.Response)
                          .GetProperty(SteamAuthenticationConstants.Parameters.Players)
                          .EnumerateArray()
                          .FirstOrDefault();

            if (profile.ValueKind == JsonValueKind.Object && profile.TryGetProperty(SteamAuthenticationConstants.Parameters.Name, out var name))
            {
                identity.AddClaim(new Claim(ClaimTypes.Name, name.GetString(), ClaimValueTypes.String, Options.ClaimsIssuer));
            }

            return(await RunAuthenticatedEventAsync(payload));

            async Task <AuthenticationTicket> RunAuthenticatedEventAsync(JsonDocument user = null)
            {
                var context = new OpenIdAuthenticatedContext(Context, Scheme, Options, ticket)
                {
                    UserPayload = user
                };

                if (user != null)
                {
#pragma warning disable CS0618
                    context.User = JObject.Parse(user.RootElement.ToString());
#pragma warning restore CS0618
                }

                // Copy the attributes to the context object.
                foreach (var attribute in attributes)
                {
                    context.Attributes.Add(attribute);
                }

                await Events.Authenticated(context);

                // Note: return the authentication ticket associated
                // with the notification to allow replacing the ticket.
                return(context.Ticket);
            }
        }
        protected override async Task <AuthenticationTicket> CreateTicketAsync(
            [NotNull] ClaimsIdentity identity, [NotNull] AuthenticationProperties properties,
            [NotNull] string identifier, [NotNull] IReadOnlyDictionary <string, string> attributes)
        {
            var principal = new ClaimsPrincipal(identity);
            var ticket    = new AuthenticationTicket(principal, properties, Scheme.Name);

            // Return the authentication ticket as-is if the
            // user information endpoint has not been set.
            if (string.IsNullOrEmpty(Options.UserInformationEndpoint))
            {
                Logger.LogInformation("The userinfo request was skipped because no userinfo endpoint was configured.");

                return(ticket);
            }

            // Return the authentication ticket as-is
            // if the application key has not been set.
            if (string.IsNullOrEmpty(Options.ApplicationKey))
            {
                Logger.LogInformation("The userinfo request was skipped because no application key was configured.");

                return(ticket);
            }

            // Note: prior to April 2018, the Steam identifier was prefixed with an HTTP base address.
            // Since then, the prefix is now an HTTPS address. The following logic supports both prefixes.
            if (identifier.StartsWith(SteamAuthenticationConstants.Namespaces.Identifier, StringComparison.Ordinal))
            {
                identifier = identifier.Substring(SteamAuthenticationConstants.Namespaces.Identifier.Length);
            }

            else if (identifier.StartsWith(SteamAuthenticationConstants.Namespaces.LegacyIdentifier, StringComparison.Ordinal))
            {
                identifier = identifier.Substring(SteamAuthenticationConstants.Namespaces.LegacyIdentifier.Length);
            }

            // Return the authentication ticket as-is if the claimed identifier is malformed.
            else
            {
                Logger.LogWarning("The userinfo request was skipped because an invalid identifier was received: {Identifier}.", identifier);

                return(ticket);
            }

            var address = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, new Dictionary <string, string>
            {
                [SteamAuthenticationConstants.Parameters.Key]     = Options.ApplicationKey,
                [SteamAuthenticationConstants.Parameters.SteamId] = identifier
            });

            var request = new HttpRequestMessage(HttpMethod.Get, address);

            request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(OpenIdAuthenticationConstants.Media.Json));

            // Return the authentication ticket as-is if the userinfo request failed.
            var response = await Options.HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);

            if (!response.IsSuccessStatusCode)
            {
                Logger.LogWarning("The userinfo request failed because an invalid response was received: the identity provider " +
                                  "returned returned a {Status} response with the following payload: {Headers} {Body}.",
                                  /* Status: */ response.StatusCode,
                                  /* Headers: */ response.Headers.ToString(),
                                  /* Body: */ await response.Content.ReadAsStringAsync());

                return(ticket);
            }

            var payload = JObject.Parse(await response.Content.ReadAsStringAsync());

            // Try to extract the profile name of the authenticated user.
            var profile = payload.Value <JObject>(SteamAuthenticationConstants.Parameters.Response)
                          ?.Value <JArray>(SteamAuthenticationConstants.Parameters.Players)
                            ?[0]?.Value <string>(SteamAuthenticationConstants.Parameters.Name);

            if (!string.IsNullOrEmpty(profile))
            {
                identity.AddClaim(new Claim(ClaimTypes.Name, profile, ClaimValueTypes.String, Options.ClaimsIssuer));
            }

            var context = new OpenIdAuthenticatedContext(Context, Scheme, Options, ticket)
            {
                User = payload
            };

            // Copy the attributes to the context object.
            foreach (var attribute in attributes)
            {
                context.Attributes.Add(attribute);
            }

            await Events.Authenticated(context);

            // Note: return the authentication ticket associated
            // with the notification to allow replacing the ticket.
            return(context.Ticket);
        }
 /// <summary>
 /// Defines a notification invoked when the user is authenticated by the identity provider.
 /// </summary>
 /// <param name="context">The context of the event carries information in and results out.</param>
 /// <returns>Task to enable asynchronous execution</returns>
 public virtual Task Authenticated(OpenIdAuthenticatedContext context) => OnAuthenticated(context);