Пример #1
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="SharedSecretAuthenticationHandler"/> class.
        /// </summary>
        ///
        /// <param name="configuration">The configuration of the athentication scheme.</param>
        ///
        public ClientCertificateAuthenticationHandler(ClientCertificateAuthenticationConfiguration configuration,
                                                      IClock clock)
        {
            this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
            this.clock         = clock ?? throw new ArgumentNullException(nameof(clock));

            this.claimsMap = new Lazy <ClientCertificateClaimsMap>(() => CreateCertificateClaimsMap(this.configuration.SerializedCertificateClaimsMapping), LazyThreadSafetyMode.PublicationOnly);
        }
Пример #2
0
        public void ConstructorValidatesClockIsPresent()
        {
            var config = new ClientCertificateAuthenticationConfiguration
            {
                Enabled = true,
                EnforceLocalCertificateValidation  = false,
                SerializedCertificateClaimsMapping = "{\"4497ebb9f0f694d219fe8652a8d4922fead6a5d9\":{\"urn:ordering:security:privilege:sudo\":\"true\"}}"
            };

            Action actionUnderTest = () => new ClientCertificateAuthenticationHandler(config, null);

            actionUnderTest.ShouldThrow <ArgumentNullException>("because the clock must be present")
            .And.ParamName.Should().Be("clock", "because the clock was missing");
        }
Пример #3
0
        public void ConstructorAllowsAnUnspecifiedClaimsMappingIsPresentInConfiguration(string serializedClaimsMap)
        {
            var config = new ClientCertificateAuthenticationConfiguration
            {
                Enabled = true,
                EnforceLocalCertificateValidation  = false,
                SerializedCertificateClaimsMapping = serializedClaimsMap
            };

            var handler   = new ClientCertificateAuthenticationHandler(config, Mock.Of <IClock>());
            var claimsMap = handler.GetType().GetField("claimsMap", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(handler) as Lazy <ClientCertificateClaimsMap>;

            claimsMap.Should().NotBeNull("because the handler should have created a claims map");
            claimsMap.Value.Should().NotBeNull("because a default claims map should be created when no serialized value is present");
            claimsMap.Value.GetCertificateThumbprints().Any().Should().BeFalse("because the defaul claims map should be empty");
        }
Пример #4
0
        public async Task ConfigureDeppendencyResolverDiscoversAuthenticationHandlers()
        {
            var mockConfigurationFactory = new Mock <IConfigurationFactory>();
            var httpConfig         = new HttpConfiguration();
            var sharedSecretConfig = new SharedSecretAuthenticationConfiguration {
                Enabled = true, PrimarySecret = "test", PrimaryKey = "key!"
            };
            var clientCertificateConfig = new ClientCertificateAuthenticationConfiguration {
                Enabled = true, EnforceLocalCertificateValidation = false, SerializedCertificateClaimsMapping = "{\";4497ebb9f0f694d219fe8652a8d4922fead6a5d9\";:{\";urn:ordering:security:privilege:sudo\";:\";true\";}}"
            };

            try
            {
                mockConfigurationFactory
                .Setup(factory => factory.Create(It.IsAny <Type>()))
                .Returns <Type>(type =>
                {
                    if (type == typeof(SharedSecretAuthenticationConfiguration))
                    {
                        return(sharedSecretConfig);
                    }
                    else if (type == typeof(ClientCertificateAuthenticationConfiguration))
                    {
                        return(clientCertificateConfig);
                    }

                    return(Activator.CreateInstance(type));
                });

                Startup.ConfigureDependencyResolver(httpConfig, () => mockConfigurationFactory.Object);

                var locator = httpConfig.DependencyResolver;
                locator.Should().NotBeNull("because the dependency resolver should have been set");

                var authenticationHandlers = locator.GetServices(typeof(IAuthenticationHandler));
                authenticationHandlers.Should().NotBeNullOrEmpty("because the authentication handlers should have been found");

                var expected = typeof(IAuthenticationHandler).Assembly.GetTypes().Where(type => type.GetInterface(nameof(IAuthenticationHandler)) != null);
                authenticationHandlers.Select(handler => handler.GetType()).Should().BeEquivalentTo(expected, "because the locator should discover handlers defined along side the interface");

                await Task.Delay(1000);
            }
            finally
            {
                httpConfig?.DependencyResolver?.Dispose();
            }
        }
Пример #5
0
        public void AuthenticateDoesNotSucceedWithUnexpectedCallerCertificate()
        {
            var config = new ClientCertificateAuthenticationConfiguration
            {
                Enabled = true,
                EnforceLocalCertificateValidation  = false,
                SerializedCertificateClaimsMapping = "{\"NOT-REAL-THUMPRINT\":{\"urn:ordering:security:privilege:sudo\":\"true\"}}"
            };

            var mockClock            = new Mock <IClock>();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var mockDependencyScope  = new Mock <IDependencyScope>();
            var callerCertificate    = new X509Certificate2(Convert.FromBase64String(ClientCertificateAuthenticationHandlerTests.Base64Certificate), ClientCertificateAuthenticationHandlerTests.CertificatePassword);
            var handler              = new ClientCertificateAuthenticationHandler(config, mockClock.Object);
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request              = new HttpRequestMessage();
            var requestContext       = new HttpRequestContext();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = "generic"
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext = new HttpActionContext(controllerContext, mockActionDescriptor.Object);
            var authcontext   = new HttpAuthenticationContext(actionContext, null);

            requestContext.ClientCertificate = callerCertificate;
            controllerContext.RequestContext = requestContext;
            controllerContext.Request        = request;

            request.Properties.Add(HttpPropertyKeys.DependencyScope, mockDependencyScope.Object);
            request.Properties.Add(HttpPropertyKeys.RequestContextKey, requestContext);
            request.Properties.Add(HttpPropertyKeys.ClientCertificateKey, requestContext.ClientCertificate);

            var result = handler.Authenticate(new Dictionary <string, string>(), authcontext);

            result.Should().BeNull("because the caller certificate does not exist in the claims mapping for known certificates");
        }
Пример #6
0
        public void AuthenticateDoesNotSucceedWithMissingCallerCertificate()
        {
            var config = new ClientCertificateAuthenticationConfiguration
            {
                Enabled = true,
                EnforceLocalCertificateValidation  = false,
                SerializedCertificateClaimsMapping = "{\"4497ebb9f0f694d219fe8652a8d4922fead6a5d9\":{\"urn:ordering:security:privilege:sudo\":\"true\"}}"
            };

            var mockClock            = new Mock <IClock>();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var handler              = new ClientCertificateAuthenticationHandler(config, mockClock.Object);
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request              = new HttpRequestMessage();
            var requestContext       = new HttpRequestContext();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = "generic"
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext = new HttpActionContext(controllerContext, mockActionDescriptor.Object);
            var authcontext   = new HttpAuthenticationContext(actionContext, null);

            requestContext.ClientCertificate = null;
            controllerContext.RequestContext = requestContext;
            controllerContext.Request        = request;

            request.Properties.Add(HttpPropertyKeys.RequestContextKey, requestContext);
            request.Properties.Add(HttpPropertyKeys.ClientCertificateKey, requestContext.ClientCertificate);

            var result = handler.Authenticate(new Dictionary <string, string>(), authcontext);

            result.Should().BeNull("because there was no client certificate assocaited with the request");
        }
Пример #7
0
        public void AuthenticatedPrincipalContainsMappedClaims()
        {
            var callerCertificate = new X509Certificate2(Convert.FromBase64String(ClientCertificateAuthenticationHandlerTests.Base64Certificate), ClientCertificateAuthenticationHandlerTests.CertificatePassword);
            var storeCertificate  = new X509Certificate2(Convert.FromBase64String(ClientCertificateAuthenticationHandlerTests.Base64Certificate), ClientCertificateAuthenticationHandlerTests.CertificatePassword);
            var mapping           = new ClientCertificateClaimsMap();

            mapping.AddCertificate(storeCertificate.Thumbprint, new Dictionary <string, string>
            {
                { CustomClaimTypes.MayAccessPriviledgedOperations, "true" },
                { CustomClaimTypes.Partner, "SQUIRE" }
            });

            var config = new ClientCertificateAuthenticationConfiguration
            {
                Enabled = true,
                EnforceLocalCertificateValidation  = false,
                SerializedCertificateClaimsMapping = mapping.Serialize()
            };

            var mockClock            = new Mock <IClock>();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var mockDependencyScope  = new Mock <IDependencyScope>();
            var mockHandler          = new Mock <ClientCertificateAuthenticationHandler>(config, mockClock.Object)
            {
                CallBase = true
            };
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request              = new HttpRequestMessage();
            var requestContext       = new HttpRequestContext();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = "generic"
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext = new HttpActionContext(controllerContext, mockActionDescriptor.Object);
            var authcontext   = new HttpAuthenticationContext(actionContext, null);

            requestContext.ClientCertificate = callerCertificate;
            controllerContext.RequestContext = requestContext;
            controllerContext.Request        = request;

            request.Properties.Add(HttpPropertyKeys.DependencyScope, mockDependencyScope.Object);
            request.Properties.Add(HttpPropertyKeys.RequestContextKey, requestContext);
            request.Properties.Add(HttpPropertyKeys.ClientCertificateKey, requestContext.ClientCertificate);

            mockClock.Setup(clock => clock.GetCurrentInstant()).Returns(Instant.FromDateTimeUtc(storeCertificate.NotBefore.AddDays(1).ToUniversalTime()));

            mockHandler.Protected()
            .Setup <X509Certificate2>("SearchForCertificate", ItExpr.Is <string>(thumb => String.Equals(thumb, storeCertificate.Thumbprint, StringComparison.OrdinalIgnoreCase)), ItExpr.IsAny <bool>())
            .Returns(storeCertificate);

            var principal = mockHandler.Object.Authenticate(new Dictionary <string, string>(), authcontext) as ClaimsPrincipal;

            principal.Should().NotBeNull("because the certificate was valid and a claims principal should have been returned");

            var identity = principal.Identity as ClaimsIdentity;

            identity.Should().NotBeNull("becaue the principal should contain a valid indentity");


            foreach (var mappedClaim in mapping[callerCertificate.Thumbprint])
            {
                var identityClaim = identity.FindFirst(claim => claim.Type == mappedClaim.Key);
                identityClaim.Should().NotBeNull($"because the { mappedClaim.Key } claim should exist");
                identityClaim.Value.Should().Be(mappedClaim.Value, $"because the claim value for { mappedClaim.Key } should match the mapping");
            }
        }
Пример #8
0
        public void AuthenticateSucceedsForValidCertificates()
        {
            var callerCertificate = new X509Certificate2(Convert.FromBase64String(ClientCertificateAuthenticationHandlerTests.Base64Certificate), ClientCertificateAuthenticationHandlerTests.CertificatePassword);
            var storeCertificate  = new X509Certificate2(Convert.FromBase64String(ClientCertificateAuthenticationHandlerTests.Base64Certificate), ClientCertificateAuthenticationHandlerTests.CertificatePassword);
            var mapping           = new ClientCertificateClaimsMap();

            mapping.AddCertificate(storeCertificate.Thumbprint, new Dictionary <string, string>
            {
                { CustomClaimTypes.MayAccessPriviledgedOperations, "true" },
                { CustomClaimTypes.Partner, "SQUIRE" }
            });

            var config = new ClientCertificateAuthenticationConfiguration
            {
                Enabled = true,
                EnforceLocalCertificateValidation  = false,
                SerializedCertificateClaimsMapping = mapping.Serialize()
            };

            var mockClock            = new Mock <IClock>();
            var mockActionDescriptor = new Mock <HttpActionDescriptor>();
            var mockDependencyScope  = new Mock <IDependencyScope>();
            var mockHandler          = new Mock <ClientCertificateAuthenticationHandler>(config, mockClock.Object)
            {
                CallBase = true
            };
            var httpConfiguration    = new HttpConfiguration();
            var routeData            = new HttpRouteData(new HttpRoute());
            var request              = new HttpRequestMessage();
            var requestContext       = new HttpRequestContext();
            var controllerDescriptor = new HttpControllerDescriptor {
                Configuration = httpConfiguration, ControllerName = "generic"
            };
            var controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerDescriptor
            };
            var actionContext = new HttpActionContext(controllerContext, mockActionDescriptor.Object);
            var authcontext   = new HttpAuthenticationContext(actionContext, null);

            requestContext.ClientCertificate = callerCertificate;
            controllerContext.RequestContext = requestContext;
            controllerContext.Request        = request;

            request.Properties.Add(HttpPropertyKeys.DependencyScope, mockDependencyScope.Object);
            request.Properties.Add(HttpPropertyKeys.RequestContextKey, requestContext);
            request.Properties.Add(HttpPropertyKeys.ClientCertificateKey, requestContext.ClientCertificate);

            mockClock.Setup(clock => clock.GetCurrentInstant()).Returns(Instant.FromDateTimeUtc(storeCertificate.NotBefore.AddDays(1).ToUniversalTime()));

            mockHandler.Protected()
            .Setup <X509Certificate2>("SearchForCertificate", ItExpr.Is <string>(thumb => String.Equals(thumb, storeCertificate.Thumbprint, StringComparison.OrdinalIgnoreCase)), ItExpr.IsAny <bool>())
            .Returns(storeCertificate)
            .Verifiable();

            var result = mockHandler.Object.Authenticate(new Dictionary <string, string>(), authcontext);

            result.Should().NotBeNull("because the certificate was valid");

            mockHandler.VerifyAll();
        }