diff --git a/src/JWT/Builder/JwtBuilder.cs b/src/JWT/Builder/JwtBuilder.cs index 7b77c64c3..abd1b302b 100644 --- a/src/JWT/Builder/JwtBuilder.cs +++ b/src/JWT/Builder/JwtBuilder.cs @@ -303,10 +303,13 @@ private void TryCreateValidator() private void EnsureCanBuild() { if (!CanBuild()) - throw new InvalidOperationException("Can't build a token. Check if you have call all of the followng methods:\r\n" + - $"-{nameof(WithAlgorithm)}" + Environment.NewLine + - $"-{nameof(WithSerializer)}" + Environment.NewLine + - $"-{nameof(WithUrlEncoder)}."); + { + throw new InvalidOperationException( + "Can't build a token. Check if you have call all of the following methods:" +Environment.NewLine + + $"-{nameof(WithAlgorithm)}" + Environment.NewLine + + $"-{nameof(WithSerializer)}" + Environment.NewLine + + $"-{nameof(WithUrlEncoder)}."); + } if (!HasOnlyOneSecret()) throw new InvalidOperationException("You can't provide more than one secret to use for encoding."); @@ -315,10 +318,13 @@ private void EnsureCanBuild() private void EnsureCanDecode() { if (!CanDecode()) - throw new InvalidOperationException("Can't decode a token. Check if you have call all of the following methods:" + Environment.NewLine + - $"-{nameof(WithSerializer)}" + Environment.NewLine + - $"-{nameof(WithValidator)}" + Environment.NewLine + - $"-{nameof(WithUrlEncoder)}."); + { + throw new InvalidOperationException( + "Can't decode a token. Check if you have call all of the following methods:" + Environment.NewLine + + $"-{nameof(WithSerializer)}" + Environment.NewLine + + $"-{nameof(WithValidator)}" + Environment.NewLine + + $"-{nameof(WithUrlEncoder)}."); + } } /// diff --git a/src/JWT/IJwtDecoder.cs b/src/JWT/IJwtDecoder.cs index 7e9568085..9ec010f45 100644 --- a/src/JWT/IJwtDecoder.cs +++ b/src/JWT/IJwtDecoder.cs @@ -50,7 +50,7 @@ public interface IJwtDecoder /// The keys bytes provided which one of them was used to sign the JWT /// Whether to verify the signature (default is true) /// A string containing the JSON payload - string Decode(string token, IReadOnlyCollection keys, bool verify); + string Decode(string token, byte[][] keys, bool verify); #endregion @@ -104,7 +104,7 @@ public interface IJwtDecoder /// An object representing the payload /// Thrown if the verify parameter was true and the signature was NOT valid or if the JWT was signed with an unsupported algorithm /// Thrown if the verify parameter was true and the token has an expired exp claim - IDictionary DecodeToObject(string token, IReadOnlyCollection keys, bool verify); + IDictionary DecodeToObject(string token, byte[][] keys, bool verify); #endregion @@ -164,7 +164,7 @@ public interface IJwtDecoder /// An object representing the payload /// Thrown if the verify parameter was true and the signature was NOT valid or if the JWT was signed with an unsupported algorithm /// Thrown if the verify parameter was true and the token has an expired exp claim - T DecodeToObject(string token, IReadOnlyCollection keys, bool verify); + T DecodeToObject(string token, byte[][] keys, bool verify); #endregion } diff --git a/src/JWT/IJwtValidator.cs b/src/JWT/IJwtValidator.cs index 9acc5c79f..b46f39ad3 100644 --- a/src/JWT/IJwtValidator.cs +++ b/src/JWT/IJwtValidator.cs @@ -5,16 +5,6 @@ /// public interface IJwtValidator { - /// - /// Given the JWT, verifies its signature correctness. - /// - /// >An arbitrary payload (already serialized to JSON) - /// Decoded body - /// Decoded signature - /// The signature is invalid - /// The token has expired - void Validate(string payloadJson, string decodedCrypto, string decodedSignature); - /// /// Given the JWT, verifies its signatures correctness. /// @@ -23,6 +13,6 @@ public interface IJwtValidator /// Decoded signatures /// The signature is invalid /// The token has expired - void Validate(string payloadJson, string decodedCrypto, string[] decodedSignatures); + void Validate(string payloadJson, string decodedCrypto, params string[] decodedSignatures); } } \ No newline at end of file diff --git a/src/JWT/JWT.csproj b/src/JWT/JWT.csproj index ded27e2e0..685ddcc9e 100644 --- a/src/JWT/JWT.csproj +++ b/src/JWT/JWT.csproj @@ -29,9 +29,9 @@ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - 5.3.1 - 5.0.0.0 - 5.0.0.0 + 6.0.0-beta1 + 6.0.0.0 + 6.0.0.0 diff --git a/src/JWT/JwtDecoder.cs b/src/JWT/JwtDecoder.cs index c377104a2..ddf0574cf 100644 --- a/src/JWT/JwtDecoder.cs +++ b/src/JWT/JwtDecoder.cs @@ -98,13 +98,13 @@ public string Decode(string token, byte[] key, bool verify) /// /// /// - public string Decode(string token, IReadOnlyCollection keys, bool verify) + public string Decode(string token, byte[][] keys, bool verify) { if (String.IsNullOrWhiteSpace(token)) throw new ArgumentException(nameof(token)); if (keys is null) throw new ArgumentNullException(nameof(keys)); - if (keys.Count == 0 || !AllKeysHaveValues(keys)) + if (keys.Length == 0 || !AllKeysHaveValues(keys)) throw new ArgumentOutOfRangeException(nameof(keys)); if (verify) @@ -152,7 +152,7 @@ public IDictionary DecodeToObject(string token, byte[] key, bool /// /// /// - public IDictionary DecodeToObject(string token, IReadOnlyCollection keys, bool verify) => + public IDictionary DecodeToObject(string token, byte[][] keys, bool verify) => DecodeToObject>(token, keys, verify); /// @@ -193,75 +193,38 @@ public T DecodeToObject(string token, byte[] key, bool verify) /// /// /// - public T DecodeToObject(string token, IReadOnlyCollection keys, bool verify) + public T DecodeToObject(string token, byte[][] keys, bool verify) { var payload = Decode(token, keys, verify); return _jsonSerializer.Deserialize(payload); } /// - /// Prepares data before calling + /// Prepares data before calling /// /// The array representation of a JWT /// The key that was used to sign the JWT /// /// /// - public void Validate(string[] parts, byte[] key) => + public void Validate(string[] parts, params byte[] key) => Validate(new JwtParts(parts), key); /// - /// Prepares data before calling - /// - /// The JWT parts - /// The key that was used to sign the JWT - /// - /// - /// - public void Validate(JwtParts jwt, byte[] key) - { - if (jwt is null) - throw new ArgumentNullException(nameof(jwt)); - if (key is null) - throw new ArgumentNullException(nameof(key)); - if (key.Length == 0) - throw new ArgumentOutOfRangeException(nameof(key)); - - var crypto = _urlEncoder.Decode(jwt.Signature); - var decodedCrypto = Convert.ToBase64String(crypto); - - var headerJson = GetString(_urlEncoder.Decode(jwt.Header)); - var headerData = _jsonSerializer.Deserialize>(headerJson); - - var payload = jwt.Payload; - var payloadJson = GetString(_urlEncoder.Decode(payload)); - - var bytesToSign = GetBytes(String.Concat(jwt.Header, ".", payload)); - - var algName = (string)headerData["alg"]; - var alg = _algFactory.Create(algName); - - var signatureData = alg.Sign(key, bytesToSign); - var decodedSignature = Convert.ToBase64String(signatureData); - - _jwtValidator.Validate(payloadJson, decodedCrypto, decodedSignature); - } - - /// - /// Prepares data before calling + /// Prepares data before calling /// /// The JWT parts /// The keys provided which one of them was used to sign the JWT /// /// /// - public void Validate(JwtParts jwt, IReadOnlyCollection keys) + public void Validate(JwtParts jwt, params byte[][] keys) { if (jwt is null) throw new ArgumentNullException(nameof(jwt)); if (keys is null) throw new ArgumentNullException(nameof(keys)); - if (keys.Count == 0 || !AllKeysHaveValues(keys)) + if (keys.Length == 0 || !AllKeysHaveValues(keys)) throw new ArgumentOutOfRangeException(nameof(keys)); var crypto = _urlEncoder.Decode(jwt.Signature); @@ -281,10 +244,11 @@ public void Validate(JwtParts jwt, IReadOnlyCollection keys) var decodedSignatures = keys.Select(key => alg.Sign(key, bytesToSign)) .Select(sd => Convert.ToBase64String(sd)) .ToArray(); + _jwtValidator.Validate(payloadJson, decodedCrypto, decodedSignatures); } private static bool AllKeysHaveValues(IEnumerable keys) => keys.All(key => key.Any()); } -} +} \ No newline at end of file diff --git a/src/JWT/JwtValidator.cs b/src/JWT/JwtValidator.cs index d57c81c0d..91068c908 100644 --- a/src/JWT/JwtValidator.cs +++ b/src/JWT/JwtValidator.cs @@ -28,17 +28,7 @@ public JwtValidator(IJsonSerializer jsonSerializer, IDateTimeProvider dateTimePr /// /// /// - public void Validate(string payloadJson, string decodedCrypto, string decodedSignature) - { - var ex = GetValidationException(payloadJson, decodedCrypto, decodedSignature); - if (ex != null) - throw ex; - } - - /// - /// - /// - public void Validate(string payloadJson, string decodedCrypto, string[] decodedSignatures) + public void Validate(string payloadJson, string decodedCrypto, params string[] decodedSignatures) { var ex = GetValidationException(payloadJson, decodedCrypto, decodedSignatures); if (ex != null) @@ -73,24 +63,7 @@ public bool TryValidate(string payloadJson, string decodedCrypto, string[] decod return ex is null; } - private Exception GetValidationException(string payloadJson, string decodedCrypto, string decodedSignature) - { - if (String.IsNullOrWhiteSpace(payloadJson)) - return new ArgumentException(nameof(payloadJson)); - - if (String.IsNullOrWhiteSpace(decodedCrypto)) - return new ArgumentException(nameof(decodedCrypto)); - - if (String.IsNullOrWhiteSpace(decodedSignature)) - return new ArgumentException(nameof(decodedSignature)); - - if (!CompareCryptoWithSignature(decodedCrypto, decodedSignature)) - return new SignatureVerificationException(decodedCrypto, decodedSignature); - - return GetValidationException(payloadJson); - } - - private Exception GetValidationException(string payloadJson, string decodedCrypto, string[] decodedSignatures) + private Exception GetValidationException(string payloadJson, string decodedCrypto, params string[] decodedSignatures) { if (String.IsNullOrWhiteSpace(payloadJson)) return new ArgumentException(nameof(payloadJson)); @@ -123,7 +96,7 @@ private static bool AreAllDecodedSignaturesNullOrWhiteSpace(IEnumerable private static bool IsAnySignatureValid(string decodedCrypto, IEnumerable decodedSignatures) => decodedSignatures.Any(decodedSignature => CompareCryptoWithSignature(decodedCrypto, decodedSignature)); - /// In the future this method can be opened for extension so made protected virtual + /// In the future this method can be opened for extension thus made protected virtual private static bool CompareCryptoWithSignature(string decodedCrypto, string decodedSignature) { if (decodedCrypto.Length != decodedSignature.Length) @@ -147,7 +120,7 @@ private static bool CompareCryptoWithSignature(string decodedCrypto, string deco /// See https://tools.ietf.org/html/rfc7515#section-4.1.4 /// /// - private static Exception ValidateExpClaim(IDictionary payloadData, double secondsSinceEpoch) + private static Exception ValidateExpClaim(IReadOnlyDictionary payloadData, double secondsSinceEpoch) { if (!payloadData.TryGetValue("exp", out var expObj)) return null; diff --git a/src/JWT/TokenExpiredException.cs b/src/JWT/TokenExpiredException.cs index 6229141ad..1169ca853 100644 --- a/src/JWT/TokenExpiredException.cs +++ b/src/JWT/TokenExpiredException.cs @@ -23,7 +23,7 @@ public TokenExpiredException(string message) /// /// The payload. /// - public IDictionary PayloadData + public IReadOnlyDictionary PayloadData { get => GetOrDefault>(PayloadDataKey); internal set => this.Data.Add(PayloadDataKey, value);