Esempio n. 1
0
        public override async Task ValidateAsync([NotNull] AppleValidateIdTokenContext context)
        {
            if (!_tokenHandler.CanValidateToken)
            {
                throw new NotSupportedException($"The configured {nameof(JwtSecurityTokenHandler)} cannot validate tokens.");
            }

            byte[] keysJson = await _keyStore.LoadPublicKeysAsync(context);

            string json   = Encoding.UTF8.GetString(keysJson);
            var    keySet = JsonWebKeySet.Create(json);

            var parameters = new TokenValidationParameters()
            {
                ValidAudience     = context.Options.ClientId,
                ValidIssuer       = context.Options.TokenAudience,
                IssuerSigningKeys = keySet.Keys,
            };

            try
            {
                _tokenHandler.ValidateToken(context.IdToken, parameters, out var _);
            }
            catch (Exception ex)
            {
                _logger.LogError(
                    ex,
                    "Apple ID token validation failed for issuer {TokenIssuer} and audience {TokenAudience}. ID Token: {IdToken}",
                    parameters.ValidAudience,
                    parameters.ValidIssuer,
                    context.IdToken);

                throw;
            }
        }
Esempio n. 2
0
        /// <inheritdoc />
        public override async Task <byte[]> LoadPublicKeysAsync([NotNull] AppleValidateIdTokenContext context)
        {
            if (_publicKey == null)
            {
                _publicKey = await LoadApplePublicKeysAsync(context);
            }

            return(_publicKey);
        }
    /// <inheritdoc />
    protected override async Task <AuthenticationTicket> CreateTicketAsync(
        [NotNull] ClaimsIdentity identity,
        [NotNull] AuthenticationProperties properties,
        [NotNull] OAuthTokenResponse tokens)
    {
        string?idToken = tokens.Response !.RootElement.GetString("id_token");

        Log.CreatingTicket(Logger);

        if (Logger.IsEnabled(LogLevel.Trace))
        {
            Log.LogAccessToken(Logger, tokens.AccessToken);
            Log.LogRefreshToken(Logger, tokens.RefreshToken);
            Log.LogTokenType(Logger, tokens.TokenType);
            Log.LogExpiresIn(Logger, tokens.ExpiresIn);
            Log.LogTokenResponse(Logger, tokens.Response.RootElement);
            Log.LogIdToken(Logger, idToken);
        }

        if (string.IsNullOrWhiteSpace(idToken))
        {
            throw new InvalidOperationException("No Apple ID token was returned in the OAuth token response.");
        }

        if (Options.ValidateTokens)
        {
            var validateIdContext = new AppleValidateIdTokenContext(Context, Scheme, Options, idToken);
            await Events.ValidateIdToken(validateIdContext);
        }

        var tokenClaims = ExtractClaimsFromToken(idToken);

        foreach (var claim in tokenClaims)
        {
            identity.AddClaim(claim);
        }

        var principal = new ClaimsPrincipal(identity);

        var context = new OAuthCreatingTicketContext(principal, properties, Context, Scheme, Options, Backchannel, tokens, tokens.Response.RootElement);

        context.RunClaimActions();

        await Events.CreatingTicket(context);

        return(new AuthenticationTicket(context.Principal !, context.Properties, Scheme.Name));
    }
Esempio n. 4
0
        private async Task <byte[]> LoadApplePublicKeysAsync([NotNull] AppleValidateIdTokenContext context)
        {
            var response = await context.Options.Backchannel.GetAsync(context.Options.PublicKeyEndpoint, context.HttpContext.RequestAborted);

            if (!response.IsSuccessStatusCode)
            {
                _logger.LogError("An error occurred while retrieving the public keys from Apple: the remote server " +
                                 "returned a {Status} response with the following payload: {Headers} {Body}.",
                                 /* Status: */ response.StatusCode,
                                 /* Headers: */ response.Headers.ToString(),
                                 /* Body: */ await response.Content.ReadAsStringAsync(context.HttpContext.RequestAborted));

                throw new HttpRequestException("An error occurred while retrieving the public keys from Apple.");
            }

            return(await response.Content.ReadAsByteArrayAsync(context.HttpContext.RequestAborted));
        }
Esempio n. 5
0
    public override async Task ValidateAsync([NotNull] AppleValidateIdTokenContext context)
    {
        if (context.Options.SecurityTokenHandler is null)
        {
            throw new InvalidOperationException("The options SecurityTokenHandler is null.");
        }

        if (!context.Options.SecurityTokenHandler.CanValidateToken)
        {
            throw new NotSupportedException($"The configured {nameof(JsonWebTokenHandler)} cannot validate tokens.");
        }

        if (context.Options.ConfigurationManager is null)
        {
            throw new InvalidOperationException($"An OpenID Connect configuration manager has not been set on the {nameof(AppleAuthenticationOptions)} instance.");
        }

        if (context.Options.TokenValidationParameters is null)
        {
            throw new InvalidOperationException($"Token validation parameters have not been set on the {nameof(AppleAuthenticationOptions)} instance.");
        }

        var configuration = await context.Options.ConfigurationManager.GetConfigurationAsync(context.HttpContext.RequestAborted);

        var validationParameters = context.Options.TokenValidationParameters.Clone();

        validationParameters.IssuerSigningKeys = configuration.JsonWebKeySet.Keys;

        try
        {
            var result = context.Options.SecurityTokenHandler.ValidateToken(context.IdToken, validationParameters);

            if (result.Exception is not null || !result.IsValid)
            {
                throw new SecurityTokenValidationException("Apple ID token validation failed.", result.Exception);
            }
        }
        catch (Exception ex)
        {
            Log.TokenValidationFailed(_logger, ex, validationParameters.ValidIssuer, validationParameters.ValidAudience);
            Log.TokenInvalid(_logger, ex, context.IdToken);
            throw;
        }
    }
Esempio n. 6
0
        /// <inheritdoc />
        public override async Task <byte[]> LoadPublicKeysAsync([NotNull] AppleValidateIdTokenContext context)
        {
            var utcNow = _clock.UtcNow;

            if (_publicKey == null || _reloadKeysAfter < utcNow)
            {
                _logger.LogInformation("Loading Apple public keys from {PublicKeyEndpoint}.", context.Options.PublicKeyEndpoint);

                _publicKey = await LoadApplePublicKeysAsync(context);

                _reloadKeysAfter = utcNow.Add(context.Options.PublicKeyCacheLifetime);

                _logger.LogInformation(
                    "Loaded Apple public keys from {PublicKeyEndpoint}. Keys will be reloaded at or after {ReloadKeysAfter}.",
                    context.Options.PublicKeyEndpoint,
                    _reloadKeysAfter);
            }

            return(_publicKey);
        }
Esempio n. 7
0
 /// <summary>
 /// Invoked whenever the ID token needs to be validated.
 /// </summary>
 /// <param name="context">Contains information about the ID token to validate.</param>
 /// <returns>
 /// A <see cref="Task"/> representing the completed operation.
 /// </returns>
 public virtual async Task ValidateIdToken([NotNull] AppleValidateIdTokenContext context) =>
 await OnValidateIdToken(context);
Esempio n. 8
0
 /// <summary>
 /// Validates the Apple ID token associated with the specified context as an asynchronous operation.
 /// </summary>
 /// <param name="context">The context to validate the ID token for.</param>
 /// <returns>
 /// A <see cref="Task"/> representing the asynchronous operation to validate the ID token.
 /// </returns>
 public abstract Task ValidateAsync(AppleValidateIdTokenContext context);