Passing a UserName as a supporting token.

Passing a UserName as a supporting token.

Rate This
  • Comments 3

Firstly i would like to thank Brent Schmaltz who helped me solve this problem.  When trying to secure messages might require more than than the primary token to identity the client. We can then resort to sending additional information that would help in identitification or some kind of custom processing.

 

Basically the code below, from Brent, shows how to use a windows token to send a supporting user name token. Sometimes the user name on another system might not be your windows creds and so this would help in flowing the expected id to the service. The windows token would be used to secure the user name token in this scenario.

 

Basically what we do is secure the binding using wsHttpBinding and then add a UserNameSecurityTokenParameters object into the security binding element.Do note the he's specifed a custom validator to validate this information and specify the UserNamePasswordValidationMode to custom.

 

 

 

using System;

using System.ServiceModel;

using System.ServiceModel.Channels;

using System.ServiceModel.Security.Tokens;

using System.ServiceModel.Security;

using System.IdentityModel.Selectors;

using System.IdentityModel.Tokens;

using System.IdentityModel.Claims;

using System.IdentityModel.Policy;

using System.Security.Cryptography.X509Certificates;

using System.Security.Principal;

using System.Threading;

using System.Collections.Generic;

using System.Collections.ObjectModel;

 

namespace Ideas

{

    class WindowsAuthDefaultClean

    {

        public static void Main()

        {

       

            string baseAddress = "http://localhost:8001/WindowsAuthDefault";

            EndpointAddress epa = new EndpointAddress(baseAddress);

 

            // Create the binding

            WSHttpBinding wsHttpBinding = new WSHttpBinding(SecurityMode.Message);

            wsHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;

            wsHttpBinding.Security.Message.EstablishSecurityContext = false;

 

 

            // Create the service host and attache the custom u/p validator]

            // and the service authorization manager.

            ServiceHost sh = new ServiceHost(typeof(WorkService), new Uri(baseAddress));

            sh.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;

            sh.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNameValidator();

            sh.Authorization.ServiceAuthorizationManager = new CustomServiceAuthorizationManager();

       

 

            // Get the security element to add the parameter requirements.

            SecurityBindingElement sbe = null;

            BindingElementCollection bec = wsHttpBinding.CreateBindingElements();

            sbe = bec.Find<SecurityBindingElement>();

 

            if (sbe == null)

                throw new InvalidOperationException("no SecurityBindingElement found");

 

            sbe.EndpointSupportingTokenParameters.SignedEncrypted.Add(new UserNameSecurityTokenParameters());

            CustomBinding cb = new CustomBinding(bec);

            sh.AddServiceEndpoint(typeof(IWorkContract), cb, baseAddress);

            sh.Open();

 

 

            Console.WriteLine("Service Listening on : " + sh.BaseAddresses[0] + "\nPress <ENTER> to call service.");

            Console.ReadLine();

 

 

            //Create the client.

            ChannelFactory<IWorkContract> cf = new ChannelFactory<IWorkContract>(cb, epa);

 

            // validated in CustomUserNameValidator

            cf.Credentials.UserName.UserName = "test1";

            cf.Credentials.UserName.Password = "1tset";

 

            IWorkContract wc = cf.CreateChannel();

            try

            {

                Console.WriteLine(wc.DoWork("Get to work"));

            }

            catch (CommunicationException e)

            {

                Console.WriteLine(e);

            }

            catch (Exception e)

            {

                Console.WriteLine("Exception: {0}", e.ToString());

            }

 

            Console.WriteLine("\nPress <ENTER> to terminate");

            Console.ReadLine();

        }

    }

 

    public class CustomUserNameValidator : UserNamePasswordValidator

    {

        // This method validates users. It allows in two users, test1 and test2

        // with passwords 1tset and 2tset respectively.

        // This code is for illustration purposes only and

        // MUST NOT be used in a production environment becuase it is NOT secure.

        public override void Validate(string userName, string password)

        {

            if (null == userName || null == password)

            {

                throw new ArgumentNullException();

            }

 

            if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))

            {

                throw new SecurityTokenException("Unknown Username or Incorrect Password");

            }

        }

    }

 

    public class CustomServiceAuthorizationManager : ServiceAuthorizationManager

    {

        protected override bool CheckAccessCore(OperationContext operationContext)

        {

            return true;

        }

 

        protected override ReadOnlyCollection<IAuthorizationPolicy> GetAuthorizationPolicies(OperationContext operationContext)

        {

            return base.GetAuthorizationPolicies(operationContext);

        }

    }

   

   

}

 

    [ServiceContract]

    public interface IWorkContract

    {

       [OperationContract]

       string DoWork(string input);

    }

   

   public class WorkService:IWorkContract

   {

       public string DoWork(string input)

       { return "Input params " + input;}

   }

 

/*

 * Config solution for setting up custom U/P validator

 *

    <behaviors>

      <serviceBehaviors>

        <behavior name="CalculatorServiceBehavior" includeExceptionDetailInFaults="True">

          <serviceCredentials>

            <!--

            The serviceCredentials behavior allows one to specify a custom validator for username/password combinations.                      

            -->

            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.CalculatorService+CustomUserNameValidator, service" />

            <!--

            The serviceCredentials behavior allows one to define a service certificate.

            A service certificate is used by a client to authenticate the service and provide message protection.

            This configuration references the "localhost" certificate installed during the setup instructions.

            -->

            <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />

          </serviceCredentials>       

        </behavior>

      </serviceBehaviors>

    </behaviors>

*/

 

Next - Web Hosted sample that implements the supporting token requirements.
Leave a Comment
  • Please add 7 and 2 and type the answer here:
  • Post
  • PingBack from http://blogs.msdn.com/sajay/archive/2006/12/12/web-hosted-sample-with-usernamepassword-supporting-token.aspx

  • Thanks! Your code is what i'm looking for but i have a question - i am pretty new to WCF and probably am missing something - why do you have to use CustomBinding and can't just use WSHttpBinding (i checked - it doesn't work if i just use wsHttpBinding for the service).

    Any ideas would be highly appreciated!

  • If you realized that I actually start with a wsHttpbinding. Now the point is i need the security element from the wsHttpBinding and I need to add this token requirement on to this so basically i get my own set of binding elements. Ever binding can be represenetd as a custom binding as basically the custom binding is just a colleciton of binding elements and out of the box binding elements are just a prebaked set that can also be represeted as a custom binding.

    So you can think of a custom binding as the name suggests a customized version where are teh out of the box binding are prepacked with standards transport like http with text encoding(basicHttpBinding) and so on.

Page 1 of 1 (3 items)
Search