February 2006 - Posts

Secure Conversation is a feature designed to improve the performance of an application that needs to interchange more than one messages with a service.

When SC is enabled, the token negotiation and authentication happens once compared to other tokens where that negotiation is done for each request to the service.

In the first negotiation, the client sends a "RequestSecurityToken" message to the service in order to ask for a session token. That message is part of the WS-Trust specification and it is protected (encrypted and signed) with a security token that will be the base token for the session token.

After that, the service creates a new token called Secure context token (SCT), which contains a reference to the original token and a symmetric key to perform cryptographic operations like encrypt or sign messages. (Message confidentiality and integrity).

WSE and WCF, both implement this feature and the service itself is responsible to emit the SCT. Therefore, the service is also a "Security token service" or STS.

The service returns the SCT to the client application and keeps the state of the original token using different strategies (Cookies, in-memory stores, etc). This article  in the MSDN describes very well what are the different approaches that a STS can use to maintain the state of a session.

The most import benefits of using a SCT to protect the communication between a client and service are:

 

1. The service execution is three or four times faster than the same execution with other tokens.

2. It is valid for a short time but it can be automatically renewed. As consequence, the  client application does not need to keep the original token.

   This is really important when the original token contains some sensitive information such an user name or password. (Username Token).

 

Secure conversation in WSE

 

Activating SC in WSE is really easy, it is just a flag in the policy configuration. All the policies for the turn-key scenarios support two attributes, "establishSecurityContext" to turn on the SC feature and renewExpiredSecurityContext to automatically renew the SCT when it expires (This attribute is helpful when storing the original token in the client is not a feasible solution).

 

The sample below shows how to activate SC for a "MutualCertificate" turn-key scenario:

 

<mutualCertificate10Security establishSecurityContext="true" renewExpiredSecurityContext="true">

  <serviceToken>

    <x509 storeLocation="LocalMachine" storeName="My" findValue="CN=WSE2QuickStartServer" findType="FindBySubjectDistinguishedName" />

  </serviceToken>

  <protection>

    <request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

    <response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

    <fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />

  </protection>

</mutualCertificate10Security>

 

WSE supports two modes to mantain the state of the original security token for a particular session.

  • Cookie mode, where the state is stored in a temporary cookie. This mode was designed to support web farm scenarios.
  • In-Memory cache in the STS

 

<microsoft.web.services3>

  <tokenIssuer>

    <statefulSecurityContextToken enabled="false" />

  </tokenIssuer>

</microsoft.web.services3>

 

The default value for this setting is "true", which enables the Cookie mode. The state for a kerberos token can not be maintained in a cookie and therefore it is the only turn-key scenario that doesn't support stateful SCT.

 

The code below shows how to reuse a SCT from a client application.

 

HelloWorldServiceWse serviceProxy = new HelloWorldServiceWse();

UsernameToken usernameToken = new UsernameToken("user", "password");

serviceProxy.SetClientCredential(usernameToken);

serviceProxy.SetPolicy("ClientPolicy");

serviceProxy.HelloWorld();

SecureConversationCorrelationState correlationState = serviceProxy.ResponseSoapContext.SessionState.Get<SecureConversationCorrelationState>("");

if (correlationState != null)

{

    SecurityContextToken sct = correlationState.Token as SecurityContextToken;

    if (sct != null)

    {

        serviceProxy = new HelloWorldServiceWse();

        serviceProxy.SetClientCredential(sct);

        // Set the ClientPolicy onto the proxy

        serviceProxy.SetPolicy("ClientPolicy");

        serviceProxy.HelloWorld();

        sct.Cancel();

    }

}

 
   

Secure conversation in WCF

 

WCF turn on SC by default for all binding that support WS-Security (WsHttpBinding, NetTcpBinding, netMsmqBinding).

The Custom binding also offers the possibility to enable SC depending on the value of the attribute "authenticationMode" (The value for this attribute must be "SecureConversation"). In addition, you can configure a binding that will be used to establish a communication with the STS by means of the element "secureConversationBootstrap".

WCF is completely different from WSE since it hides the SCT from the client application and automatically maintains a copy of this token at channel level (A channel is related to a contract). That is, it will reuse the SCT as long as the client application uses the same instance of the client channel.

When the channel is closed in a normal fashion, a message is sent to the service to release the SCT.  If the channel closes abruptly, the SCT will eventually be released on the service after after a period of in-actively.

 

The configuration below shows two equivalent bindings that use the SC feature:

 

<bindings>

  <wsHttpBinding>

    <binding name="ServiceBinding">

      <security mode="Message">

        <message clientCredentialType="Certificate" establishSecurityContext="true"/>

      </security>

    </binding>

  </wsHttpBinding>

  <customBinding>

    <binding name="ServiceBinding">

      <security authenticationMode="SecureConversation"

            requireSecurityContextCancellation ="false">

         <secureConversationBootstrap authenticationMode="MutualCertificate">

         </secureConversationBootstrap>

      </security>

      <httpTransport/>

    </binding>

   </customBinding>

</bindings>

 

The "requireSecurityContextCancellation" attribute specifies if the client application must send a "shutdown" message to the service after closing the client channel.

Posted by cibrax | 9 comment(s)
Filed under: ,
Jason Hogg is blogging, what good news. I have been working with Jason for almost two years on different projects (Shadowfax, some applications blocks, and other projects for web services).
Jason is program manager on the Patterns & Practices team, a smart guy and guru on web services.
He has been writing excellent articles about WSE, SAML and his work on Microsoft.  Check out his blog at http://blogs.msdn.com/thehoggblog/
Posted by cibrax
Filed under:
Roldolfo Finochietti has written a nice implementation of WS-Compression for WSE 3.0.
You can download it here.
Posted by cibrax
Filed under:

Last week, Sergio, a friend of mine asked me the following question about WCF "Hey Pablo, do you know how WCF does to create a channel with a specific interface on the fly ?".

He was talking about this piece of code:


ChannelFactory<IMyService> factory = new ChannelFactory<IMyService>();

IMyService myService = factory.CreateChannel();


My answer at that moment was "Nice question but I don't have idea, let me take a look".

That trigger my curiosity so I decided to find out the way to do something similar. After all, that could be useful in some scenarios where a Service interface is required (A way to separate the service interface from the service implementation).

After some investigation, I could reproduce something similar although I am not sure if this code is the same code as WCF.


As first step, I used some code provided by Cristofer Gonzales to build a template for a proxy. The code for that class looks as follows:


public class MyProxy<T> : System.Runtime.Remoting.Proxies.RealProxy where T : class

{

  public MyProxy() : base(typeof(T))

  {

  }

  public new T GetTransparentProxy()

  {

    return (T)base.GetTransparentProxy();

  }

  public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage imsg)

  {  

    Console.WriteLine("Invoking the transparent Proxy ...");

    ReturnMessage retmsg = null;

   

    int result = 0;

    if (imsg is IMethodCallMessage)

    {

      IMethodCallMessage call = imsg as IMethodCallMessage;

      Console.WriteLine("Calling to the method:");

      Console.WriteLine("\Name: {0}", call.MethodName);

    }

    else if (imsg is IMethodReturnMessage)

    {

      Console.WriteLine("Returning ...");

      retmsg = new ReturnMessage(null, null, 0, null, (IMethodCallMessage)imsg);

    

      return retmsg;

    }

  }

}


This proxy class will contain the same methods as the class specified as T and will intercept all the calls to those methods (Using a Transparent proxy).


Secondly, I defined a factory for the proxies. This class pretend to be equivalent to the class FactoryChannel in WCF.


class Factory<T>

{

  public Factory()

  {

  }

  public T Create()

  {

    MyProxy<IMyService> proxy = new MyProxy<IMyService>();

    return (T)proxy.GetTransparentProxy();

  }

}


Finally, I created some classes to test the factory and proxy classes.

public interface IMyService

{

  void HelloWorld(string message);

}

class Program

{

  static void Main(string[] args)

  {

    Factory<IMyService> factory = new Factory<IMyService>();

    IMyService service = factory.Create();

    service.HelloWorld("Cibrax");

  }

}


This is really cool, isn't it ?.

Posted by cibrax
Filed under:

Federation is key concept that allows to enable collaboration across multiple security or trust realms.
There are many resources on Internet about this topic so I won't enter in details during this post.
The solution that I will give is based on the second extension of this pattern:


http://msdn.microsoft.com/practices/default.aspx?pull=/library/en-us/dnpag2/html/wss_ch1_brokauthsts.asp


By the way, this is one of the security patterns published by the Pattern and Practices team in Microsoft.
This a good starting point if you want to be familiar with different and useful patterns for web services.


Sample scenario

Imagine the following scenario:


Fabrikam has exposed some services to make on line operations, such as purchase goods, make orders and others.
These services can be used only by customers so the access to them is restricted.
Contoso is one of Fabrikam's customers and it has developed an internal desktop application to consume some of these services.
As you can see, this is a typical scenario for Federation where we have both companies in different security domains or realms but they trust each other.


The services exposed by Fabrikam authenticate the users by means of X509 certificates, so one certificate is used for the client(Contoso) and another for the service(Fabrikam).
Contoso has deployed the desktop application in almost 100 machines and therefore installing both certificates in each one is not a practical solution in this case.




The Brokered Authentication pattern by means of security token services meets really well the requirements for this solution.


The arrows in this figure only show the work flow path and not the real path of the interchanged messages (Pair of request and response messages).


1. Contoso deploys a STS with both certificates and the desktop application can ask for a SAML token to this service using a UsernameToken, a Kerberos token, or other kind of client credential.
2. The STS in the Fabrikam's domain only accepts SAML tokens signed by a well-know Authority (The Contoso's STS in this case) and creates an equivalent SAML token signed by him.
3. The Fabrikam's services only accept SAML tokens signed by Fabrikam's STS.


With this solution, Fabrikam can start to accept request from other customers and the services will not notice the difference.
In addition, if the communication between the STS and the services in Fabrikam is protected by means of a Kerberos token instead of a SAML token, the
X509 certificates must be only deployed in the servers where both STS run.


Implementation


In order to implement this sample scenario, I used the SAML implementation for WSE. You can download the code for this project in the GDN workspace.
The image above illustrates the turn-key scenario used to secure the communication between the different participants in the architecture.



1. WSE Policy file in the client application

<policies xmlns="http://schemas.microsoft.com/wse/2005/06/policy">

  <extensions>

    <extension name="saml" type="Microsoft.Practices.WSSP.WSE3.QuickStart.SamlAssertion.SamlPolicyAssertion, Microsoft.Practices.WSSP.WSE3.QuickStart.SamlAssertion"/>

  </extensions>


  <policy name="PurchaseGoods">

    <saml issuer="http://localhost/FabrikamSTS/SamlTokenIssuer.ashx" issuerPolicy="FabrikamSTS" establishSecurityContext="true" renewExpiredSecurityContext="true" requireDerivedKeys="true">

      <protection>

        <request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

        <response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

        <fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />

      </protection>

    </saml>

  </policy>

  <policy name="FabrikamSTS">

    <saml issuer="http://localhost/ContosoSTS/SamlTokenIssuer.ashx" issuerPolicy="ContosoSTS" establishSecurityContext="false" renewExpiredSecurityContext="false" requireDerivedKeys="true">

      <protection>

        <request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

        <response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

        <fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />

      </protection>

    </saml>

  </policy>

  <policy name="ContosoSTS">

    <usernameForCertificateSecurity establishSecurityContext="true" renewExpiredSecurityContext="true" requireSignatureConfirmation="false" messageProtectionOrder="SignBeforeEncryptAndEncryptSignature" requireDerivedKeys="true">

      <serviceToken>

        <x509 storeLocation="LocalMachine" storeName="My" findValue="CN=ContosoSTS" findType="FindBySubjectDistinguishedName" />

      </serviceToken>

      <protection>

        <request signatureOptions="IncludeSoapBody" encryptBody="true" />

        <response signatureOptions="IncludeSoapBody" encryptBody="true" />

        <fault signatureOptions="IncludeSoapBody" encryptBody="false" />

      </protection>

    </usernameForCertificateSecurity>

  </policy>

</policies>


The policy definition above contains three policies:


1. PurchaseGoods: This policy is used to secure the communication between the client and the Fabrikam's service (PurchaseGoods service). As you can see, this service requires a SAML token created by the Fabrikam's STS. The address for that STS is specified in the attribute "issuer".

2. FabrikamSTS: This policy is used to secure the communication between the client and the STS in the Fabrikam realm. The Fabrikam's STS requires a SAML token from Contoso 

3. ContosoSTS: This policy is used to secure the communication between the client and the STS in the Contoso realm. In this case, to make the things simpler, I decided to use a UsernameForCertificate turn-key scenario although any of the available turn-key scenarios can be used here.


2. WSE Policy file in the Contoso's STS


<policies xmlns="http://schemas.microsoft.com/wse/2005/06/policy">

  <policy name="ContosoSTS">

    <usernameForCertificateSecurity establishSecurityContext="true" renewExpiredSecurityContext="true" requireSignatureConfirmation="false"   messageProtectionOrder="SignBeforeEncryptAndEncryptSignature" requireDerivedKeys="true">

      <serviceToken>

        <x509 storeLocation="LocalMachine" storeName="My" findValue="CN=ContosoSTS" findType="FindBySubjectDistinguishedName" />

      </serviceToken>

      <protection>

        <request signatureOptions="IncludeSoapBody" encryptBody="true" />

        <response signatureOptions="IncludeSoapBody" encryptBody="true" />

        <fault signatureOptions="IncludeSoapBody" encryptBody="false" />

      </protection>

    </usernameForCertificateSecurity>

  </policy>

</policies>


3. SAML configuration for the Contoso's STS


<WseSaml>

  <samlTokenIssuer allowCachingToken="true" ttlInSeconds="300">

  <!-- the config for the saml token issuer, this is the only config we use. This token is used to sign the SAML token -->

    <serviceTokens>

      <!-- SAML Authority certificate -->

      <add uri="http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue/SAML" storeLocation="LocalMachine" storeName="My" findValue="CN=ContosoSTS" findType="FindBySubjectDistinguishedName" />

      <!-- Fabrikam STS -->

      <add uri="http://localhost/FabrikamSTS/SamlTokenIssuer.ashx" storeLocation="LocalMachine" storeName="My" findValue="CN=FabrikamSTS" findType="FindBySubjectDistinguishedName" />

    </serviceTokens>

    <policy name="ContosoSTS">

    </policy>

  </samlTokenIssuer>

</WseSaml>


A quick description of the configuration above:


a. allowCachingToken attribute: This attribute specifies whether the SAML token can be stored in a cache or not. Depending on this attribute, the STS will add or not a DoNotCacheCondition to the SAML token.

b. ttlInSeconds attribute: Lifetime in seconds for the SAML token

c. serviceTokens element: It specifies the location for the different X509 certificates required by the STS. The "SAML authority certificate" is used to sign the SAML token. (This signature is really important since the target service can trust or not in the SAML token depending on the certificate used to create it). The "Fabrikam STS certificate" is used to encrypt some sections in the SAML token, and thefore only the Fabrikam STS can decrypt those sections and use the token. In other words, it defines the X509 certificate for the target service.

d. policy element: The WSE policy used to secure the communication between the clients and the STS.


4. WSE policy file in the Fabrikam's STS


<policies>

  <extensions>

    <extension name="saml" type="Microsoft.Practices.WSSP.WSE3.QuickStart.SamlAssertion.SamlPolicyAssertion, Microsoft.Practices.WSSP.WSE3.QuickStart.SamlAssertion"/>

  </extensions>

  <policy name="FabrikamSTS">

    <saml issuer="http://localhost/ContosoSTS/SamlTokenIssuer.ashx" issuerPolicy="issuerPolicy" establishSecurityContext="false" renewExpiredSecurityContext="false" requireDerivedKeys="true">

      <trustedTokenIssuers>

        <add>

          <x509 storeLocation="LocalMachine" storeName="My" findValue="CN=ContosoSTS" findType="FindBySubjectDistinguishedName" />

        </add>

      </trustedTokenIssuers>

      <protection>

        <request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

        <response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

        <fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />

      </protection>

    </saml>

  </policy>

</policies>


This STS only accepts SAML tokens created by the Contoso's STS (trustedTokenIssuers element in the policy definition). In other words, it only accepts SAML tokens signed by any of the issuers specified in the "trustedTokenIssuers" element.


5. SAML configuration for the Fabrikam's STS


<WseSaml>

  <samlTokenIssuer allowCachingToken="true" ttlInSeconds="300" >

  <!-- the config for the saml token issuer, this is the only config we use. This token is used to sign the SAML token -->

  <serviceTokens>

    <!-- SAML Authority certificate. Certificate used to sign the token -->

    <add uri="http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue/SAML"

storeLocation="LocalMachine" storeName="My" findValue="CN=FabrikamSTS" findType="FindBySubjectDistinguishedName"/>

    <!-- Fabrikam service. Certificate used to encrypt the token subject -->

    <add uri="http://localhost/FabrikamServices/PurchaseGoods.asmx"

storeLocation="LocalMachine" storeName="My" findValue="CN=FabrikamServices" findType="FindBySubjectDistinguishedName"/>

  </serviceTokens>

  <policy name="FabrikamSTS"></policy>

  </samlTokenIssuer>

</WseSaml>


As you can see, this configuration is similar to the configuration in the Contoso STS. The only difference is the configuration for the service tokens.


6. WSE policy file in the Fabrikam's service


<policies>

  <extensions>

    <extension name="saml" type="Microsoft.Practices.WSSP.WSE3.QuickStart.SamlAssertion.SamlPolicyAssertion, Microsoft.Practices.WSSP.WSE3.QuickStart.SamlAssertion"/>

  </extensions>

  <policy name="FabrikamServices">

    <saml issuer="http://localhost/FabrikamSTS/SamlTokenIssuer.ashx" issuerPolicy="issuerPolicy" establishSecurityContext="true" renewExpiredSecurityContext="true" requireDerivedKeys="true">

      <trustedTokenIssuers>

        <add>

          <x509 storeLocation="LocalMachine" storeName="My" findValue="CN=FabrikamSTS" findType="FindBySubjectDistinguishedName" />

        </add>

      </trustedTokenIssuers>

      <protection>

        <request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

        <response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="true" />

        <fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />

      </protection>

    </saml>

   </policy>

</policies>


Again, it is similar to the policy in the Fabrikam's STS but the configuration for the "trustedTokenIssuers" element changes.


Send me an email if are interested in the source code of this sample. 

Posted by cibrax | 4 comment(s)
Filed under:
More Posts