/// <summary>
        /// Build an instance of <see cref="NodeEntitlements"/> from the information supplied on the
        /// command line by the user
        /// </summary>
        /// <returns>Either a usable (and completely valid) <see cref="NodeEntitlements"/> or a set
        /// of errors.</returns>
        private Errorable <NodeEntitlements> Build()
        {
            var entitlement = new NodeEntitlements();
            var errors      = new List <string>();

            ConfigureOptional(VirtualMachineId, url => entitlement.WithVirtualMachineId(url));
            Configure(NotBefore, notBefore => entitlement.FromInstant(notBefore));
            Configure(NotAfter, notAfter => entitlement.UntilInstant(notAfter));
            Configure(Audience, audience => entitlement.WithAudience(audience));
            Configure(Issuer, issuer => entitlement.WithIssuer(issuer));
            ConfigureAll(Addresses, address => entitlement.AddIpAddress(address));
            ConfigureAll(Applications, app => entitlement.AddApplication(app));

            if (errors.Any())
            {
                return(Errorable.Failure <NodeEntitlements>(errors));
            }

            return(Errorable.Success(entitlement));

            // <param name="readConfiguration">function to read the configuration value.</param>
            // <param name="applyConfiguration">function to modify our configuration with the value read.</param>
            void Configure <V>(Func <Errorable <V> > readConfiguration, Func <V, NodeEntitlements> applyConfiguration)
            {
                readConfiguration().Match(
                    whenSuccessful: value => entitlement = applyConfiguration(value),
                    whenFailure: e => errors.AddRange(e));
            }

            // <param name="readConfiguration">function to read the configuration value.</param>
            // <param name="applyConfiguration">function to modify our configuration with the value read.</param>
            void ConfigureOptional <V>(Func <Errorable <V> > readConfiguration, Func <V, NodeEntitlements> applyConfiguration)
                where V : class
예제 #2
0
            public void WhenSuccess_CallsActionWithExpectedValue()
            {
                var errorable = Errorable.Success(43);

                errorable.Match(
                    v => v.Should().Be(43),
                    errors => throw new InvalidOperationException("Should not be called"));
            }
예제 #3
0
            public void WhenSuccess_ReturnsExpectedValueFromFunction()
            {
                var errorable = Errorable.Success(43);
                var result    = errorable.Match <int>(
                    v => 128,
                    errors => throw new InvalidOperationException("Should not be called"));

                result.Should().Be(128);
            }
예제 #4
0
 public void WhenSuccess_CallsFunctionWithExpectedValue()
 {
     var errorable = Errorable.Success(43);
     var result    = errorable.Match <int>(
         v =>
     {
         v.Should().Be(43);
         return(128);    // Needs a return value so this is a Func<int,int>
     },
         errors => throw new InvalidOperationException("Should not be called"));
 }
예제 #5
0
        private static Errorable <X509Certificate2> FindCertificate(string purpose, string thumbprint)
        {
            if (string.IsNullOrEmpty(thumbprint))
            {
                // No certificate requested, so we successfully return null
                return(Errorable.Success <X509Certificate2>(null));
            }

            var t = new CertificateThumbprint(thumbprint);

            return(CertificateStore.FindByThumbprint(purpose, t));
        }
예제 #6
0
        private static Errorable <LogLevel> TryParse(string level, string purpose, LogLevel defaultLevel)
        {
            if (string.IsNullOrEmpty(level))
            {
                return(Errorable.Success(defaultLevel));
            }

            if (Enum.TryParse <LogLevel>(level, true, out var result))
            {
                // Successfully parsed the string
                return(Errorable.Success(result));
            }

            return(Errorable.Failure <LogLevel>(
                       $"Failed to recognize {purpose} log level '{level}'; valid choices are: error, warning, information, and debug."));
        }
예제 #7
0
        /// <summary>
        /// Verify the provided software entitlement token
        /// </summary>
        /// <param name="tokenString">A software entitlement token to verify.</param>
        /// <param name="expectedAudience">The audience for whom the token should be intended.</param>
        /// <param name="expectedIssuer">The issuer who should have created the token.</param>
        /// <param name="application">The specific application id of the application </param>
        /// <param name="ipAddress">Address of the machine requesting token validation.</param>
        /// <returns>Either a software entitlement describing the approved entitlement, or errors
        /// explaining why it wasn't approved.</returns>
        public Errorable <NodeEntitlements> Verify(
            string tokenString,
            string expectedAudience,
            string expectedIssuer,
            string application,
            IPAddress ipAddress)
        {
            var validationParameters = new TokenValidationParameters
            {
                ValidateAudience         = true,
                ValidAudience            = expectedAudience,
                ValidateIssuer           = true,
                ValidIssuer              = expectedIssuer,
                ValidateLifetime         = true,
                RequireExpirationTime    = true,
                RequireSignedTokens      = SigningKey != null,
                ClockSkew                = TimeSpan.FromSeconds(60),
                IssuerSigningKey         = SigningKey,
                ValidateIssuerSigningKey = true,
                TokenDecryptionKey       = EncryptionKey
            };

            try
            {
                var handler   = new JwtSecurityTokenHandler();
                var principal = handler.ValidateToken(tokenString, validationParameters, out var token);

                if (!VerifyApplication(principal, application))
                {
                    return(ApplicationNotEntitledError(application));
                }

                if (!VerifyIpAddress(principal, ipAddress))
                {
                    return(MachineNotEntitledError(ipAddress));
                }

                var entitlementIdClaim = principal.FindFirst(Claims.EntitlementId);
                if (entitlementIdClaim == null)
                {
                    return(IdentifierNotPresentError());
                }

                var result = new NodeEntitlements()
                             .FromInstant(new DateTimeOffset(token.ValidFrom))
                             .UntilInstant(new DateTimeOffset(token.ValidTo))
                             .AddApplication(application)
                             .WithIdentifier(entitlementIdClaim.Value)
                             .AddIpAddress(ipAddress);

                var virtualMachineIdClaim = principal.FindFirst(Claims.VirtualMachineId);
                if (virtualMachineIdClaim != null)
                {
                    result = result.WithVirtualMachineId(virtualMachineIdClaim.Value);
                }

                return(Errorable.Success(result));
            }
            catch (SecurityTokenNotYetValidException exception)
            {
                return(TokenNotYetValidError(exception.NotBefore));
            }
            catch (SecurityTokenExpiredException exception)
            {
                return(TokenExpiredError(exception.Expires));
            }
            catch (SecurityTokenException exception)
            {
                return(InvalidTokenError(exception.Message));
            }
        }
예제 #8
0
            public void GivenValue_ReturnsResultWithNoErrors()
            {
                var result = Errorable.Success(42);

                result.Errors.Should().HaveCount(0);
            }
예제 #9
0
            public void WhenSuccess_ReturnsExpectedValue()
            {
                var result = Errorable.Success(42);

                result.Value.Should().Be(42);
            }
예제 #10
0
            public void GivenValue_ReturnsResultWithValue()
            {
                var result = Errorable.Success(42);

                result.HasValue.Should().BeTrue();
            }