private bool ValidateCodeVerifierAgainstCodeChallenge(string codeVerifier, string codeChallenge, string codeChallengeMethod) { if (codeChallengeMethod == OidcConstants.CodeChallengeMethods.Plain) { return(TimeConstantComparer.IsEqual(codeVerifier.Sha256(), codeChallenge)); } var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier); var hashedBytes = codeVerifierBytes.Sha256(); var transformedCodeVerifier = Base64Url.Encode(hashedBytes); return(TimeConstantComparer.IsEqual(transformedCodeVerifier.Sha256(), codeChallenge)); }
/// <summary> /// Validates a secret /// </summary> /// <param name="secrets">The stored secrets.</param> /// <param name="parsedSecret">The received secret.</param> /// <returns> /// A validation result /// </returns> /// <exception cref="System.ArgumentException">id or credential is missing.</exception> public Task <SecretValidationResult> ValidateAsync(IEnumerable <Secret> secrets, ParsedSecret parsedSecret) { var fail = Task.FromResult(new SecretValidationResult { Success = false }); var success = Task.FromResult(new SecretValidationResult { Success = true }); if (parsedSecret.Type != IdentityServerConstants.ParsedSecretTypes.SharedSecret) { _logger.LogError("Parsed secret should not be of type: {type}", parsedSecret.Type ?? "null"); return(fail); } var sharedSecrets = secrets.Where(s => s.Type == IdentityServerConstants.SecretTypes.SharedSecret); if (!sharedSecrets.Any()) { _logger.LogDebug("No shared secret configured for client."); return(fail); } var sharedSecret = parsedSecret.Credential as string; if (parsedSecret.Id.IsMissing() || sharedSecret.IsMissing()) { throw new ArgumentException("Id or Credential is missing."); } foreach (var secret in sharedSecrets) { var secretDescription = string.IsNullOrEmpty(secret.Description) ? "no description" : secret.Description; // use time constant string comparison var isValid = TimeConstantComparer.IsEqual(sharedSecret, secret.Value); if (isValid) { return(success); } } _logger.LogDebug("No matching plain text secret found."); return(fail); }
/// <summary> /// Validates a secret /// </summary> /// <param name="secrets">The stored secrets.</param> /// <param name="parsedSecret">The received secret.</param> /// <returns> /// A validation result /// </returns> /// <exception cref="System.ArgumentException">id or credential is missing.</exception> public Task <SecretValidationResult> ValidateAsync(IEnumerable <Secret> secrets, ParsedSecret parsedSecret) { var fail = Task.FromResult(new SecretValidationResult { Success = false }); var success = Task.FromResult(new SecretValidationResult { Success = true }); if (parsedSecret.Type != Constants.ParsedSecretTypes.SharedSecret) { Logger.Debug(string.Format("Parsed secret should not be of type: {0}", parsedSecret.Type ?? "null")); return(fail); } var sharedSecret = parsedSecret.Credential as string; if (parsedSecret.Id.IsMissing() || sharedSecret.IsMissing()) { throw new ArgumentException("Id or Credential is missing."); } foreach (var secret in secrets) { var secretDescription = string.IsNullOrEmpty(secret.Description) ? "no description" : secret.Description; // this validator is only applicable to shared secrets if (secret.Type != Constants.SecretTypes.SharedSecret) { Logger.Debug(string.Format("Skipping secret: {0}, secret is not of type {1}.", secretDescription, Constants.SecretTypes.SharedSecret)); continue; } // use time constant string comparison var isValid = TimeConstantComparer.IsEqual(sharedSecret, secret.Value); if (isValid) { return(success); } } Logger.Debug("No matching plain text secret found."); return(fail); }
/// <summary> /// Validates a secret /// </summary> /// <param name="secrets">The stored secrets.</param> /// <param name="parsedSecret">The received secret.</param> /// <returns> /// A validation result /// </returns> /// <exception cref="System.ArgumentException">id or credential is missing.</exception> public Task <SecretValidationResult> ValidateAsync(IEnumerable <Secret> secrets, ParsedSecret parsedSecret) { var fail = Task.FromResult(new SecretValidationResult { Success = false }); var success = Task.FromResult(new SecretValidationResult { Success = true }); if (parsedSecret.Type == Constants.ParsedSecretTypes.SharedSecret) { var sharedSecret = parsedSecret.Credential as string; if (parsedSecret.Id.IsMissing() || sharedSecret.IsMissing()) { throw new ArgumentException("id or credential is missing."); } foreach (var secret in secrets) { // this validator is only applicable to shared secrets if (secret.Type != Constants.SecretTypes.SharedSecret) { continue; } // check if client secret is still valid if (secret.Expiration.HasExpired()) { continue; } // use time constant string comparison var isValid = TimeConstantComparer.IsEqual(sharedSecret, secret.Value); if (isValid) { return(success); } } } return(fail); }
private async Task ProcessResponseAsync(HttpContext context) { _logger.LogDebug("Federated signout path requested"); var user = await _userSession.GetIdentityServerUserAsync(); if (user != null) { var upstreamSid = user.FindFirst(OidcConstants.EndSessionRequest.Sid)?.Value; if (upstreamSid != null) { var sidParam = await GetSidRequestParamAsync(context.Request); if (TimeConstantComparer.IsEqual(upstreamSid, sidParam)) { _logger.LogDebug("sid parameter matches external idp sid claim for current user"); // todo - default method does not pick up our auhtN scheme await context.SignOutAsync(); var iframeUrl = await context.GetIdentityServerSignoutFrameCallbackUrlAsync(); if (iframeUrl != null) { _logger.LogDebug("Rendering signout callback iframe"); await RenderResponseAsync(context, iframeUrl); } else { _logger.LogDebug("No signout callback iframe to render"); } } } else { _logger.LogDebug("no sid param passed"); } } else { _logger.LogDebug("no authenticated user"); } }
public Task <SecretValidationResult> ValidateAsync(IEnumerable <Secret> secrets, ParsedSecret parsedSecret) { logger.LogDebug("X509 Validation start"); var fail = Task.FromResult(new SecretValidationResult { Success = false }); var success = Task.FromResult(new SecretValidationResult { Success = true }); if (parsedSecret.Type != IdentityServer4.IdentityServerConstants.ParsedSecretTypes.X509Certificate) { return(fail); } var cert = parsedSecret.Credential as X509Certificate2; if (cert == null) { throw new ArgumentException("ParsedSecret.Credential is not an X509 Certificate"); } string thumbprint = cert.Thumbprint; if (string.IsNullOrWhiteSpace(thumbprint)) { throw new ArgumentException("ParsedSecret.Credential.Thumbprint is empty"); } foreach (var secret in secrets) { if (secret.Type == IdentityServer4.IdentityServerConstants.SecretTypes.X509CertificateThumbprint) { if (TimeConstantComparer.IsEqual(thumbprint.ToLowerInvariant(), secret.Value.ToLowerInvariant())) { return(success); } } } return(fail); }
/// <summary> /// Validates a secret /// </summary> /// <param name="secrets">The stored secrets.</param> /// <param name="parsedSecret">The received secret.</param> /// <returns> /// A validation result /// </returns> /// <exception cref="System.ArgumentException">ParsedSecret.Credential is not an X509 Certificate</exception> public Task <SecretValidationResult> ValidateAsync(IEnumerable <Secret> secrets, ParsedSecret parsedSecret) { var fail = Task.FromResult(new SecretValidationResult { Success = false }); var success = Task.FromResult(new SecretValidationResult { Success = true }); if (parsedSecret.Type != Constants.ParsedSecretTypes.X509Certificate) { return(fail); } var cert = parsedSecret.Credential as X509Certificate2; if (cert == null) { throw new ArgumentException("ParsedSecret.Credential is not an X509 Certificate"); } var thumbprint = cert.Thumbprint; foreach (var secret in secrets) { // check if client secret is still valid if (secret.Expiration.HasExpired()) { continue; } if (secret.Type == Constants.SecretTypes.X509CertificateThumbprint) { if (TimeConstantComparer.IsEqual(thumbprint.ToLowerInvariant(), secret.Value.ToLowerInvariant())) { return(success); } } } return(fail); }
private static bool EmbeddedCertificateIsTrusted(X509Certificate2 certificate, IReadOnlyCollection <Secret> secrets) { if (certificate == null || certificate.Thumbprint == null) { return(false); } if (secrets.Any(s => s.Type == Constants.SecretTypes.X509CertificateThumbprint && TimeConstantComparer.IsEqual(s.Value.ToLowerInvariant(), certificate.Thumbprint.ToLowerInvariant()))) { return(true); } if (secrets.Any(s => s.Type == Constants.SecretTypes.X509CertificateBase64 && Equals(certificate, GetCertificateFromString(s.Value)))) { return(true); } return(false); }
private async Task ProcessResponseAsync(HttpContext context) { _logger.LogDebug("Federated signout path requested"); var user = await context.GetIdentityServerUserAsync(); if (user != null) { var sid = user.FindFirst(OidcConstants.EndSessionRequest.Sid)?.Value; if (sid != null) { var sidParam = await GetSidRequestParamAsync(context.Request); if (TimeConstantComparer.IsEqual(sid, sidParam)) { _logger.LogDebug("sid parameter matches current sid"); var iframeUrl = await context.GetIdentityServerSignoutFrameCallbackUrlAsync(); if (iframeUrl != null) { _logger.LogDebug("Rendering signout callback iframe"); await RenderResponseAsync(context, iframeUrl, sid); } else { _logger.LogDebug("No signout callback iframe to render"); } } } else { _logger.LogDebug("no sid param passed"); } } else { _logger.LogDebug("no authenticated user"); } }
/// <summary> /// Validates a secret /// </summary> /// <param name="secrets">The stored secrets.</param> /// <param name="parsedSecret">The received secret.</param> /// <returns> /// A validation result /// </returns> /// <exception cref="System.ArgumentNullException">Id or cedential</exception> public Task <SecretValidationResult> ValidateAsync(IEnumerable <Secret> secrets, ParsedSecret parsedSecret) { var fail = Task.FromResult(new SecretValidationResult { Success = false }); var success = Task.FromResult(new SecretValidationResult { Success = true }); if (parsedSecret.Type != IdentityServerConstants.ParsedSecretTypes.SharedSecret) { _logger.LogDebug("Hashed shared secret validator cannot process {type}", parsedSecret.Type ?? "null"); return(fail); } var sharedSecrets = secrets.Where(s => s.Type == IdentityServerConstants.SecretTypes.SharedSecret); if (!sharedSecrets.Any()) { _logger.LogDebug("No shared secret configured for client."); return(fail); } var sharedSecret = parsedSecret.Credential as string; var secretSha256 = sharedSecret.Sha256(); var secretSha512 = sharedSecret.Sha512(); foreach (var secret in sharedSecrets) { var secretDescription = string.IsNullOrEmpty(secret.Description) ? "no description" : secret.Description; bool isValid = false; byte[] secretBytes; try { secretBytes = Convert.FromBase64String(secret.Value); } catch (FormatException) { _logger.LogInformation("Secret: {description} uses invalid hashing algorithm.", secretDescription); return(fail); } catch (ArgumentNullException) { _logger.LogInformation("Secret: {description} is null.", secretDescription); return(fail); } if (secretBytes.Length == 32) { isValid = TimeConstantComparer.IsEqual(secret.Value, secretSha256); } else if (secretBytes.Length == 64) { isValid = TimeConstantComparer.IsEqual(secret.Value, secretSha512); } else { _logger.LogInformation("Secret: {description} uses invalid hashing algorithm.", secretDescription); return(fail); } if (isValid) { return(success); } } _logger.LogDebug("No matching hashed secret found."); return(fail); }
/// <summary> /// Validates a secret /// </summary> /// <param name="secrets">The stored secrets.</param> /// <param name="parsedSecret">The received secret.</param> /// <returns> /// A validation result /// </returns> /// <exception cref="System.ArgumentNullException">Id or cedential</exception> public Task<SecretValidationResult> ValidateAsync(IEnumerable<Secret> secrets, ParsedSecret parsedSecret) { var fail = Task.FromResult(new SecretValidationResult { Success = false }); var success = Task.FromResult(new SecretValidationResult { Success = true }); if (parsedSecret.Type != Constants.ParsedSecretTypes.SharedSecret) { Logger.Debug(string.Format("Parsed secret should not be of type {0}", parsedSecret.Type ?? "null")); return fail; } var sharedSecret = parsedSecret.Credential as string; if (parsedSecret.Id.IsMissing() || sharedSecret.IsMissing()) { throw new ArgumentException("Id or Credential is missing."); } var secretSha256 = sharedSecret.Sha256(); var secretSha512 = sharedSecret.Sha512(); foreach (var secret in secrets) { var secretDescription = string.IsNullOrEmpty(secret.Description) ? "no description" : secret.Description; // this validator is only applicable to shared secrets if (secret.Type != Constants.SecretTypes.SharedSecret) { Logger.Debug(string.Format("Skipping secret: {0}, secret is not of type {1}.", secretDescription, Constants.SecretTypes.SharedSecret)); continue; } // check if client secret is still valid if (secret.Expiration.HasExpired()) { Logger.Debug(string.Format("Skipping secret: {0}, secret is expired.", secretDescription)); continue; } bool isValid = false; byte[] secretBytes; try { secretBytes = Convert.FromBase64String(secret.Value); } catch (FormatException) { Logger.Error(string.Format("Secret: {0} uses invalid hashing algorithm.", secretDescription)); return fail; } if (secretBytes.Length == 32) { isValid = TimeConstantComparer.IsEqual(secret.Value, secretSha256); } else if (secretBytes.Length == 64) { isValid = TimeConstantComparer.IsEqual(secret.Value, secretSha512); } else { Logger.Error(string.Format("Secret: {0} uses invalid hashing algorithm.", secretDescription)); return fail; } if (isValid) { return success; } } Logger.Debug("No matching hashed secret found."); return fail; }
/// <summary> /// Validates a secret /// </summary> /// <param name="secrets">The stored secrets.</param> /// <param name="parsedSecret">The received secret.</param> /// <returns> /// A validation result /// </returns> /// <exception cref="System.ArgumentNullException">Id or cedential</exception> public Task <SecretValidationResult> ValidateAsync(IEnumerable <Secret> secrets, ParsedSecret parsedSecret) { var fail = Task.FromResult(new SecretValidationResult { Success = false }); var success = Task.FromResult(new SecretValidationResult { Success = true }); if (parsedSecret.Type != IdentityServerConstants.ParsedSecretTypes.SharedSecret) { _logger.LogDebug("Hashed shared secret validator cannot process {type}", parsedSecret.Type ?? "null"); return(fail); } var sharedSecret = parsedSecret.Credential as string; if (parsedSecret.Id.IsMissing() || sharedSecret.IsMissing()) { throw new ArgumentException("Id or Credential is missing."); } var secretSha256 = sharedSecret.Sha256(); var secretSha512 = sharedSecret.Sha512(); foreach (var secret in secrets) { var secretDescription = string.IsNullOrEmpty(secret.Description) ? "no description" : secret.Description; // this validator is only applicable to shared secrets if (secret.Type != IdentityServerConstants.SecretTypes.SharedSecret) { _logger.LogDebug("Skipping secret: {description}, secret is not of type {type}.", secretDescription, IdentityServerConstants.SecretTypes.SharedSecret); continue; } bool isValid = false; byte[] secretBytes; try { secretBytes = Convert.FromBase64String(secret.Value); } catch (FormatException) { _logger.LogInformation("Secret: {description} uses invalid hashing algorithm.", secretDescription); return(fail); } if (secretBytes.Length == 32) { isValid = TimeConstantComparer.IsEqual(secret.Value, secretSha256); } else if (secretBytes.Length == 64) { isValid = TimeConstantComparer.IsEqual(secret.Value, secretSha512); } else { _logger.LogInformation("Secret: {description} uses invalid hashing algorithm.", secretDescription); return(fail); } if (isValid) { return(success); } } _logger.LogDebug("No matching hashed secret found."); return(fail); }
/// <summary> /// Validates a secret /// </summary> /// <param name="secrets">The stored secrets.</param> /// <param name="parsedSecret">The received secret.</param> /// <returns> /// A validation result /// </returns> /// <exception cref="System.ArgumentNullException">Id or cedential</exception> public Task <SecretValidationResult> ValidateAsync(IEnumerable <Secret> secrets, ParsedSecret parsedSecret) { var fail = Task.FromResult(new SecretValidationResult { Success = false }); var success = Task.FromResult(new SecretValidationResult { Success = true }); if (parsedSecret.Type == Constants.ParsedSecretTypes.SharedSecret) { var sharedSecret = parsedSecret.Credential as string; if (parsedSecret.Id.IsMissing() || sharedSecret.IsMissing()) { throw new ArgumentNullException("Id or cedential"); } var secretSha256 = sharedSecret.Sha256(); var secretSha512 = sharedSecret.Sha512(); foreach (var secret in secrets) { // this validator is only applicable to shared secrets if (secret.Type != Constants.SecretTypes.SharedSecret) { continue; } bool isValid = false; byte[] secretBytes; // check if client secret is still valid if (secret.Expiration.HasExpired()) { continue; } try { secretBytes = Convert.FromBase64String(secret.Value); } catch (FormatException) { Logger.Error("Secret uses invalid hashing algorithm"); return(fail); } if (secretBytes.Length == 32) { isValid = TimeConstantComparer.IsEqual(secret.Value, secretSha256); } else if (secretBytes.Length == 64) { isValid = TimeConstantComparer.IsEqual(secret.Value, secretSha512); } else { Logger.Error("Secret uses invalid hashing algorithm"); return(fail); } if (isValid) { return(success); } } } return(fail); }