Zulfiqar's weblog

Middleware, security & random .Net

Archive for July, 2008

SAML Token Requestor

Posted by zamd on July 11, 2008

In yesterdays post I have shown you how to create a basic STS using Zermatt. You can use this STS by configuring your clients to use WSFederationHttpBinding however in that case you will never see the token issued by STS. In this post I will show you a direct way to communicate with your STS by using the IssuedSecurityTokenProvider – This is useful for quick testing scenarios or when you need access to the issued token.

TokenProviders are the WCF components which provide the tokens used in message security. There is usually a TokenProvider for each type of security token (Certficate, UserName, Kerberos, IssuedToken etc). IssuedSecurityTokenProvider internally uses a ChannelFactory to communicate with the STS to get the actual token. You can configure this ChannelFactory by adding your custom behaviors to the IssuerChannelBehaviors property of the IssuedSecurityTokenProvider. Here is the code sample.

 

public static void Main()

{

    //This provider internally creates a WCF proxy (ChannelFactory) and uses it to issues RST request.

    IssuedSecurityTokenProvider provider = new IssuedSecurityTokenProvider();

    provider.SecurityTokenSerializer = new WSSecurityTokenSerializer();

 

    provider.TargetAddress = new EndpointAddress(http://localhost/IService”);

    provider.IssuerAddress = new EndpointAddress(http://localhost:9000/STS”);

 

    var be = new WSFederationHttpBinding().CreateBindingElements().Find<SecurityBindingElement>();

    // use the default algo & security versions used by Federation binding.

    provider.SecurityAlgorithmSuite = be.DefaultAlgorithmSuite;

    provider.MessageSecurityVersion = be.MessageSecurityVersion;

 

    // Binding used to communicate with STS.

    provider.IssuerBinding = new WSHttpBinding();

 

    // opent the internal channelfactory.

    provider.Open();

   

    // request token by issuing a WS-Trust RST request.

    var issuedToken = provider.GetToken(TimeSpan.FromMinutes(1));

   

    // print token on the console.

    WSSecurityTokenSerializer serializer = new WSSecurityTokenSerializer(be.MessageSecurityVersion.SecurityVersion);

    var writer = XmlWriter.Create(Console.OpenStandardOutput());

    serializer.WriteToken(writer, issuedToken);

    writer.Flush();

    provider.Close();

}

 

My STS requires Kerberos token to issue a SAML token – so this provider simply uses the kerberos token of the process. If you need to send different token (UserName etc) then you can do that using the IsserChannelBehaviors propery mentioned ealier.

provider.IssuerChannelBehaviors.Add(new IssuerCredBehavior());

And custom behavior looks like this.

public class IssuerCredBehavior : IEndpointBehavior

{

    #region IEndpointBehavior Members

 

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)

    {

        var cc = bindingParameters.Find<ClientCredentials>();

        if (cc == null)

        {

            cc = new ClientCredentials();

            cc.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;

            cc.ServiceCertificate.SetDefaultCertificate(“CN=localhost”, StoreLocation.LocalMachine, StoreName.My);

           //Use this client certificate to get a SAML token.

            cc.ClientCertificate.Certificate = CertificateUtil.GetCertificate(StoreName.My, StoreLocation.CurrentUser, “cn=localhost”);

            bindingParameters.Add(cc);

        }

    }

 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)   {    }

 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)    {    }

 

    public void Validate(ServiceEndpoint endpoint)    {    }

 

    #endregion

}

Posted in Federation/STS, Geneva | 7 Comments »

Creating a Basic STS using Geneva Framework( aka Zermatt)

Posted by zamd on July 10, 2008

Zermatt (Geneva Framework) is an identity framework built on top of solid WCF foundation. It makes writing custom STSs a breeze as the amount of code you have to write is substantially low compared with, when building the same STS directly on top of WCF. In this post I will show you how to write a basic STS using Zermatt. 

This STS will be used by active clients, which mean, it will expose its token issuance functionality using the WS-Trust protocol. In a later post I will talk about passive clients and WS-Federation protocol. 

So the first step is to drive a class from Zermatt provided SecurityTokenService abstract base class. This class provides most of the plubming required implementing an STS and you have to only provide missing pieces in your derived class. 

class CustomSecurityTokenService : SecurityTokenService{} 

Next you have to override following two methods: 

    protected override Scope GetScope(IClaimsPrincipal principal, RequestSecurityToken request) 

    { 

        Scope scope = base.GetScope(principal, request); 

        scope.EncryptingCredentials = new X509EncryptingCredentials(CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, “CN=localhost”)); 

        return scope; 

    } 

  

    public override ClaimsIdentityCollection  GetOutputSubjects(Scope scope, IClaimsPrincipal principal, RequestSecurityToken request) 

    { 

        ClaimsIdentityCollection collection = new ClaimsIdentityCollection(); 

        collection.Add( new ClaimsIdentity( new Claim( ClaimTypes.Name, “zulfiqar” ) ) ); 

        return collection; 

    } 

In the GetScope method, you get all the information about the requestor and based on that you can select credentials which will be used to encrypt the issued token to the requestor. You can do that in the GetOutputSubjects method as well in which case you don’t need to override GetScope. 

In GetOutputSubjects method you create a collection of claims which will be added to the issued token. In a production STS, this is where you will access the external system to get information about the requestor and will create claims based on that information. In this example, I’m simply returning a single Name claim. That’s it – you are done with STS part. 

Now as an STS is essentially a service, so you need to host it inside a ServiceHost and expose it’s functionality using an Endpoint (Standard WCF stuff). Zermatt also provides a custom service host, known as WSTrustServiceHost – which adds Zermatt specific stuff (configuration etc) to the standard ServiceHost class. 

    SecurityTokenServiceConfiguration config = 

        new SecurityTokenServiceConfiguration(stsAddress, new X509SigningCredentials(stsCert)); 

    stsConfig.SecurityTokenService = typeof(CustomSecurityTokenService); 

    //Create host based on our configuration. 

    stsHost = new WSTrustServiceHost(stsConfig, new Uri(stsAddress)); 

    // Add an endpoint – this can be added using standard config mechansims as well. 

    stsHost.AddServiceEndpoint(typeof(IWSTrustFeb2005SyncContract), 

       new WSHttpBinding(), new Uri(stsAddress)); 

    // open the host now.            

    stsHost.Open(); 

At this point our STS is ready to go. You might have noticed that I’m using the standard WSHttpBinding, which mean my STS will authenticate requestors using windows authenticaiton (default for WSHttpBinding) – and then I can use all that information to inlcude appropraite claims in the returned SAML token. One last important point is that Zermatt is build on top of WCF security model – so I can change the binding to require a certificate or a userName to issue a SAML token.  

 

In the next post I will show how to a write a basic test harnesses for our Security Token Service. 

 

Posted in Geneva | Leave a Comment »

Zermatt Beta Released

Posted by zamd on July 10, 2008

Yesterday Microsoft has released the beta version of Zermatt identity framework. Zermatt SDK comes with lots of sample explaining different bits and pieces of the framework. For the next couple of weeks I will be sharing my learning and experience of Zermatt. So stay tuned…

In the mean time, please read this excellent article by Keith Brown.

Posted in Zermatt | Leave a Comment »

Error handling with WebHttpBinding for Ajax/JSON

Posted by zamd on July 8, 2008

WebHttpBinding is the non-SOAP binding shipped with .net Framework 3.5. This binding along with WebHttpBehavior will be your friend for REST, POX & AJAX scenarios.

When you expose an endpoint using WebHttpBinding the default error handling mechanism is overridden by a custom error handler added by the WebHttpBehavior. Now if you throw a FaultException from your methods – this handler will simply swallow your exception and will generate a generic 400 Bad Request error message. It will do the same for non-fault exceptions. The reason for this change is that in the SOAP world, Faults have a well known wire representation and based on that your FaultException is translated into a SOAP fault message. There is no such wire representation for the faults in REST or AJAX scenarios. If you own both sides (client & service) of the solution, you might want to customize this default WCF behavior. For example, in my scenario I want to send fault object as a JSON string to the client with a 400, “Bad request” http error code. For non-fault exception I will return a generic message with 500 “Internal Server Error”. 

First step of this customization is to subclass the WebHttpBehavior and replace the default error handler with you own error handler.

public class WebHttpBehaviorEx : WebHttpBehavior

{

    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)

    {

        // clear default erro handlers.

        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();

        // add our own error handler.

        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new ErrorHandlerEx());

    }

}

Create your own error handler by impelemting IErrorHandler interface.

public class ErrorHandlerEx : IErrorHandler

{

    public bool HandleError(Exception error)

    {

        return true;

    }

    public void ProvideFault(

        Exception error, MessageVersion version, ref Message fault)

    {

     

        //TODO: here we can provide our own fault

    }

}

ProvideFault implementation looks like this:

    public void ProvideFault(

        Exception error, MessageVersion version, ref Message fault)

    {

        if (error is FaultException)

        {

            // extract the our FaultContract object from the exception object.

            var detail = error.GetType().GetProperty(“Detail”).GetGetMethod().Invoke(error, null);

            // create a fault message containing our FaultContract object

            fault = Message.CreateMessage(version, “”, detail, new DataContractJsonSerializer(detail.GetType()));

            // tell WCF to use JSON encoding rather than default XML

            var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);

            fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);

 

            // return custom error code.

            var rmp = new HttpResponseMessageProperty();

            rmp.StatusCode = System.Net.HttpStatusCode.BadRequest;

            // put appropraite description here..

            rmp.StatusDescription = “See fault object for more information.”;

            fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);

        }

        else

        {

            fault = Message.CreateMessage(version, “”, “An non-fault exception is occured.”, new DataContractJsonSerializer(typeof(string)));

            var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);

            fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);

            // return custom error code.

            var rmp = new HttpResponseMessageProperty();

            rmp.StatusCode = System.Net.HttpStatusCode.InternalServerError;

            // put appropraite description here..

            rmp.StatusDescription = “Uknown exception…”;

            fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);

        }

    }

 

Now if you throw a FaulException with following fault contract.

    [DataContract]

    public class GreaterThan3Fault

    {

        [DataMember]

        public string FaultMessage { get; set; }

        [DataMember]

        public int ErrorCode { get; set; }

        [DataMember]

        public string Location { get; set; }

    }

You will get this on the client side with a 400 error code. You can use the javascript:eval() to convert this string into javascript object.

{“ErrorCode”:90192,”FaultMessage”:”Count cannot be greate than 3. Please try again later.”,”Location”:”ISB”}

You can plug-in your custom/extended behavior by using a custom ServiceHostFactory.

 

    public class MyFactory : WebServiceHostFactory

    {

        public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)

        {

            var sh = new ServiceHost(typeof(Service1), baseAddresses);

            sh.Description.Endpoints[0].Behaviors.Add(new WebHttpBehaviorEx());

 

            return sh;

        }

        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)

        {

            return base.CreateServiceHost(serviceType, baseAddresses);

        }

    }

And your svc should look like this.

<%@ ServiceHost Language=C# Debug=true Service=Test.Service1 CodeBehind=Service1.svc.cs Factory=Test.MyFactory %>

I have attached complete solution with this post.

Update: Please note this sample will NOT work with Microsoft Ajax library as it is. See this post if you are using Microsoft Ajax library as your client.

Download: jsonSerial.zip

Posted in Ajax | 9 Comments »

Federation over TCP streaming

Posted by zamd on July 4, 2008

Pablo described here a way to configure federation over TCP. In his approach he gets a SAML token from STS and then uses that token to get a security context token which will be used to provide actual message security throughout the session.

As message security only works in a buffered mode, so his approach is not suitable for a TCP streaming scenario. To enable federation along with TCP streaming you have to use mixed mode security (TransportWithMessageCredential) over TCP.  Let’s consider following binding which uses mixed mode security.

      <netTcpBinding>

        <binding name="tcp" transferMode="Streamed">

          <security mode="TransportWithMessageCredential">

            <message clientCredentialType="IssuedToken"/>

            <transport clientCredentialType="Windows"></transport>

          </security>

        </binding>

      </netTcpBinding>

Now the trouble is that there is no way to configure STS settings in this binding configuration so your only choice is to mimic the above settings in a custom binding.

      <wsHttpBinding>

        <binding name="simpTransport">

          <security mode="Transport">

            <transport clientCredentialType="None"/>

          </security>

        </binding>

      </wsHttpBinding>

 

      <customBinding>

        <binding name="tcp">

          <security authenticationMode="SecureConversation">

            <secureConversationBootstrap authenticationMode="IssuedTokenOverTransport">

              <issuedTokenParameters>

                <issuer address="https://localhost:9000/STS" binding="wsHttpBinding" bindingConfiguration="simpTransport"/>

              </issuedTokenParameters>

            </secureConversationBootstrap>

          </security>

          <windowsStreamSecurity/>

          <tcpTransport transferMode="Streamed" />

        </binding>

      </customBinding>

Posted in Federation/STS | 1 Comment »

 
Follow

Get every new post delivered to your Inbox.