Standard.Licensing icon indicating copy to clipboard operation
Standard.Licensing copied to clipboard

LicenseType is not validated

Open mph911 opened this issue 2 years ago • 6 comments

A license is returned as valid despite the different license types, e.g. if License.LicenseType = LicneseType.Trail and one tries to use the following example from your documentation and using the following code:

var passPhrase = "TestPassword101";
var keyGenerator = Standard.Licensing.Security.Cryptography.KeyGenerator.Create();
var keyPair = keyGenerator.GenerateKeyPair();
var privateKey = keyPair.ToEncryptedPrivateKeyString (passPhrase);
var publicKey = keyPair.ToPublicKeyString();

var license = License.New()
    .WithUniqueIdentifier (Guid.NewGuid())
    .As (LicenseType.Trial)
    .ExpiresAt (DateTime.Now.AddDays (30))
    .WithMaximumUtilization (5)
    .WithProductFeatures (new Dictionary<string, string>
        {
            {"Sales Module", "yes"},
            {"Purchase Module", "yes"},
            {"Maximum Transactions", "10000"}
        })
    .LicensedTo ("John Doe", "[email protected]")
    .CreateAndSignWithPrivateKey (privateKey, passPhrase);

var savedLicense = license.ToString();

var licenseToVerify = License.Load (savedLicense);

var validationFailures = license.Validate()
                                .ExpirationDate()
                                .When (lic => lic.Type == LicenseType.Standard)
                                .And()
                                .Signature (publicKey)
                                .AssertValidLicense();

if (validationFailures.Any())
{
    foreach (var failure in validationFailures)
        Console.WriteLine (failure.GetType().Name + ": " + failure.Message + " - " + failure.HowToResolve);
}
else
    Console.WriteLine ("License valid!");


var errors = license.Validate()
       .AssertThat (lic => lic.Type == LicenseType.Standard,
                    new GeneralValidationFailure ("License type wrong!"))
       .AssertValidLicense().ToList();

Console.WriteLine ($"\nErrors found: {errors.Any ()}");

if (errors.Any())
{
    foreach (var failure in errors)
        Console.WriteLine (failure.GetType().Name + ": " + failure.Message + " - " + failure.HowToResolve);
}
else
    Console.WriteLine ("License valid!");

then no validationFailures.Any() == true! but should be false.

When using the Assert.That then the error is detected as can be seen if the above code is run.

Either I did not understand the purpose of the When clause or it is an error.

In the former case, I'd be happy to learn the purpose and in the later to learn about the correction.

Cheers,

Peter

mph911 avatar Mar 23 '22 13:03 mph911

For what it's worth, I am seeing the same. The only difference seems to be that the expiration date comes back as 12/31/9999 5:59:59 PM for Standard vs. Trial which is whatever you had set.

RFC1920 avatar Mar 24 '22 12:03 RFC1920

OK. But that means that the test in the When clause is not used, or do I get it wrong?

mph911 avatar Mar 24 '22 12:03 mph911

I would tend to agree, or I also completely misunderstand the purpose of it.

RFC1920 avatar Mar 24 '22 18:03 RFC1920

Seems that I can also modify the signature and ID randomly and the license still validates as Trial with the expiration of 12/31/9999 :(

RFC1920 avatar Mar 25 '22 11:03 RFC1920

I just checked your provided example and stepped through the logic.

It seem as if the When validation condition is not meant to be used as a check as in

"This is only valid if it is a standard license"

but

"Only check the expiration date if/when this is a standard license" The code that is responsible for this behaviour can currently be found here Standard.Licensing/Validation/ValidationChainBuilder.cs:76 and looks like this:

public IEnumerable<IValidationFailure> AssertValidLicense()
{
    CompleteValidatorChain();

    while (validators.Count > 0)
    {
        var validator = validators.Dequeue();
        if (validator.ValidateWhen != null && !validator.ValidateWhen(license))
            continue;

        if (!validator.Validate(license))
            yield return validator.FailureResult
                         ?? new GeneralValidationFailure
                                {
                                    Message = "License validation failed!"
                                };
    }
}

AntiGuideAkquinet avatar Feb 24 '23 09:02 AntiGuideAkquinet

The issue you describe does indeed seem like a bug:

Seems that I can also modify the signature and ID randomly and the license still validates as Trial with the expiration of 12/31/9999 :(

The example code provides an IEnumerable<IValidationFailure> which seems to return an error like it should the first time it is enumerated. Sadly a second enumeration provides no failures.

grafik

I opened issue #28 to track this.

AntiGuideAkquinet avatar Feb 24 '23 09:02 AntiGuideAkquinet