private async Task <AuthenticateResult> ValidateCertificateAsync(X509Certificate2 clientCertificate) { // If we have a self signed cert, and they're not allowed, exit early and not bother with // any other validations. if (clientCertificate.IsSelfSigned() && !Options.AllowedCertificateTypes.HasFlag(CertificateTypes.SelfSigned)) { Logger.CertificateRejected("Self signed", clientCertificate.Subject); return(AuthenticateResult.Fail("Options do not allow self signed certificates.")); } // If we have a chained cert, and they're not allowed, exit early and not bother with // any other validations. if (!clientCertificate.IsSelfSigned() && !Options.AllowedCertificateTypes.HasFlag(CertificateTypes.Chained)) { Logger.CertificateRejected("Chained", clientCertificate.Subject); return(AuthenticateResult.Fail("Options do not allow chained certificates.")); } var chainPolicy = BuildChainPolicy(clientCertificate); using var chain = new X509Chain { ChainPolicy = chainPolicy }; var certificateIsValid = chain.Build(clientCertificate); if (!certificateIsValid) { var chainErrors = new List <string>(chain.ChainStatus.Length); foreach (var validationFailure in chain.ChainStatus) { chainErrors.Add($"{validationFailure.Status} {validationFailure.StatusInformation}"); } Logger.CertificateFailedValidation(clientCertificate.Subject, chainErrors); return(AuthenticateResult.Fail("Client certificate failed validation.")); } var certificateValidatedContext = new CertificateValidatedContext(Context, Scheme, Options) { ClientCertificate = clientCertificate, Principal = CreatePrincipal(clientCertificate) }; await Events.CertificateValidated(certificateValidatedContext); if (certificateValidatedContext.Result != null) { return(certificateValidatedContext.Result); } certificateValidatedContext.Success(); return(certificateValidatedContext.Result !); }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { // You only get client certificates over HTTPS if (!Context.Request.IsHttps) { return(AuthenticateResult.NoResult()); } try { var clientCertificate = await Context.Connection.GetClientCertificateAsync(); // This should never be the case, as cert authentication happens long before ASP.NET kicks in. if (clientCertificate == null) { Logger.NoCertificate(); return(AuthenticateResult.NoResult()); } // If we have a self signed cert, and they're not allowed, exit early and not bother with // any other validations. if (clientCertificate.IsSelfSigned() && !Options.AllowedCertificateTypes.HasFlag(CertificateTypes.SelfSigned)) { Logger.CertificateRejected("Self signed", clientCertificate.Subject); return(AuthenticateResult.Fail("Options do not allow self signed certificates.")); } // If we have a chained cert, and they're not allowed, exit early and not bother with // any other validations. if (!clientCertificate.IsSelfSigned() && !Options.AllowedCertificateTypes.HasFlag(CertificateTypes.Chained)) { Logger.CertificateRejected("Chained", clientCertificate.Subject); return(AuthenticateResult.Fail("Options do not allow chained certificates.")); } var chainPolicy = BuildChainPolicy(clientCertificate); var chain = new X509Chain { ChainPolicy = chainPolicy }; var certificateIsValid = chain.Build(clientCertificate); if (!certificateIsValid) { var chainErrors = new List <string>(); foreach (var validationFailure in chain.ChainStatus) { chainErrors.Add($"{validationFailure.Status} {validationFailure.StatusInformation}"); } Logger.CertificateFailedValidation(clientCertificate.Subject, chainErrors); return(AuthenticateResult.Fail("Client certificate failed validation.")); } var certificateValidatedContext = new CertificateValidatedContext(Context, Scheme, Options) { ClientCertificate = clientCertificate, Principal = CreatePrincipal(clientCertificate) }; await Events.CertificateValidated(certificateValidatedContext); if (certificateValidatedContext.Result != null) { return(certificateValidatedContext.Result); } certificateValidatedContext.Success(); return(certificateValidatedContext.Result); } catch (Exception ex) { var authenticationFailedContext = new CertificateAuthenticationFailedContext(Context, Scheme, Options) { Exception = ex }; await Events.AuthenticationFailed(authenticationFailedContext); if (authenticationFailedContext.Result != null) { return(authenticationFailedContext.Result); } throw; } }
/// <summary> /// Invoked after a certificate has been validated /// </summary> /// <param name="context"></param> /// <returns></returns> public virtual Task CertificateValidated(CertificateValidatedContext context) => OnCertificateValidated(context);