WCF Authorized Service with SSL Authentication and Username and Password Authentication

I want to publish a WCF service from a console application. For security reasons, I want to communicate over SSL, so I created a self-signed certificate. For authentication, I wrote my own UserNamePasswordValidator. Unfortunately this does not work.

This is my code:

Server

public class Program
{
    public static void Main()
    {
        var baseAddress = new Uri("https://localhost:8080/SelfHostedUsernamePasswordService");

        using (var host = new ServiceHost(typeof(SelfHostedUsernamePasswordService), baseAddress))
        {
            var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
            binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;

            var endpoint = host.AddServiceEndpoint(typeof(ISelfHostedUsernamePasswordService), binding, baseAddress);

            var cf = new ChannelFactory<ISelfHostedUsernamePasswordService>(binding, endpoint.Address);
            cf.Credentials.ClientCertificate.SetCertificate(
                StoreLocation.LocalMachine,
                StoreName.My,
                X509FindType.FindByThumbprint,
                "0000000000000000000000000000000000000000");

            var metadataBehavior = new ServiceMetadataBehavior();
            metadataBehavior.HttpsGetEnabled = true;
            metadataBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            host.Description.Behaviors.Add(metadataBehavior);

            var credentialBehavior = new ServiceCredentials();
            credentialBehavior.UserNameAuthentication.CustomUserNamePasswordValidator = new UsernamePasswordValidator();
            credentialBehavior.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
            host.Description.Behaviors.Add(credentialBehavior);

            host.Open();

            Console.WriteLine("The service is ready at {0}", baseAddress);
            Console.WriteLine("Press <Enter> to stop the service.");
            Console.ReadLine();

            host.Close();
        }
    }
}

public class UsernamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        if (!string.Equals(userName, "admin", StringComparison.OrdinalIgnoreCase) ||
            !string.Equals(password, "password", StringComparison.Ordinal))
        {
            Console.WriteLine("Validation failed.");
            throw new SecurityTokenException("Validation failed.");
        }
        Console.WriteLine("Validation successful.");
    }
}

Client

class Program
{
    static void Main()
    {
        using (var client = new SelfHostedUsernamePasswordServiceClient())
        {
            client.ClientCredentials.UserName.UserName = "admin";
            client.ClientCredentials.UserName.Password = "password";

            var result = client.GetData(12345);
            Console.WriteLine("Result from service: {0}", result);

            client.Close();
        }
    }
}

With this code, I get a MessageSecurityException message (I can not find the token authenticator for the token type "System.IdentityModel.Tokens.UserNameSecurityToken"). But I think that when I create the TokenAuthenticator, I am wrong ...

Btw, UserPasswordValidator is never called.

+4
source share
1

, .

Transport CredentialType "Certificate" Message CredentialType "UserName". .

:

public class Program
{
    public static void Main()
    {
        var baseAddress = new Uri("https://localhost:8080/SelfHostedUsernamePasswordService");

        using (var host = new ServiceHost(typeof(SelfHostedUsernamePasswordService), baseAddress))
        {
            var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
            binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

            var endpoint = host.AddServiceEndpoint(typeof(ISelfHostedUsernamePasswordService), binding, baseAddress);

            var cf = new ChannelFactory<ISelfHostedUsernamePasswordService>(binding, endpoint.Address);
            cf.Credentials.ClientCertificate.SetCertificate(
                StoreLocation.LocalMachine,
                StoreName.My,
                X509FindType.FindByThumbprint,
                "0000000000000000000000000000000000000000");

            var credentialBehavior = new ServiceCredentials();
            credentialBehavior.UserNameAuthentication.CustomUserNamePasswordValidator = new UsernamePasswordValidator();
            credentialBehavior.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
            credentialBehavior.IssuedTokenAuthentication.AllowUntrustedRsaIssuers = true;
            host.Description.Behaviors.Add(credentialBehavior);

            var metadataBehavior = new ServiceMetadataBehavior();
            metadataBehavior.HttpsGetEnabled = true;
            metadataBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            host.Description.Behaviors.Add(metadataBehavior);

            host.Open();

            Console.WriteLine("The service is ready at {0}", baseAddress);
            Console.WriteLine("Press <Enter> to stop the service.");
            Console.ReadLine();

            host.Close();
        }
    }
}

public class UsernamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        if (!string.Equals(userName, "admin", StringComparison.OrdinalIgnoreCase) ||
            !string.Equals(password, "password", StringComparison.Ordinal))
        {
            Console.WriteLine("Validation failed.");
            throw new SecurityTokenException("Validation failed.");
        }
        Console.WriteLine("Validation successful.");
    }
}

Client

class Program
{
    static void Main()
    {
        var remoteAddress = new EndpointAddress(new Uri("https://localhost:8080/SelfHostedUsernamePasswordService"));

        var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
        binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

        using (var client = new SelfHostedUsernamePasswordServiceClient(binding, remoteAddress))
        {
            client.ClientCredentials.UserName.UserName = "admin";
            client.ClientCredentials.UserName.Password = "password";

            var result = client.GetData(12345);
            Console.WriteLine("Got result from service: {0}", result);
            Console.ReadLine();

            client.Close();
        }
    }
}
+4

Source: https://habr.com/ru/post/1531308/


All Articles