/// <inheritdoc/> public string GenerateSignedJWT() { try { TimeSpan timeSpanIat = DateTime.UtcNow - new DateTime(1970, 1, 1); TimeSpan timeSpanExp = DateTime.UtcNow.AddHours(1) - new DateTime(1970, 1, 1); var payload = new JwtPayload { { "sub", _configuration.ClientId }, { "iat", (int)timeSpanIat.TotalSeconds }, { "exp", (int)timeSpanExp.TotalSeconds }, { "iss", _configuration.ClientId }, { "aud", $"{_configuration.OktaDomain}oauth2/v1/token" }, { "jti", Guid.NewGuid() }, }; var jsonWebKey = new Microsoft.IdentityModel.Tokens.JsonWebKey(JsonConvert.SerializeObject(_configuration.PrivateKey)); var securityToken = new JwtSecurityToken(new JwtHeader(GetSigningCredentials(_configuration.PrivateKey)), payload); return(new JwtSecurityTokenHandler().WriteToken(securityToken)); } catch (Exception e) { throw new InvalidOperationException("Something went wrong when creating the signed JWT. Verify your private key.", e); } }
public async Task <SigningCredentials> GetSigningCredentialsAsync() { async Task <SigningCredentials> FromFile(IFileInfo file) { using var ms = new MemoryStream(); await file .CreateReadStream() .CopyToAsync(ms); var json = Encoding.UTF8.GetString(ms.ToArray()); var jwk = new JsonWebKey(json); return(new SigningCredentials( jwk, RS256)); } var files = Files.GetDirectoryContents("rotation") .OrderByDescending(x => Int32.Parse(x.Name.Split('.')[1])) .ToList(); switch (files.Count()) { case 0: throw new ArgumentOutOfRangeException("There must be at least 1 key in the keystore."); case 1: return(await FromFile(files[0])); default: return(await FromFile(files[1])); } }
/// <summary> /// 產生jwk檔 /// </summary> /// <param name="builder"></param> /// <returns></returns> public static IIdentityServerBuilder AddCustomCredential( this IIdentityServerBuilder builder) { bool persistKey = true; string filename = "Credential.jwk"; IdentityServerConstants.RsaSigningAlgorithm signingAlgorithm = IdentityServerConstants.RsaSigningAlgorithm.RS256; if (File.Exists(filename)) { var json = File.ReadAllText(filename); var jwk = new JsonWebKey(json); return(builder.AddSigningCredential(jwk, jwk.Alg)); } else { var key = CryptoHelper.CreateRsaSecurityKey(); var jwk = JsonWebKeyConverter.ConvertFromRSASecurityKey(key); jwk.Alg = signingAlgorithm.ToString(); if (persistKey) { File.WriteAllText(filename, System.Text.Json.JsonSerializer.Serialize(jwk)); } return(builder.AddSigningCredential(key, signingAlgorithm)); } }
private async Task CreateSelfSignedCertificateAsync(GeneralTrackCertificateViewModel generalCertificate) { generalCertificate.Form.ClearError(); try { var trackKeyResponse = await TrackService.UpdateTrackKeyContainedAsync(generalCertificate.Form.Model.Map <TrackKeyItemContainedRequest>(afterMap: afterMap => { afterMap.CreateSelfSigned = true; afterMap.Key = null; })); var certificate = new MTokens.JsonWebKey((generalCertificate.Form.Model.IsPrimary ? trackKeyResponse.PrimaryKey : trackKeyResponse.SecondaryKey).JsonSerialize()).ToX509Certificate(); generalCertificate.Subject = certificate.Subject; generalCertificate.ValidFrom = certificate.NotBefore; generalCertificate.ValidTo = certificate.NotAfter; generalCertificate.IsValid = certificate.IsValid(); generalCertificate.Thumbprint = certificate.Thumbprint; generalCertificate.CreateMode = false; generalCertificate.Edit = false; } catch (TokenUnavailableException) { await(OpenidConnectPkce as TenantOpenidConnectPkce).TenantLoginAsync(); } catch (HttpRequestException ex) { generalCertificate.Form.SetError(ex.Message); } catch (FoxIDsApiException aex) { generalCertificate.Form.SetError(aex.Message); } }
/// <summary> /// Converts a X509 Certificate to Microsoft JWK. /// </summary> public static MSTokens.JsonWebKey ToMSJsonWebKey(this X509Certificate2 certificate, bool includePrivateKey = false) { if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } var jwk = new MSTokens.JsonWebKey(); jwk.Kty = MSTokens.JsonWebAlgorithmsKeyTypes.RSA; var securityKey = new MSTokens.X509SecurityKey(certificate); jwk.X5c.Add(Convert.ToBase64String(certificate.RawData)); jwk.X5t = certificate.Thumbprint; jwk.Kid = WebEncoders.Base64UrlEncode(certificate.GetCertHash()); var parameters = (securityKey.PublicKey as RSA).ExportParameters(false); jwk.N = WebEncoders.Base64UrlEncode(parameters.Modulus); jwk.E = WebEncoders.Base64UrlEncode(parameters.Exponent); if (includePrivateKey && securityKey.PrivateKeyStatus == MSTokens.PrivateKeyStatus.Exists) { parameters = (securityKey.PrivateKey as RSA).ExportParameters(true); jwk.D = WebEncoders.Base64UrlEncode(parameters.D); jwk.P = WebEncoders.Base64UrlEncode(parameters.P); jwk.Q = WebEncoders.Base64UrlEncode(parameters.Q); jwk.DP = WebEncoders.Base64UrlEncode(parameters.DP); jwk.DQ = WebEncoders.Base64UrlEncode(parameters.DQ); jwk.QI = WebEncoders.Base64UrlEncode(parameters.InverseQ); } return(jwk); }
public async Task <IEnumerable <SecurityKeyInfo> > GetValidationKeysAsync() { async Task <SecurityKeyInfo> FromFile(IFileInfo file) { using var ms = new MemoryStream(); await file .CreateReadStream() .CopyToAsync(ms); var json = Encoding.UTF8.GetString(ms.ToArray()); var jwk = new JsonWebKey(json); return(new SecurityKeyInfo { Key = jwk, SigningAlgorithm = RS256 }); } var files = Files.GetDirectoryContents("rotation") .Select(FromFile); return(await Task.WhenAll(files)); }
private async Task <object> GetAccessTokenAsync(OAuthOptions oAuthOptions, Microsoft.IdentityModel.Tokens.JsonWebKey jsonWebKey) { var clientAssertion = CreateJwtClientAssertion(oAuthOptions, jsonWebKey); using (var httpClient = new HttpClient()) { var parameters = new Dictionary <string, string> { { "grant_type", "authorization_code" }, { "code", oAuthOptions.AuthorizationCode }, { "client_assertion", HttpUtility.UrlEncode(clientAssertion) }, { "client_assertion_type", ClientAssertionType }, { "scope", string.Join(SpaceSeparator, oAuthOptions.Scopes) }, { "redirect_uri", oAuthOptions.RedirectUri.AbsoluteUri } }; var httpContent = new FormUrlEncodedContent(parameters); var httpResponse = await httpClient.PostAsync(oAuthOptions.TokenEndpoint, httpContent); return(!httpResponse.IsSuccessStatusCode ? (object)JsonConvert.DeserializeObject <ErrorResponse>(await httpResponse.Content.ReadAsStringAsync()) : JsonConvert.DeserializeObject <AuthorizationCodeFlowResponse>(await httpResponse.Content.ReadAsStringAsync())); } }
/// <summary> /// Sets the temporary signing credential. /// </summary> /// <param name="builder">The builder.</param> /// <param name="persistKey">Specifies if the temporary key should be persisted to disk.</param> /// <param name="filename">The filename.</param> /// <param name="signingAlgorithm">The signing algorithm (defaults to RS256)</param> /// <returns></returns> public static IIdentityServerBuilder AddDeveloperSigningCredential( this IIdentityServerBuilder builder, bool persistKey = true, string filename = null, IdentityServerConstants.RsaSigningAlgorithm signingAlgorithm = IdentityServerConstants.RsaSigningAlgorithm.RS256) { if (filename == null) { filename = Path.Combine(Directory.GetCurrentDirectory(), "tempkey.jwk"); } if (File.Exists(filename)) { var json = File.ReadAllText(filename); var jwk = new JsonWebKey(json); return(builder.AddSigningCredential(jwk, jwk.Alg)); } else { var key = CryptoHelper.CreateRsaSecurityKey(); var jwk = JsonWebKeyConverter.ConvertFromRSASecurityKey(key); jwk.Alg = signingAlgorithm.ToString(); if (persistKey) { File.WriteAllText(filename, JsonConvert.SerializeObject(jwk)); } return(builder.AddSigningCredential(key, signingAlgorithm)); } }
public GeneralTrackCertificateViewModel(JsonWebKey key, bool isPrimary) : this(isPrimary) { var certificate = new MTokens.JsonWebKey(key.JsonSerialize()).ToX509Certificate(); Subject = certificate.Subject; ValidFrom = certificate.NotBefore; ValidTo = certificate.NotAfter; IsValid = certificate.IsValid(); Thumbprint = certificate.Thumbprint; }
public async Task <IActionResult> ExchangeRefreshToken() { var oauthResponse = _dbContext.OAuthResponses.Find(1); if (oauthResponse == null) { return(RedirectToAction("Index", "Home")); } var jsonWebKeyText = Encoding.UTF8.GetString(Convert.FromBase64String(_oAuthOptions.JsonWebKey)); var jsonWebKey = new Microsoft.IdentityModel.Tokens.JsonWebKey(jsonWebKeyText); var clientAssertion = CreateJwtClientAssertion(_oAuthOptions, jsonWebKey); var parameters = new Dictionary <string, string> { { "grant_type", "refresh_token" }, { "refresh_token", oauthResponse.RefreshToken }, { "client_assertion", HttpUtility.UrlEncode(clientAssertion) }, { "client_assertion_type", ClientAssertionType } }; var httpClient = _httpClientFactory.CreateClient("OAuthClient"); var httpContent = new FormUrlEncodedContent(parameters); var httpResponse = await httpClient.PostAsync(_oAuthOptions.TokenEndpoint, httpContent); if (httpResponse.IsSuccessStatusCode) { var responseString = await httpResponse.Content.ReadAsStringAsync(); var oAuthResponse = JsonConvert.DeserializeObject <OAuthResponse>(responseString); var dbValue = _dbContext.OAuthResponses.Find(1); if (dbValue != null) { _dbContext.Entry(dbValue).State = EntityState.Detached; _dbContext.OAuthResponses.Attach(oAuthResponse); _dbContext.Entry(oAuthResponse).State = EntityState.Modified; } else { _dbContext.OAuthResponses.Add(oAuthResponse); } _dbContext.SaveChanges(); return(RedirectToAction("Index", "Api")); } var errorResponse = JsonConvert.DeserializeObject <ErrorResponse>(await httpResponse.Content.ReadAsStringAsync()); return(UnprocessableEntity(errorResponse)); }
public async Task Jwks_entries_should_countain_crv() { var ecdsaKey = CryptoHelper.CreateECDsaSecurityKey(JsonWebKeyECTypes.P256); var parameters = ecdsaKey.ECDsa.ExportParameters(true); IdentityServerPipeline pipeline = new IdentityServerPipeline(); var jsonWebKeyFromECDsa = new JsonWebKey() { Kty = JsonWebAlgorithmsKeyTypes.EllipticCurve, Use = "sig", Kid = ecdsaKey.KeyId, KeyId = ecdsaKey.KeyId, X = Base64UrlEncoder.Encode(parameters.Q.X), Y = Base64UrlEncoder.Encode(parameters.Q.Y), D = Base64UrlEncoder.Encode(parameters.D), Crv = JsonWebKeyECTypes.P256, Alg = SecurityAlgorithms.EcdsaSha256 }; pipeline.OnPostConfigureServices += services => { // add ECDsa as JsonWebKey services.AddIdentityServerBuilder() .AddSigningCredential(jsonWebKeyFromECDsa, SecurityAlgorithms.EcdsaSha256); }; pipeline.Initialize("/ROOT"); var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration/jwks"); var json = await result.Content.ReadAsStringAsync(); var data = JObject.Parse(json); var keys = data["keys"]; keys.Should().NotBeNull(); var key = keys[1]; key.Should().NotBeNull(); var crv = key["crv"]; crv.Should().NotBeNull(); crv.Value <string>().Should().Be(JsonWebKeyECTypes.P256); }
private string CreateJwtClientAssertion(OAuthOptions oAuthOptions, Microsoft.IdentityModel.Tokens.JsonWebKey jwk) { var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { Expires = DateTime.UtcNow.AddMinutes(960), SigningCredentials = new SigningCredentials(jwk, SecurityAlgorithms.RsaSha256Signature), Subject = new ClaimsIdentity(new List <Claim> { new Claim("sub", oAuthOptions.ClientId.ToString()), new Claim("iss", oAuthOptions.ClientId.ToString()), new Claim("jti", Guid.NewGuid().ToString()), new Claim("aud", oAuthOptions.TokenEndpoint.ToString()) }) }; return(tokenHandler.WriteToken(tokenHandler.CreateJwtSecurityToken(tokenDescriptor))); }
public async Task RunAsync() { Console.WriteLine("Retrieving access token..."); var jsonWebKeyText = Encoding.UTF8.GetString(Convert.FromBase64String(_oAuthOptions.JsonWebKey)); var jsonWebKey = new Microsoft.IdentityModel.Tokens.JsonWebKey(jsonWebKeyText); var accessTokenResponse = await GetAccessTokenAsync(_oAuthOptions, jsonWebKey); Console.WriteLine(accessTokenResponse); if (accessTokenResponse is AuthorizationCodeFlowResponse authorizationCodeFlowResponse) { var pdoResult = await CallGipodApi(authorizationCodeFlowResponse.AccessToken); Console.WriteLine(JToken.Parse(pdoResult).ToString(Formatting.Indented)); //This whould be done just before the access token expires. Console.WriteLine("Exchanging refresh token..."); accessTokenResponse = await ExchangeRefreshTokenAsync(_oAuthOptions, jsonWebKey, authorizationCodeFlowResponse.RefreshToken); Console.WriteLine(accessTokenResponse); } }
private async Task <object> ExchangeRefreshTokenAsync(OAuthOptions oAuthOptions, Microsoft.IdentityModel.Tokens.JsonWebKey jsonWebKey, string refreshToken) { var clientAssertion = CreateJwtClientAssertion(oAuthOptions, jsonWebKey); using (var httpClient = new HttpClient()) { var parameters = new Dictionary <string, string> { { "grant_type", "refresh_token" }, { "refresh_token", refreshToken }, { "client_assertion", HttpUtility.UrlEncode(clientAssertion) }, { "client_assertion_type", ClientAssertionType } }; var httpContent = new FormUrlEncodedContent(parameters); var httpResponse = await httpClient.PostAsync(oAuthOptions.TokenEndpoint, httpContent); return(!httpResponse.IsSuccessStatusCode ? (object)JsonConvert.DeserializeObject <ErrorResponse>(await httpResponse.Content.ReadAsStringAsync()) : JsonConvert.DeserializeObject <AuthorizationCodeFlowResponse>(await httpResponse.Content.ReadAsStringAsync())); } }
public static JsonWebKeySet GetJwks() { KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback( (authority, resource, scope) => KeyVaultUtil.GetToken(authority, resource, scope))); var key = Task.Run(() => keyVaultClient.GetKeyAsync(SignKey())).ConfigureAwait(false).GetAwaiter().GetResult(); var e = Base64UrlEncoder.Encode(key.Key.E); var n = Base64UrlEncoder.Encode(key.Key.E); var jsonWebKey = new Microsoft.IdentityModel.Tokens.JsonWebKey() { Kid = KEY, Kty = "RSA", E = Base64UrlEncoder.Encode(key.Key.E), N = Base64UrlEncoder.Encode(key.Key.N), Alg = "RS256" }; JsonWebKeySet jsonWebKeySet = new JsonWebKeySet(); jsonWebKeySet.Keys.Add(jsonWebKey); return(jsonWebKeySet); }
public async Task RunAsync() { Console.WriteLine("Retrieving access token..."); var jsonWebKeyText = Encoding.UTF8.GetString(Convert.FromBase64String(_oAuthOptions.JsonWebKey)); var jsonWebKey = new Microsoft.IdentityModel.Tokens.JsonWebKey(jsonWebKeyText); var accessTokenResponse = await GetAccessTokenAsync(_oAuthOptions, jsonWebKey); Console.WriteLine(accessTokenResponse); if (accessTokenResponse is ClientCredentialGrantResponse clientCredentialGrantResponse) { Console.WriteLine("Calling Gipod API..."); var searchBaseAddress = _configuration["GipodApiUrl"]; var queryStringParameters = new Dictionary <string, string> { { "limit", "1" }, { "offset", "0" } }; var pdoResult = await _dataProvider.Get(new Uri(searchBaseAddress + "/api/v1/public-domain-occupancies"), queryStringParameters, clientCredentialGrantResponse.AccessToken); Console.WriteLine(JToken.Parse(pdoResult).ToString(Formatting.Indented)); } }
private async Task ShowUpdateUpPartyAsync(GeneralUpPartyViewModel upParty) { upParty.CreateMode = false; upParty.DeleteAcknowledge = false; upParty.ShowAdvanced = false; upParty.Error = null; upParty.Edit = true; if (upParty.Type == PartyTypes.Login) { try { var generalLoginUpParty = upParty as GeneralLoginUpPartyViewModel; var loginUpParty = await UpPartyService.GetLoginUpPartyAsync(upParty.Name); await generalLoginUpParty.Form.InitAsync(loginUpParty.Map <LoginUpPartyViewModel>(afterMap: afterMap => { afterMap.EnableSingleLogout = !loginUpParty.DisableSingleLogout; afterMap.EnableResetPassword = !loginUpParty.DisableResetPassword; if (afterMap.ClaimTransforms?.Count > 0) { afterMap.ClaimTransforms = afterMap.ClaimTransforms.MapClaimTransforms(); } })); } catch (TokenUnavailableException) { await(OpenidConnectPkce as TenantOpenidConnectPkce).TenantLoginAsync(); } catch (HttpRequestException ex) { upParty.Error = ex.Message; } } else if (upParty.Type == PartyTypes.Oidc) { try { var generalOidcUpParty = upParty as GeneralOidcUpPartyViewModel; var oidcUpParty = await UpPartyService.GetOidcUpPartyAsync(upParty.Name); await generalOidcUpParty.Form.InitAsync(oidcUpParty.Map((Action <OidcUpPartyViewModel>)(afterMap => { if (oidcUpParty.UpdateState == PartyUpdateStates.Manual) { afterMap.IsManual = true; } if (oidcUpParty.UpdateState == PartyUpdateStates.AutomaticStopped) { afterMap.AutomaticStopped = true; } else { afterMap.AutomaticStopped = false; } afterMap.EnableSingleLogout = !oidcUpParty.DisableSingleLogout; if (oidcUpParty.Client != null) { afterMap.Client.EnableFrontChannelLogout = !oidcUpParty.Client.DisableFrontChannelLogout; } foreach (var key in oidcUpParty.Keys) { afterMap.KeyIds.Add(key.Kid); } if (afterMap.ClaimTransforms?.Count > 0) { afterMap.ClaimTransforms = afterMap.ClaimTransforms.MapClaimTransforms(); } }))); } catch (TokenUnavailableException) { await(OpenidConnectPkce as TenantOpenidConnectPkce).TenantLoginAsync(); } catch (HttpRequestException ex) { upParty.Error = ex.Message; } } else if (upParty.Type == PartyTypes.Saml2) { try { var generalSamlUpParty = upParty as GeneralSamlUpPartyViewModel; var samlUpParty = await UpPartyService.GetSamlUpPartyAsync(upParty.Name); await generalSamlUpParty.Form.InitAsync(samlUpParty.Map <SamlUpPartyViewModel>(afterMap => { afterMap.EnableSingleLogout = !samlUpParty.DisableSingleLogout; afterMap.AuthnRequestBinding = samlUpParty.AuthnBinding.RequestBinding; afterMap.AuthnResponseBinding = samlUpParty.AuthnBinding.ResponseBinding; if (!samlUpParty.LogoutUrl.IsNullOrEmpty()) { afterMap.LogoutRequestBinding = samlUpParty.LogoutBinding.RequestBinding; afterMap.LogoutResponseBinding = samlUpParty.LogoutBinding.ResponseBinding; } generalSamlUpParty.CertificateInfoList.Clear(); foreach (var key in afterMap.Keys) { var certificate = new MTokens.JsonWebKey(key.JsonSerialize()).ToX509Certificate(); generalSamlUpParty.CertificateInfoList.Add(new CertificateInfoViewModel { Subject = certificate.Subject, ValidFrom = certificate.NotBefore, ValidTo = certificate.NotAfter, IsValid = certificate.IsValid(), Thumbprint = certificate.Thumbprint, Key = key }); } if (afterMap.ClaimTransforms?.Count > 0) { afterMap.ClaimTransforms = afterMap.ClaimTransforms.MapClaimTransforms(); } })); } catch (TokenUnavailableException) { await(OpenidConnectPkce as TenantOpenidConnectPkce).TenantLoginAsync(); } catch (HttpRequestException ex) { upParty.Error = ex.Message; } } }
internal static RsaAlgorithm ResolveRsaAlgorithm(SecurityKey key, string algorithm, bool requirePrivateKey) { if (key == null) { return(null); } var rsaAlgorithm = new RsaAlgorithm(); var rsaKey = key as RsaSecurityKey; if (rsaKey != null) { if (rsaKey.Rsa != null) { #if NETSTANDARD1_4 rsaAlgorithm.rsa = rsaKey.Rsa; #else rsaAlgorithm.rsaCryptoServiceProvider = rsaKey.Rsa as RSACryptoServiceProvider; #endif return(rsaAlgorithm); } else { #if NETSTANDARD1_4 rsaAlgorithm.rsa = RSA.Create(); rsaAlgorithm.rsa.ImportParameters(rsaKey.Parameters); rsaAlgorithm.dispose = true; #else rsaAlgorithm.rsaCryptoServiceProvider = new RSACryptoServiceProvider(); (rsaAlgorithm.rsaCryptoServiceProvider as RSA).ImportParameters(rsaKey.Parameters); rsaAlgorithm.dispose = true; #endif } return(rsaAlgorithm); } X509SecurityKey x509Key = key as X509SecurityKey; if (x509Key != null) { #if NETSTANDARD1_4 if (requirePrivateKey) { rsaAlgorithm.rsa = x509Key.PrivateKey as RSA; } else { rsaAlgorithm.rsa = x509Key.PublicKey as RSA; } #else if (requirePrivateKey) { rsaAlgorithm.rsaCryptoServiceProviderProxy = new RSACryptoServiceProviderProxy(x509Key.PrivateKey as RSACryptoServiceProvider); } else { rsaAlgorithm.rsaCryptoServiceProviderProxy = new RSACryptoServiceProviderProxy(x509Key.PublicKey as RSACryptoServiceProvider); } #endif return(rsaAlgorithm); } JsonWebKey webKey = key as JsonWebKey; if (webKey != null && webKey.Kty == JsonWebAlgorithmsKeyTypes.RSA) { #if NETSTANDARD1_4 RSAParameters parameters = webKey.CreateRsaParameters(); rsaAlgorithm.rsa = RSA.Create(); rsaAlgorithm.dispose = true; if (rsaAlgorithm.rsa != null) { rsaAlgorithm.rsa.ImportParameters(parameters); } #else RSAParameters parameters = webKey.CreateRsaParameters(); rsaAlgorithm.rsaCryptoServiceProvider = new RSACryptoServiceProvider(); (rsaAlgorithm.rsaCryptoServiceProvider as RSA).ImportParameters(parameters); #endif return(rsaAlgorithm); } return(null); }
/// <summary> /// Returns the JsonWebKeys as a <see cref="IList{SecurityKey}"/>. /// </summary> public IList <SecurityKey> GetSigningKeys() { List <SecurityKey> keys = new List <SecurityKey>(); for (int i = 0; i < Keys.Count; i++) { JsonWebKey webKey = Keys[i]; if (!StringComparer.Ordinal.Equals(webKey.Kty, JsonWebAlgorithmsKeyTypes.RSA)) { continue; } if ((string.IsNullOrWhiteSpace(webKey.Use) || (StringComparer.Ordinal.Equals(webKey.Use, JsonWebKeyUseNames.Sig)))) { if (webKey.X5c != null) { foreach (var certString in webKey.X5c) { try { // Add chaining SecurityKey key = new X509SecurityKey(new X509Certificate2(Convert.FromBase64String(certString))); key.KeyId = webKey.Kid; keys.Add(key); } catch (CryptographicException ex) { throw LogHelper.LogExceptionMessage(new InvalidOperationException(LogHelper.FormatInvariant(LogMessages.IDX10802, webKey.X5c[0]), ex)); } catch (FormatException fex) { throw LogHelper.LogExceptionMessage(new InvalidOperationException(LogHelper.FormatInvariant(LogMessages.IDX10802, webKey.X5c[0]), fex)); } } } if (!string.IsNullOrWhiteSpace(webKey.E) && !string.IsNullOrWhiteSpace(webKey.N)) { try { SecurityKey key = new RsaSecurityKey ( new RSAParameters { Exponent = Base64UrlEncoder.DecodeBytes(webKey.E), Modulus = Base64UrlEncoder.DecodeBytes(webKey.N), } ); key.KeyId = webKey.Kid; keys.Add(key); } catch (CryptographicException ex) { throw LogHelper.LogExceptionMessage(new InvalidOperationException(LogHelper.FormatInvariant(LogMessages.IDX10801, webKey.E, webKey.N), ex)); } catch (FormatException ex) { throw LogHelper.LogExceptionMessage(new InvalidOperationException(LogHelper.FormatInvariant(LogMessages.IDX10801, webKey.E, webKey.N), ex)); } } } } return(keys); }
private SignatureProvider CreateSignatureProvider(SecurityKey key, string algorithm, bool willCreateSignatures) { if (key == null) { throw LogHelper.LogArgumentNullException(nameof(key)); } if (string.IsNullOrEmpty(algorithm)) { throw LogHelper.LogArgumentNullException(nameof(algorithm)); } if (CustomCryptoProvider != null && CustomCryptoProvider.IsSupportedAlgorithm(algorithm, key, willCreateSignatures)) { SignatureProvider signatureProvider = CustomCryptoProvider.Create(algorithm, key, willCreateSignatures) as SignatureProvider; if (signatureProvider == null) { throw LogHelper.LogExceptionMessage(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, LogMessages.IDX10646, algorithm, key, typeof(SignatureProvider)))); } return(signatureProvider); } if (!IsSupportedAlgorithm(algorithm, key)) { throw LogHelper.LogExceptionMessage(new ArgumentException(String.Format(CultureInfo.InvariantCulture, LogMessages.IDX10634, algorithm, key))); } AsymmetricSecurityKey asymmetricKey = key as AsymmetricSecurityKey; if (asymmetricKey != null) { return(new AsymmetricSignatureProvider(asymmetricKey, algorithm, willCreateSignatures)); } SymmetricSecurityKey symmetricKey = key as SymmetricSecurityKey; if (symmetricKey != null) { return(new SymmetricSignatureProvider(symmetricKey, algorithm)); } JsonWebKey jsonWebKey = key as JsonWebKey; if (jsonWebKey != null) { if (jsonWebKey.Kty != null) { if (jsonWebKey.Kty == JsonWebAlgorithmsKeyTypes.RSA || jsonWebKey.Kty == JsonWebAlgorithmsKeyTypes.EllipticCurve) { return(new AsymmetricSignatureProvider(key, algorithm, willCreateSignatures)); } if (jsonWebKey.Kty == JsonWebAlgorithmsKeyTypes.Octet) { return(new SymmetricSignatureProvider(key, algorithm)); } } } // TODO improve this message. Nothing about JsonWebKey is mentioned. throw LogHelper.LogExceptionMessage(new ArgumentException(String.Format(CultureInfo.InvariantCulture, LogMessages.IDX10600, typeof(SignatureProvider), typeof(SecurityKey), typeof(AsymmetricSecurityKey), typeof(SymmetricSecurityKey), key.GetType()))); }
/// <summary> /// Checks if an 'algorithm, key' pair is supported. /// </summary> /// <param name="algorithm">the algorithm to check.</param> /// <param name="key">the <see cref="SecurityKey"/>.</param> /// <returns>true if 'algorithm, key' pair is supported.</returns> public virtual bool IsSupportedAlgorithm(string algorithm, SecurityKey key) { if (CustomCryptoProvider != null && CustomCryptoProvider.IsSupportedAlgorithm(algorithm, key)) { return(true); } if (key as RsaSecurityKey != null) { return(IsRsaAlgorithmSupported(algorithm)); } var x509Key = key as X509SecurityKey; if (x509Key != null) { #if NETSTANDARD1_4 if (x509Key.PublicKey as RSA == null) { return(false); } #else if (x509Key.PublicKey as RSACryptoServiceProvider == null) { return(false); } #endif return(IsRsaAlgorithmSupported(algorithm)); } JsonWebKey jsonWebKey = key as JsonWebKey; if (jsonWebKey != null) { if (jsonWebKey.Kty == JsonWebAlgorithmsKeyTypes.RSA) { return(IsRsaAlgorithmSupported(algorithm)); } else if (jsonWebKey.Kty == JsonWebAlgorithmsKeyTypes.EllipticCurve) { return(IsEcdsaAlgorithmSupported(algorithm)); } else if (jsonWebKey.Kty == JsonWebAlgorithmsKeyTypes.Octet) { return(IsSymmetricAlgorithmSupported(algorithm)); } return(false); } ECDsaSecurityKey ecdsaSecurityKey = key as ECDsaSecurityKey; if (ecdsaSecurityKey != null) { return(IsEcdsaAlgorithmSupported(algorithm)); } if (key as SymmetricSecurityKey != null) { return(IsSymmetricAlgorithmSupported(algorithm)); } return(false); }
private SignatureProvider CreateProvider(SecurityKey key, string algorithm, bool willCreateSignatures) { if (key == null) { throw LogHelper.LogArgumentNullException(nameof(key)); } if (string.IsNullOrWhiteSpace(algorithm)) { throw LogHelper.LogArgumentNullException(nameof(algorithm)); } if (CustomCryptoProvider != null && CustomCryptoProvider.IsSupportedAlgorithm(algorithm, key, willCreateSignatures)) { SignatureProvider signatureProvider = CustomCryptoProvider.Create(algorithm, key, willCreateSignatures) as SignatureProvider; if (signatureProvider == null) { throw LogHelper.LogException <InvalidOperationException>(LogMessages.IDX10646, key, algorithm, typeof(SignatureProvider)); } return(signatureProvider); } if (!IsSupportedAlgorithm(algorithm, key)) { throw LogHelper.LogException <ArgumentException>(LogMessages.IDX10634, algorithm, key); } AsymmetricSecurityKey asymmetricKey = key as AsymmetricSecurityKey; if (asymmetricKey != null) { return(new AsymmetricSignatureProvider(asymmetricKey, algorithm, willCreateSignatures)); } SymmetricSecurityKey symmetricKey = key as SymmetricSecurityKey; if (symmetricKey != null) { return(new SymmetricSignatureProvider(symmetricKey, algorithm)); } JsonWebKey jsonWebKey = key as JsonWebKey; if (jsonWebKey != null) { if (jsonWebKey.Kty != null) { if (jsonWebKey.Kty == JsonWebAlgorithmsKeyTypes.RSA || jsonWebKey.Kty == JsonWebAlgorithmsKeyTypes.EllipticCurve) { return(new AsymmetricSignatureProvider(key, algorithm, willCreateSignatures)); } if (jsonWebKey.Kty == JsonWebAlgorithmsKeyTypes.Octet) { return(new SymmetricSignatureProvider(key, algorithm)); } } } throw LogHelper.LogException <ArgumentException>(LogMessages.IDX10600, typeof(SignatureProvider), typeof(SecurityKey), typeof(AsymmetricSecurityKey), typeof(SymmetricSecurityKey), key.GetType()); }
internal ECDsaSecurityKey(JsonWebKey webKey, bool usePrivateKey) : base(webKey) { ECDsa = ECDsaAdapter.Instance.CreateECDsa(webKey, usePrivateKey); webKey.ConvertedSecurityKey = this; }
private async Task ShowUpdateDownPartyAsync(GeneralDownPartyViewModel downParty) { downParty.CreateMode = false; downParty.DeleteAcknowledge = false; downParty.ShowAdvanced = false; downParty.Error = null; downParty.Edit = true; if (downParty.Type == PartyTypes.Oidc) { try { var generalOidcDownParty = downParty as GeneralOidcDownPartyViewModel; var oidcDownParty = await DownPartyService.GetOidcDownPartyAsync(downParty.Name); var oidcDownSecrets = await DownPartyService.GetOidcClientSecretDownPartyAsync(downParty.Name); await generalOidcDownParty.Form.InitAsync(oidcDownParty.Map((Action <OidcDownPartyViewModel>)(afterMap => { if (afterMap.Client == null) { generalOidcDownParty.EnableClientTab = false; } else { generalOidcDownParty.EnableClientTab = true; afterMap.Client.ExistingSecrets = oidcDownSecrets.Select(s => new OAuthClientSecretViewModel { Name = s.Name, Info = s.Info }).ToList(); var defaultResourceScopeIndex = afterMap.Client.ResourceScopes.FindIndex(r => r.Resource.Equals(generalOidcDownParty.Name, StringComparison.Ordinal)); if (defaultResourceScopeIndex > -1) { afterMap.Client.DefaultResourceScope = true; var defaultResourceScope = afterMap.Client.ResourceScopes[defaultResourceScopeIndex]; if (defaultResourceScope.Scopes?.Count() > 0) { foreach (var scope in defaultResourceScope.Scopes) { afterMap.Client.DefaultResourceScopeScopes.Add(scope); } } afterMap.Client.ResourceScopes.RemoveAt(defaultResourceScopeIndex); } else { afterMap.Client.DefaultResourceScope = false; } afterMap.Client.ScopesViewModel = afterMap.Client.Scopes.Map <List <OidcDownScopeViewModel> >() ?? new List <OidcDownScopeViewModel>(); } if (afterMap.Resource == null) { generalOidcDownParty.EnableResourceTab = false; } else { generalOidcDownParty.EnableResourceTab = true; } if (afterMap.ClaimTransforms?.Count > 0) { afterMap.ClaimTransforms = afterMap.ClaimTransforms.MapClaimTransforms(); } }))); } catch (TokenUnavailableException) { await(OpenidConnectPkce as TenantOpenidConnectPkce).TenantLoginAsync(); } catch (HttpRequestException ex) { downParty.Error = ex.Message; } } else if (downParty.Type == PartyTypes.OAuth2) { try { var generalOAuthDownParty = downParty as GeneralOAuthDownPartyViewModel; var oauthDownParty = await DownPartyService.GetOAuthDownPartyAsync(downParty.Name); var oauthDownSecrets = await DownPartyService.GetOAuthClientSecretDownPartyAsync(downParty.Name); await generalOAuthDownParty.Form.InitAsync(oauthDownParty.Map <OAuthDownPartyViewModel>(afterMap => { if (afterMap.Client == null) { generalOAuthDownParty.EnableClientTab = false; } else { generalOAuthDownParty.EnableClientTab = true; afterMap.Client.ExistingSecrets = oauthDownSecrets.Select(s => new OAuthClientSecretViewModel { Name = s.Name, Info = s.Info }).ToList(); var defaultResourceScopeIndex = afterMap.Client.ResourceScopes.FindIndex(r => r.Resource.Equals(generalOAuthDownParty.Name, StringComparison.Ordinal)); if (defaultResourceScopeIndex > -1) { afterMap.Client.DefaultResourceScope = true; var defaultResourceScope = afterMap.Client.ResourceScopes[defaultResourceScopeIndex]; if (defaultResourceScope.Scopes?.Count() > 0) { foreach (var scope in defaultResourceScope.Scopes) { afterMap.Client.DefaultResourceScopeScopes.Add(scope); } } afterMap.Client.ResourceScopes.RemoveAt(defaultResourceScopeIndex); } else { afterMap.Client.DefaultResourceScope = false; } afterMap.Client.ScopesViewModel = afterMap.Client.Scopes.Map <List <OAuthDownScopeViewModel> >() ?? new List <OAuthDownScopeViewModel>(); } if (afterMap.Resource == null) { generalOAuthDownParty.EnableResourceTab = false; } else { generalOAuthDownParty.EnableResourceTab = true; } if (afterMap.ClaimTransforms?.Count > 0) { afterMap.ClaimTransforms = afterMap.ClaimTransforms.MapClaimTransforms(); } })); } catch (TokenUnavailableException) { await(OpenidConnectPkce as TenantOpenidConnectPkce).TenantLoginAsync(); } catch (HttpRequestException ex) { downParty.Error = ex.Message; } } else if (downParty.Type == PartyTypes.Saml2) { try { var generalSamlDownParty = downParty as GeneralSamlDownPartyViewModel; var samlDownParty = await DownPartyService.GetSamlDownPartyAsync(downParty.Name); await generalSamlDownParty.Form.InitAsync(samlDownParty.Map <SamlDownPartyViewModel>(afterMap => { afterMap.AuthnRequestBinding = samlDownParty.AuthnBinding.RequestBinding; afterMap.AuthnResponseBinding = samlDownParty.AuthnBinding.ResponseBinding; if (!samlDownParty.LoggedOutUrl.IsNullOrEmpty()) { afterMap.LogoutRequestBinding = samlDownParty.LogoutBinding.RequestBinding; afterMap.LogoutResponseBinding = samlDownParty.LogoutBinding.ResponseBinding; } generalSamlDownParty.CertificateInfoList.Clear(); if (afterMap.Keys?.Count() > 0) { foreach (var key in afterMap.Keys) { var certificate = new MTokens.JsonWebKey(key.JsonSerialize()).ToX509Certificate(); generalSamlDownParty.CertificateInfoList.Add(new CertificateInfoViewModel { Subject = certificate.Subject, ValidFrom = certificate.NotBefore, ValidTo = certificate.NotAfter, Thumbprint = certificate.Thumbprint, Key = key }); } } if (afterMap.ClaimTransforms?.Count > 0) { afterMap.ClaimTransforms = afterMap.ClaimTransforms.MapClaimTransforms(); } })); } catch (TokenUnavailableException) { await(OpenidConnectPkce as TenantOpenidConnectPkce).TenantLoginAsync(); } catch (HttpRequestException ex) { downParty.Error = ex.Message; } } }
private void CreateECDsaFromJsonWebKey(JsonWebKey webKey, bool willCreateSignatures) { if (webKey == null) { throw LogHelper.LogArgumentNullException(nameof(webKey)); } if (webKey.Crv == null) { throw LogHelper.LogArgumentNullException(nameof(webKey.Crv)); } if (webKey.X == null) { throw LogHelper.LogArgumentNullException(nameof(webKey.X)); } if (webKey.Y == null) { throw LogHelper.LogArgumentNullException(nameof(webKey.Y)); } GCHandle keyBlobHandle = new GCHandle(); try { uint dwMagic = GetMagicValue(webKey.Crv, willCreateSignatures); uint cbKey = GetKeyByteCount(webKey.Crv); byte[] keyBlob; if (willCreateSignatures) { keyBlob = new byte[3 * cbKey + 2 * Marshal.SizeOf <uint>()]; } else { keyBlob = new byte[2 * cbKey + 2 * Marshal.SizeOf <uint>()]; } keyBlobHandle = GCHandle.Alloc(keyBlob, GCHandleType.Pinned); IntPtr keyBlobPtr = keyBlobHandle.AddrOfPinnedObject(); byte[] x = Base64UrlEncoder.DecodeBytes(webKey.X); byte[] y = Base64UrlEncoder.DecodeBytes(webKey.Y); Marshal.WriteInt64(keyBlobPtr, 0, dwMagic); Marshal.WriteInt64(keyBlobPtr, 4, cbKey); int index = 8; foreach (byte b in x) { Marshal.WriteByte(keyBlobPtr, index++, b); } foreach (byte b in y) { Marshal.WriteByte(keyBlobPtr, index++, b); } if (willCreateSignatures) { if (webKey.D == null) { throw LogHelper.LogArgumentNullException(nameof(webKey.D)); } byte[] d = Base64UrlEncoder.DecodeBytes(webKey.D); foreach (byte b in d) { Marshal.WriteByte(keyBlobPtr, index++, b); } Marshal.Copy(keyBlobPtr, keyBlob, 0, keyBlob.Length); using (CngKey cngKey = CngKey.Import(keyBlob, CngKeyBlobFormat.EccPrivateBlob)) { _ecdsa = new ECDsaCng(cngKey); _disposeEcdsa = true; } } else { Marshal.Copy(keyBlobPtr, keyBlob, 0, keyBlob.Length); using (CngKey cngKey = CngKey.Import(keyBlob, CngKeyBlobFormat.EccPublicBlob)) { _ecdsa = new ECDsaCng(cngKey); _disposeEcdsa = true; } } } finally { if (keyBlobHandle != null) { keyBlobHandle.Free(); } } }
internal static ECDsa ECDsaNotSupported(JsonWebKey jsonWebKey, bool usePrivateKey) { // we will get here on platforms that are not supported. throw LogHelper.LogExceptionMessage(new PlatformNotSupportedException(LogMessages.IDX10690)); }
/// <summary> /// Creates an ECDsa object using the <paramref name="jsonWebKey"/> and <paramref name="usePrivateKey"/>. /// 'ECParameters' structure is available in .NET Framework 4.7+, .NET Standard 1.6+, and .NET Core 1.0+. /// This method is supported only on Windows as other platforms don't support operations with <see cref="CngKey"/>. /// </summary> private ECDsa CreateECDsaUsingCNGKey(JsonWebKey jsonWebKey, bool usePrivateKey) { if (jsonWebKey == null) { throw LogHelper.LogArgumentNullException(nameof(jsonWebKey)); } if (jsonWebKey.Crv == null) { throw LogHelper.LogArgumentNullException(nameof(jsonWebKey.Crv)); } if (jsonWebKey.X == null) { throw LogHelper.LogArgumentNullException(nameof(jsonWebKey.X)); } if (jsonWebKey.Y == null) { throw LogHelper.LogArgumentNullException(nameof(jsonWebKey.Y)); } GCHandle keyBlobHandle = new GCHandle(); try { uint dwMagic = GetMagicValue(jsonWebKey.Crv, usePrivateKey); uint cbKey = GetKeyByteCount(jsonWebKey.Crv); byte[] keyBlob; #if NET45 if (usePrivateKey) { keyBlob = new byte[3 * cbKey + 2 * Marshal.SizeOf(typeof(uint))]; } else { keyBlob = new byte[2 * cbKey + 2 * Marshal.SizeOf(typeof(uint))]; } #else if (usePrivateKey) { keyBlob = new byte[3 * cbKey + 2 * Marshal.SizeOf <uint>()]; } else { keyBlob = new byte[2 * cbKey + 2 * Marshal.SizeOf <uint>()]; } #endif keyBlobHandle = GCHandle.Alloc(keyBlob, GCHandleType.Pinned); IntPtr keyBlobPtr = keyBlobHandle.AddrOfPinnedObject(); byte[] x = Base64UrlEncoder.DecodeBytes(jsonWebKey.X); if (x.Length > cbKey) { throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(jsonWebKey), LogHelper.FormatInvariant(LogMessages.IDX10675, LogHelper.MarkAsNonPII(nameof(jsonWebKey)), LogHelper.MarkAsNonPII(nameof(jsonWebKey.X)), cbKey, LogHelper.MarkAsNonPII(x.Length)))); } byte[] y = Base64UrlEncoder.DecodeBytes(jsonWebKey.Y); if (y.Length > cbKey) { throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(jsonWebKey), LogHelper.FormatInvariant(LogMessages.IDX10675, LogHelper.MarkAsNonPII(nameof(jsonWebKey)), LogHelper.MarkAsNonPII(nameof(jsonWebKey.Y)), cbKey, LogHelper.MarkAsNonPII(y.Length)))); } Marshal.WriteInt64(keyBlobPtr, 0, dwMagic); Marshal.WriteInt64(keyBlobPtr, 4, cbKey); int index = 8; foreach (byte b in x) { Marshal.WriteByte(keyBlobPtr, index++, b); } foreach (byte b in y) { Marshal.WriteByte(keyBlobPtr, index++, b); } if (usePrivateKey) { if (jsonWebKey.D == null) { throw LogHelper.LogArgumentNullException(nameof(jsonWebKey.D)); } byte[] d = Base64UrlEncoder.DecodeBytes(jsonWebKey.D); if (d.Length > cbKey) { throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(jsonWebKey), LogHelper.FormatInvariant(LogMessages.IDX10675, LogHelper.MarkAsNonPII(nameof(jsonWebKey)), LogHelper.MarkAsNonPII(nameof(jsonWebKey.D)), cbKey, LogHelper.MarkAsNonPII(d.Length)))); } foreach (byte b in d) { Marshal.WriteByte(keyBlobPtr, index++, b); } Marshal.Copy(keyBlobPtr, keyBlob, 0, keyBlob.Length); using (CngKey cngKey = CngKey.Import(keyBlob, CngKeyBlobFormat.EccPrivateBlob)) { return(new ECDsaCng(cngKey)); } } else { Marshal.Copy(keyBlobPtr, keyBlob, 0, keyBlob.Length); using (CngKey cngKey = CngKey.Import(keyBlob, CngKeyBlobFormat.EccPublicBlob)) { return(new ECDsaCng(cngKey)); } } } catch (Exception ex) { throw LogHelper.LogExceptionMessage(new CryptographicException(LogMessages.IDX10689, ex)); } finally { if (keyBlobHandle != null && keyBlobHandle.IsAllocated) { keyBlobHandle.Free(); } } }
/// <summary> /// Creates an ECDsa object using the <paramref name="jsonWebKey"/> and <paramref name="usePrivateKey"/>. /// </summary> internal ECDsa CreateECDsa(JsonWebKey jsonWebKey, bool usePrivateKey) { return(CreateECDsaFunction(jsonWebKey, usePrivateKey)); }
/// <summary> /// Gets a new SigningCredentials instance. /// </summary> /// <param name="jsonWebKeyConfiguration">The JWK configuration.</param> /// <returns>A <c>SigningCredentials</c> instance. </returns> private SigningCredentials GetSigningCredentials(JsonWebKeyConfiguration jsonWebKeyConfiguration) { var jsonWebKey = new Microsoft.IdentityModel.Tokens.JsonWebKey(JsonConvert.SerializeObject(jsonWebKeyConfiguration)); return(new SigningCredentials(jsonWebKey, GetSecurityAlgorithm(jsonWebKeyConfiguration.Kty))); }
private void ResolveAsymmetricAlgorithm(SecurityKey key, string algorithm, bool willCreateSignatures) { if (key == null) { throw LogHelper.LogArgumentNullException("key"); } if (string.IsNullOrWhiteSpace(algorithm)) { throw LogHelper.LogArgumentNullException("algorithm"); } _hashAlgorithm = GetHashAlgorithmString(algorithm); RsaSecurityKey rsaKey = key as RsaSecurityKey; if (rsaKey != null) { if (rsaKey.Rsa != null) { _rsaCryptoServiceProvider = rsaKey.Rsa as RSACryptoServiceProvider; } if (_rsaCryptoServiceProvider == null) { _rsaCryptoServiceProvider = new RSACryptoServiceProvider(); (_rsaCryptoServiceProvider as RSA).ImportParameters(rsaKey.Parameters); _disposeRsa = true; } return; } X509SecurityKey x509Key = key as X509SecurityKey; if (x509Key != null) { if (willCreateSignatures) { _rsaCryptoServiceProviderProxy = new RSACryptoServiceProviderProxy(x509Key.PrivateKey as RSACryptoServiceProvider); } else { _rsaCryptoServiceProviderProxy = new RSACryptoServiceProviderProxy(x509Key.PublicKey as RSACryptoServiceProvider); } return; } ECDsaSecurityKey ecdsaKey = key as ECDsaSecurityKey; if (ecdsaKey != null) { if (ecdsaKey.ECDsa != null) { _ecdsa = ecdsaKey.ECDsa as ECDsaCng; _ecdsa.HashAlgorithm = new CngAlgorithm(_hashAlgorithm); return; } } JsonWebKey webKey = key as JsonWebKey; if (webKey.Kty == JsonWebAlgorithmsKeyTypes.RSA) { RSAParameters parameters = CreateRsaParametersFromJsonWebKey(webKey, willCreateSignatures); _rsaCryptoServiceProvider = new RSACryptoServiceProvider(); (_rsaCryptoServiceProvider as RSA).ImportParameters(parameters); return; } else if (webKey.Kty == JsonWebAlgorithmsKeyTypes.EllipticCurve) { CreateECDsaFromJsonWebKey(webKey, willCreateSignatures); return; } throw LogHelper.LogExceptionMessage(new ArgumentOutOfRangeException(nameof(key), String.Format(CultureInfo.InvariantCulture, LogMessages.IDX10641, key))); }