none
[Question]Handle UserNamePasswordValidator RRS feed

  • Question

  • Hi everyone,

    I'm making a WCF application using WSDualHttpBinding whose service layer validates client credential as long as it connects.

    Everything has been fine but one problem is : I cannot handle the Exception thrown in UserNamePasswordValidator class.

    Here is my code:

    +) Service layer:

    using System;
    using System.IdentityModel.Configuration;
    using System.Security.Cryptography.X509Certificates;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using System.ServiceModel.Security;
    using ServiceLayer.Interfaces;
    using ServiceLayer.Models;
    
    namespace ServiceLayer
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
                //const string serviceAddress = "http://localhost:27020/AccountAuthenticator";
                var serverPort = 0;
    
                while (true)
                {
                    try
                    {
                        Console.Write("Enter service port : ");
                        serverPort = int.Parse(Console.ReadLine());
                        break;
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Invalid server port. Please try again");
                        Console.ReadLine();
                    }
                }
    
                var serviceAddress = string.Format("http://localhost:{0}/AccountAuthenticator", serverPort);
    
                // Create an isntance of service host which manages connection from clients.
                var serviceHost = new ServiceHost(typeof (AuthenticationService), new Uri(serviceAddress));
    
                // Create an instance of ServiceMetadataBehavior class to define what server will behave.
                var serviceMetadataBehavior = new ServiceMetadataBehavior();
    
                // Retrieve service credential from service host.
                var serviceCredentials = serviceHost.Description.Behaviors.Find<ServiceCredentials>();
    
                // Instance hasn't been found. Create a new one.
                if (serviceCredentials == null)
                {
                    serviceCredentials = new ServiceCredentials();
                    serviceHost.Description.Behaviors.Add(serviceCredentials);
                }
                
                // Update credential information.
                serviceCredentials.UserNameAuthentication.UserNamePasswordValidationMode =
                    UserNamePasswordValidationMode.Custom;
                serviceCredentials.UserNameAuthentication.CustomUserNamePasswordValidator = new IdentityValidator();
                serviceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My,
                    X509FindType.FindBySubjectName, "localhost");
    
                serviceHost.Description.Behaviors.Add(serviceMetadataBehavior);
                serviceHost.AddServiceEndpoint(typeof (IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(),
                    "mex");
                
                // Create an instance of BasicHttpBinding with default initialization.
                var wsDualHttpBinding = new WSDualHttpBinding();
                wsDualHttpBinding.Security.Mode = WSDualHttpSecurityMode.Message;
                wsDualHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
                serviceHost.AddServiceEndpoint(typeof (IAuthenticationService), wsDualHttpBinding, serviceAddress);
                serviceHost.Open();
    
                
                Console.WriteLine("Service has started at port {0}. Press enter to terminate", serverPort);
                Console.ReadLine();
            }
        }
    }

    My client code is :

    using System;
    using System.Security.Cryptography.X509Certificates;
    using System.ServiceModel;
    using System.ServiceModel.Security;
    using ClientLayer.Models;
    using ClientLayer.Service_References.AuthenticateService;
    
    namespace ClientLayer
    {
        internal class Program
        {
            //private const string ServiceAddress = "http://localhost:27020/AccountAuthenticator";
    
            private static void Main(string[] args)
            {
                var serverPort = 0;
                while (true)
                {
                    try
                    {
                        Console.Write("Enter server port : ");
                        serverPort = int.Parse(Console.ReadLine());
                        break;
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Invalid server port. Please try again");
                        Console.ReadLine();
                    }
                }
    
                var serviceAddress = string.Format("http://localhost:{0}/AccountAuthenticator", serverPort);
                var endpointAddress = new EndpointAddress(new Uri(serviceAddress));
                var wsDualHttpBinding = new WSDualHttpBinding();
                wsDualHttpBinding.Security.Mode = WSDualHttpSecurityMode.Message;
                wsDualHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
                var callbackHandler = new AuthenticationServiceHandler();
                var client = new AuthenticationServiceClient(new InstanceContext(callbackHandler), wsDualHttpBinding,
                    endpointAddress);
    
                client.ClientCredentials.UserName.UserName = "redplane";
                client.ClientCredentials.UserName.Password = "fayaz1";
                client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My,
                    X509FindType.FindBySubjectName, "localhost");
                client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
                    X509CertificateValidationMode.None;
    
                try
                {
                    client.AuthenticateAccount("Akai", "Akai");
                }
                catch (Exception exceptionInfo)
                {
                    Console.WriteLine("Error happended");
                }
                Console.ReadLine();
            }
        }
    }

    When my client connects to service with false username or password, after a short time waiting on client app, I receive this error :

    Client is unable to finish the security negotiation within the configured timeout (00:00:00).  The current negotiation leg is 1 (00:00:00).  

    My question is :

    How can I handle the SecurityException thrown in UserNamePasswordValidator and send back a message to client to notify it the authentication is failed.

    I've searched for many topics about this, so , please look at my code before giving me a solution.

    Thank you :)


    Sunday, December 27, 2015 1:49 PM

Answers