Skip to content

Commit

Permalink
Added ctor accepting inner factory (#437)
Browse files Browse the repository at this point in the history
* Added ctor accepting inner factory
* Added tests
* Bumped version to 10.0.0-beta9
  • Loading branch information
abatishchev authored Sep 21, 2022
1 parent 0381094 commit e59150f
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 102 deletions.
90 changes: 56 additions & 34 deletions src/JWT/Algorithms/DelegateAlgorithmFactory.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,56 @@
using System;

namespace JWT.Algorithms
{
/// <summary>
/// Implements <see href="IAlgorithmFactory" /> by returning the supplied <see href="IJwtAlgorithm" /> while ignoring parameters.
/// </summary>
public sealed class DelegateAlgorithmFactory : IAlgorithmFactory
{
private readonly Func<IJwtAlgorithm> _algFactory;

/// <summary>
/// Creates an instance of <see cref="DelegateAlgorithmFactory" /> with supplied delegate to an algorithm.
/// </summary>
/// <exception cref="ArgumentNullException" />
public DelegateAlgorithmFactory(Func<IJwtAlgorithm> algFactory) =>
_algFactory = algFactory ?? throw new ArgumentNullException(nameof(algFactory));

/// <summary>
/// Creates an instance of <see cref="DelegateAlgorithmFactory" /> with supplied algorithm.
/// </summary>
/// <exception cref="ArgumentNullException" />
public DelegateAlgorithmFactory(IJwtAlgorithm algorithm) :
this(() => algorithm)
{
if (algorithm is null)
throw new ArgumentNullException(nameof(algorithm));
}

/// <inheritdoc />
public IJwtAlgorithm Create(JwtDecoderContext context) =>
_algFactory();
}
}
using System;

namespace JWT.Algorithms
{
/// <summary>
/// Implements <see href="IAlgorithmFactory" /> by returning the supplied <see href="IJwtAlgorithm" /> while ignoring parameters.
/// </summary>
public sealed class DelegateAlgorithmFactory : IAlgorithmFactory
{
private readonly Func<JwtDecoderContext, IJwtAlgorithm> _algFactory;

/// <summary>
/// Creates an instance of <see cref="DelegateAlgorithmFactory" /> with supplied delegate to an algorithm with a context.
/// </summary>
/// <exception cref="ArgumentNullException" />
public DelegateAlgorithmFactory(Func<JwtDecoderContext, IJwtAlgorithm> algFactory) =>
_algFactory = algFactory ?? throw new ArgumentNullException(nameof(algFactory));

/// <summary>
/// Creates an instance of <see cref="DelegateAlgorithmFactory" /> with supplied delegate to an algorithm.
/// </summary>
/// <exception cref="ArgumentNullException" />
public DelegateAlgorithmFactory(Func<IJwtAlgorithm> algFactory)
: this(_ => algFactory())
{
if (algFactory is null)
throw new ArgumentNullException(nameof(algFactory));
}

/// <summary>
/// Creates an instance of <see cref="DelegateAlgorithmFactory" /> with supplied algorithm factory.
/// </summary>
/// <exception cref="ArgumentNullException" />
public DelegateAlgorithmFactory(IAlgorithmFactory algFactory) :
this(c => algFactory?.Create(c))
{
if (algFactory is null)
throw new ArgumentNullException(nameof(algFactory));
}

/// <summary>
/// Creates an instance of <see cref="DelegateAlgorithmFactory" /> with supplied algorithm.
/// </summary>
/// <exception cref="ArgumentNullException" />
public DelegateAlgorithmFactory(IJwtAlgorithm algorithm) :
this(() => algorithm)
{
if (algorithm is null)
throw new ArgumentNullException(nameof(algorithm));
}

/// <inheritdoc />
public IJwtAlgorithm Create(JwtDecoderContext context) =>
_algFactory(context);
}
}
132 changes: 66 additions & 66 deletions src/JWT/Algorithms/RSAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -1,70 +1,70 @@
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace JWT.Algorithms
{
/// <summary>
/// RSASSA-PKCS1-v1_5 using SHA-256
/// </summary>
public abstract class RSAlgorithm : CertificateAlgorithm<RSA>
{
/// <summary>
/// Creates an instance of <see cref="RSAlgorithm" /> using the provided pair of public and private keys.
/// </summary>
/// <param name="publicKey">The public key for verifying the data.</param>
/// <param name="privateKey">The private key for signing the data.</param>
protected RSAlgorithm(RSA publicKey, RSA privateKey)
: base(publicKey, privateKey)
{
}

/// <summary>
/// Creates an instance of <see cref="RSAlgorithm" /> using the provided public key only.
/// </summary>
/// <remarks>
/// An instance created using this constructor can only be used for verifying the data, not for signing it.
/// </remarks>
/// <param name="publicKey">The public key for verifying the data.</param>
protected RSAlgorithm(RSA publicKey)
: base(publicKey)
{
}

/// <summary>
/// Creates an instance using the provided certificate.
/// </summary>
/// <param name="cert">The certificate having a public key and an optional private key.</param>
protected RSAlgorithm(X509Certificate2 cert)
: base(cert)
{
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace JWT.Algorithms
{
/// <summary>
/// RSASSA-PKCS1-v1_5 using SHA-256
/// </summary>
public abstract class RSAlgorithm : CertificateAlgorithm<RSA>
{
/// <summary>
/// Creates an instance of <see cref="RSAlgorithm" /> using the provided pair of public and private keys.
/// </summary>
/// <param name="publicKey">The public key for verifying the data.</param>
/// <param name="privateKey">The private key for signing the data.</param>
protected RSAlgorithm(RSA publicKey, RSA privateKey)
: base(publicKey, privateKey)
{
}

/// <summary>
/// Creates an instance of <see cref="RSAlgorithm" /> using the provided public key only.
/// </summary>
/// <remarks>
/// An instance created using this constructor can only be used for verifying the data, not for signing it.
/// </remarks>
/// <param name="publicKey">The public key for verifying the data.</param>
protected RSAlgorithm(RSA publicKey)
: base(publicKey)
{
}

/// <summary>
/// Creates an instance using the provided certificate.
/// </summary>
/// <param name="cert">The certificate having a public key and an optional private key.</param>
protected RSAlgorithm(X509Certificate2 cert)
: base(cert)
{
}

protected override RSA GetPublicKey(X509Certificate2 cert) =>
#if NETSTANDARD || NETCOREAPP || NET462
cert.GetRSAPublicKey();
#else
(RSA)cert.PublicKey.Key;
#endif

protected override RSA GetPrivateKey(X509Certificate2 cert) =>
#if NETSTANDARD || NETCOREAPP || NET462
protected override RSA GetPublicKey(X509Certificate2 cert) =>
#if NETSTANDARD || NETCOREAPP || NET462
cert.GetRSAPublicKey();
#else
(RSA)cert.PublicKey.Key;
#endif

protected override RSA GetPrivateKey(X509Certificate2 cert) =>
#if NETSTANDARD || NETCOREAPP || NET462
cert.GetRSAPrivateKey();
#else
(RSA)cert.PrivateKey;
#endif

protected override byte[] SignData(byte[] bytesToSign) =>
#if NET35 || NET40
((RSACryptoServiceProvider)_privateKey).SignData(bytesToSign, this.HashAlgorithmName.Name);
#else
#else
(RSA)cert.PrivateKey;
#endif

protected override byte[] SignData(byte[] bytesToSign) =>
#if NET35 || NET40
((RSACryptoServiceProvider)_privateKey).SignData(bytesToSign, this.HashAlgorithmName.Name);
#else
_privateKey.SignData(bytesToSign, this.HashAlgorithmName, RSASignaturePadding.Pkcs1);
#endif

protected override bool VerifyData(byte[] bytesToSign, byte[] signature) =>
#if NET35 || NET40
((RSACryptoServiceProvider)_publicKey).VerifyData(bytesToSign, this.HashAlgorithmName.Name, signature);
#else
_publicKey.VerifyData(bytesToSign, signature, this.HashAlgorithmName, RSASignaturePadding.Pkcs1);
#endif
}
}
#endif

protected override bool VerifyData(byte[] bytesToSign, byte[] signature) =>
#if NET35 || NET40
((RSACryptoServiceProvider)_publicKey).VerifyData(bytesToSign, this.HashAlgorithmName.Name, signature);
#else
_publicKey.VerifyData(bytesToSign, signature, this.HashAlgorithmName, RSASignaturePadding.Pkcs1);
#endif
}
}
2 changes: 1 addition & 1 deletion src/JWT/JWT.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<Authors>Alexander Batishchev, John Sheehan, Michael Lehenbauer</Authors>
<PackageTags>jwt;json;authorization</PackageTags>
<PackageLicenseExpression>CC0-1.0</PackageLicenseExpression>
<Version>10.0.0-beta8</Version>
<Version>10.0.0-beta9</Version>
<FileVersion>10.0.0.0</FileVersion>
<AssemblyVersion>10.0.0.0</AssemblyVersion>
<RootNamespace>JWT</RootNamespace>
Expand Down
14 changes: 13 additions & 1 deletion src/JWT/Serializers/DelegateJsonSerializerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,32 @@ internal sealed class DelegateJsonSerializerFactory : IJsonSerializerFactory
{
private readonly Func<IJsonSerializer> _factory;

/// <summary>
/// Creates an instance of <see cref="DelegateJsonSerializerFactory" /> with supplied JSON serializer.
/// </summary>
/// <exception cref="ArgumentNullException" />
public DelegateJsonSerializerFactory(IJsonSerializer jsonSerializer) :
this(() => jsonSerializer)
{
if (jsonSerializer is null)
throw new ArgumentNullException(nameof(jsonSerializer));
}

/// <summary>
/// Creates an instance of <see cref="DelegateJsonSerializerFactory" /> with supplied serializer JSON serializer factory.
/// </summary>
/// <exception cref="ArgumentNullException" />
public DelegateJsonSerializerFactory(IJsonSerializerFactory factory) :
this(() => factory.Create())
this(() => factory?.Create())
{
if (factory is null)
throw new ArgumentNullException(nameof(factory));
}

/// <summary>
/// Creates an instance of <see cref="DelegateJsonSerializerFactory" /> with supplied delegate to a JSON serializer.
/// </summary>
/// <exception cref="ArgumentNullException" />
public DelegateJsonSerializerFactory(Func<IJsonSerializer> factory) =>
_factory = factory ?? throw new ArgumentNullException(nameof(factory));

Expand Down
65 changes: 65 additions & 0 deletions tests/JWT.Tests.Common/Algorithms/DelegateAlgorithmFactoryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using FluentAssertions;
using JWT.Algorithms;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace JWT.Tests.Algorithms
{
[TestClass]
public class DelegateAlgorithmFactoryTests
{
[TestMethod]
public void Ctor_Accepting_Func_IJwtAlgorithm_Should_Throw_When_Param_Is_Null()
{
Action action = () => new DelegateAlgorithmFactory((Func<IJwtAlgorithm>)null);

action.Should()
.Throw<ArgumentNullException>();
}

[TestMethod]
public void Ctor_Accepting_Func_JwtDecoderContext_IJwtAlgorithm_Should_Throw_When_Param_Is_Null()
{
Action action = () => new DelegateAlgorithmFactory((Func<JwtDecoderContext, IJwtAlgorithm>)null);

action.Should()
.Throw<ArgumentNullException>();
}

[TestMethod]
public void Ctor_Accepting_IAlgorithmFactory_Should_Throw_When_Param_Is_Null()
{
Action action = () => new DelegateAlgorithmFactory((IAlgorithmFactory)null);

action.Should()
.Throw<ArgumentNullException>();
}

[TestMethod]
public void Ctor_Accepting_IAlgorithm_Should_Throw_When_Param_Is_Null()
{
Action action = () => new DelegateAlgorithmFactory((IJwtAlgorithm)null);

action.Should()
.Throw<ArgumentNullException>();
}

[TestMethod]
public void Create_Should_Return_Algorithm_Returned_By_Inner_Factory()
{
var expected = Mock.Of<IJwtAlgorithm>();

var context = new JwtDecoderContext();
var innerFactory = new Mock<IAlgorithmFactory>();
innerFactory.Setup(f => f.Create(context)).Returns(expected);

var delFactory = new DelegateAlgorithmFactory(innerFactory.Object);
var actual = delFactory.Create(context);

actual.Should().Be(expected);

innerFactory.VerifyAll();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using FluentAssertions;
using JWT.Serializers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace JWT.Tests.Algorithms
{
[TestClass]
public class DelegateJsonSerializerFactoryTests
{
[TestMethod]
public void Ctor_Accepting_JsonSerializer_Should_Throw_When_Param_Is_Null()
{
Action action = () => new DelegateJsonSerializerFactory((IJsonSerializer)null);

action.Should()
.Throw<ArgumentNullException>();
}

[TestMethod]
public void Ctor_Accepting_Factory_Should_Throw_When_Param_Is_Null()
{
Action action = () => new DelegateJsonSerializerFactory((IJsonSerializerFactory)null);

action.Should()
.Throw<ArgumentNullException>();
}

[TestMethod]
public void Ctor_Accepting_Func_Should_Throw_When_Param_Is_Null()
{
Action action = () => new DelegateJsonSerializerFactory((Func<IJsonSerializer>)null);

action.Should()
.Throw<ArgumentNullException>();
}

[TestMethod]
public void Create_Should_Return_JsonSerializer_Returned_By_Inner_Factory()
{
var expected = Mock.Of<IJsonSerializer>();

var delFactory = new DelegateJsonSerializerFactory(() => expected);
var actual = delFactory.Create();

actual.Should().Be(expected);
}
}
}

0 comments on commit e59150f

Please sign in to comment.