Zulfiqar's weblog

Middleware, security & random .Net

Exposing Workflow Service over Azure Service Bus

Posted by zamd on February 2, 2011

In this post I’ll walk you through the steps of exposing a ‘Windows Server AppFabric’ hosted workflow service over the Azure service bus.  IIS/AppFabric hosted services are message activated so they cannot be visible on the servicebus until they are activated. So in this post, I’ll use the AutoStart feature of AppFabric to make my service available over service bus.

Create a workflow service project using Visual Studio

image

VS would generate a .xamlx based service and a default web.config file

image

The generated web.config uses the new WCF 4.0 default configuration option so no <service> tag was generated. If you run the service now, default endpoints would automatically be generated based on the base address of the service provided by the IIS.

Service bus endpoints requires an address in the service bus namespace so I can’t use IIS provided base address which means I can’t use the default endpoints feature. So the first set of changes would to be revert back to the old-style explicit endpoint definition.

    <services>
      <service name="Service1">
        <endpoint address="http://eval01.servicebus.windows.net/wfappfabric/" binding="ws2007HttpRelayBinding" contract="IService"/>
        <endpoint address="http://eval01.servicebus.windows.net/wfappfabric/mex" binding="ws2007HttpRelayBinding" kind="mexEndpoint"/>
      </service>
    </services>

The service name & contract name (‘Service1’ & ‘IService’) can be found from the properties of the workflow and the receive activity respectively.  Because I’m using an absolute address for my endpoint, WCF tells me to disable the multipleSiteBindings by removing the following element.

    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
Next I’ll change the default ws2007HttpRelayBinding to disable security.
    <bindings>
      <ws2007HttpRelayBinding>
        <binding>
          <security mode="None" relayClientAuthenticationType="None" />
        </binding>
      </ws2007HttpRelayBinding>
    </bindings>

Configure the ACS security for the ServiceBus and specify the discovery mode to public so that I can see my service in the registry. All of this is done using a default a endpoint behavior.

      <endpointBehaviors>
        <behavior>
          <serviceRegistrySettings discoveryMode="Public" />
          <transportClientEndpointBehavior credentialType="SharedSecret">
            <clientCredentials>
              <sharedSecret issuerName="owner" issuerSecret="SECRET=" />
            </clientCredentials>
          </transportClientEndpointBehavior>
        </behavior>
      </endpointBehaviors>

Using the project properties, I’ll configure the service to run under IIS/AppFabric

image

I can now see my endpoints in the AppFabric management console but I can’t see my service in the Service Bus registry because it’s not activated yet.

image

So I need to configure Auto-Start feature on this service which I can easily do using the AppFabric management console.

image

After configuring AutoStart I can straight a way see my service in the registry

image

When I browse to my service I see the standard help page which the metadata URL

image

Download: Web.config

Posted in Uncategorized | Leave a Comment »

2010 in review

Posted by zamd on January 3, 2011

The stats helper monkeys at WordPress.com mulled over how this blog did in 2010, and here’s a high level summary of its overall blog health:

Healthy blog!

The Blog-Health-o-Meter™ reads Wow.

Crunchy numbers

Featured image

About 3 million people visit the Taj Mahal every year. This blog was viewed about 27,000 times in 2010. If it were the Taj Mahal, it would take about 3 days for that many people to see it.

In 2010, there were 22 new posts, growing the total archive of this blog to 66 posts. There were 108 pictures uploaded, taking up a total of 7mb. That’s about 2 pictures per week.

The busiest day of the year was July 7th with 287 views. The most popular post that day was Using WIF with Workflow Services.

Where did they come from?

The top referring sites in 2010 were stackoverflow.com, social.msdn.microsoft.com, blogs.msdn.com, davidezordan.net, and forums.silverlight.net.

Some visitors came searching, mostly for datacontract isreference, this element is not currently associated with any context, id3082: the request scope is not valid or is unsupported., wif rest, and zamd.

Attractions in 2010

These are the posts and pages that got the most views in 2010.

1

Using WIF with Workflow Services July 2010
3 comments

2

DataContract Serializer and IsReference property May 2008
2 comments

3

Adding Dynamic methods to a WCF Service February 2010
1 comment

4

Integrating WIF, WF 4.0 & AppFabric: Claims-Based-Delegation June 2010
9 comments

5

Error handling with WebHttpBinding for Ajax/JSON July 2008
1 comment

Posted in Uncategorized | Leave a Comment »

WCF Certificates in Compute Emulator

Posted by zamd on December 21, 2010

Windows Azure SDK 1.3 introduced significant changes to the local development environment. The old DevFabric is broken down into “Compute emulator” & “Storage emulator” which are the local emulated environments for the compute and storage respectively.

Azure SDK 1.3 uses the ‘full IIS’ feature for the WebRole running in the compute emulator which makes it much easier to configure and debug applications in the emulator. For example, when you run your azure project (containing a WebRole) in the Compute emulator it transparently creates web sites and application pools in IIS and configures them correctly by pointing to the physical application directory. Your WebRole code executes inside the good-old worker process (w3wp.exe) and can be configured using the appPool properties plus you can directly edit the web.config to change application settings.

image image

You can configure HTTPs endpoints for you application and the emulator automatically setup SSL bindings using a test certificate. These bindings can be viewed using the netsh.exe utility.image

If your WebRole however requires additional certificates then you have to manually deploy those. For example, WCF message security would require a service certificate which needs to be referenced in the web.config. 

  1. <serviceCredentials>
  2.   <serviceCertificate findValue="bc2b61b66fda75dbaae50ae2757ad756cfeff016" x509FindType="FindByThumbprint" storeLocation="LocalMachine" storeName="My" />
  3. </serviceCredentials>

The AppPool created by the Compute emulator is configured to run under ‘Network Service’ account so additional certificate needs to be copied in the local machine store (inside personal folder) and ‘Network Service’ account needs to have read permissions to the private keys.

Posted in Windows Azure | Leave a Comment »

Initializing Auto-Start WCF/Workflow Services

Posted by zamd on November 26, 2010

AppFabric AutoStart feature is built on top of IIS 7.5 AutoStart feature. IIS 7.5 provides an extensibility point where you can specify your custom initialization providers which will be executed as part of application start-up and gives you the ability to perform costly initialization. For example, pre-populating an AppFabric cache.

Windows Server AppFabric uses this extensibility point to implement the AutoStart feature for WCF & Workflow Services (XAMLX). As part of AppFabric installation, it registers a custom AutoStartProvider which is responsible for activating all the services configured for AutoStart. Here is a simple flow diagram…

imageActivation of WCF/Workflow Services results in calling the ServiceHostFactory associated with the service to return an instance of the ServiceHost which would ultimately host the service and make it available to the clients. This behaviour opens up an option where you could put your costly initialization inside the custom ServiceHostFactory directly rather than using the IIS 7.5 extensibility. CreateServiceHost method of your custom factory will be invoked as soon as AppFabric auto starts your service.

public class CustomXamlxHostFactory : WorkflowServiceHostFactory     
{
      protected override WorkflowServiceHost CreateWorkflowServiceHost(WorkflowService service, Uri[] baseAddresses)

        {

            var host = base.CreateWorkflowServiceHost(service, baseAddresses);

            // Initialization logic: Populate AppFabric cache etc..

            return host;

        }

}

In .NET 4.0, a custom ServiceHostFactory can be easily associated with a service using the <serviceActivations> element in the web.config.

image

Check out my earlier post for additional details…

Posted in Windows Server AppFabric | Leave a Comment »

WCF Reliable Messaging Retransmission Algorithm

Posted by zamd on October 13, 2010

When configuring WS-Reliable messaging, you would notice that even though number of retries (MaxRetryCount) is configurable but the interval in which retries are attempted is NOT configurable.  This is because WCF uses an exponential back-off congestion control algorithm to calculate the retry timeout.  This algorithm is internal to WCF and is NOT configurable.

The initial retry time is calculated based on the “session initiation time” (Time difference between the CreateSequence and CreateSequenceResponse). The algorithm doubles the retransmission delay with every attempt until MaxRetryCount reached.

If you try to send large messages inside a reliable session you might see additional retransmission fairly quickly. As the RM implementation calculates its initial retransmission timeout based on the “session initiation time” which remains quite small value (< 50ms ) in most cases. Now if the second message is a large one – the retry timeout expires and message is retransmitted.  This behaviour is by design as Reliable messaging is not intended to be used for large messages – this is why it doesn’t support streaming. If your goal is to send large messages and survive broken connections, then you should look at ReliableSessions along with the ChunckingChannel.

Posted in WCF | Leave a Comment »

Web Services Federation with ACS v2

Posted by zamd on October 5, 2010

Access Control Service v2 is significantly enhanced compared to the first version which only supported OAuth WRAP and Simple Web Tokens. Check out this post from Hervey for a listing of new exciting features. In this post I’ll talk about integrating ACS v2 with web/workflow services (hosted in Windows Server AppFabric) and show you all the steps involved in this process.

To start login into ACS Portal and create a new namespace:

image

Once the namespace is activated, click on the manage link to open the ACS management portal:

image 

Switch to “Application Integration” page which list various endpoints exposed by the ACS

image

Copy the URL of the WS-Federation Metadata endpoint in a new browser window and you would get following error.

image

So our STS instance needs a signing certificate. This certificate is even required to generate Federation metadata document as it is a signed document.  Let’s add a private key signing certificate.

Go to “Certificates and Keys” page and add a token signing certificate.

image

The command to generate a simple self-signed certificate is listed on the page.

image

Now try browsing the Federation metadata and this time you should see the metadata in the browser.

Next create a new Workflow Service in using the “WCF Workflow Service Application” template

image 

Wizard also generates some basic configuration…

Code Snippet
  1. <?xml version=1.0 encoding=utf-8 ?>
  2. <configuration>
  3.   <system.web>
  4.     <compilation debug=true targetFramework=4.0 />
  5.   </system.web>
  6.   <system.serviceModel>
  7.     <behaviors>
  8.       <serviceBehaviors>
  9.         <behavior>
  10.           <!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>
  11.           <serviceMetadata httpGetEnabled=true/>
  12.           <!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>
  13.           <serviceDebug includeExceptionDetailInFaults=false/>
  14.         </behavior>
  15.       </serviceBehaviors>
  16.     </behaviors>
  17.     <serviceHostingEnvironment multipleSiteBindingsEnabled=true />
  18.   </system.serviceModel>
  19.   <system.webServer>
  20.     <modules runAllManagedModulesForAllRequests=true/>
  21.   </system.webServer>
  22. </configuration>

 

ACS v2 fully integrates with Windows Identity Foundation and this integration is done using the WS-Federation Metadata. When you install WIF SDK, it extends Visual Studio with some additional command like “Add STS Reference” etc.

Right click on the project and Choose the “Add STS Reference” command to launch Federation Utility wizard.

image 

Choose the existing STS option and in textbox specify the Federation metadata URL.

image

If you have used a self-signed signing certificate you would get “chain validation error” in the next step.

image

Disable the “Certificate Chain Validation” and continue to the next step and specify a “Token encryption certificate”

image

Click next to finish the wizard.  The wizard would generate the required configuration to configure this web service to require a SAML token from ACS v2.

Following are some key configuration changes.

  • Default binding for the http scheme is set to ws2007FederationHttpBinding.
<protocolMapping>
  <add scheme=http binding=ws2007FederationHttpBinding />
</protocolMapping>
  • WIF is configured on the Web Service using the default service behavior
<serviceBehaviors>
  <behavior>
    <federatedServiceHostConfiguration />
    <serviceMetadata httpGetEnabled=true />
    <serviceDebug includeExceptionDetailInFaults=false />
    <serviceCredentials>
      <!–Certificate added by FedUtil.  Subject=’CN=localhost’, Issuer=’CN=Root Agency’.–>
      <serviceCertificate findValue=F7AD5A9DCC35F21FFC691925515F48EB44F5E07A
                          storeLocation=LocalMachine
                          storeName=My x509FindType=FindByThumbprint />
    </serviceCredentials>
  </behavior>
</serviceBehaviors>

 

Default ws2007FederationHttpBinding is configured to require token from ACS v2

<ws2007FederationHttpBinding>
  <binding>
    <security mode=Message>
      <message>
        <issuerMetadata address=https://alpha2.accesscontrol.appfabriclabs.com/v2/wstrust/mex />
        <claimTypeRequirements>
          <!–Following are the claims offered by STS ‘https://alpha2.accesscontrol.appfabriclabs.com/’.
          <add claimType=”http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name” isOptional=”true” />
          <add claimType=”http://schemas.microsoft.com/ws/2008/06/identity/claims/role” isOptional=”true” />
          <!–<add claimType=”http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier” isOptional=”true” />–>
          <!–<add claimType=”http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider” isOptional=”true” />–>
        </claimTypeRequirements>
      </message>
    </security>
  </binding>
</ws2007FederationHttpBinding>

And finally Microsoft.IdentityModel configuration is generated to configure various WIF token validation configuration

<microsoft.identityModel>
  <service>
    <audienceUris>
      <add value=http://localhost:53250/Service1.xamlx />
    </audienceUris>
    <issuerNameRegistry type=Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry,
                        Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35>
      <trustedIssuers>
        <add thumbprint=F7AD5A9DCC35F21FFC691925515F48EB44F5E07A name=https://alpha2.accesscontrol.appfabriclabs.com/ />
      </trustedIssuers>
    </issuerNameRegistry>
    <certificateValidation certificateValidationMode=None />
  </service>
</microsoft.identityModel>

 

Ok let’s now create a console client for this web service. Remember we haven’t configured anything in the ACS yet other than specifying a signing cert.

image 

Choose the “Add Service Reference” to add a reference to this service

image

When you click Ok, SvcUtil.exe will detect that this service requires a token from ACS and will go and do metadata exchange to figure out various endpoints supported ACS v2. It will then generate all the configuration required to talk to ACS and the service. Because ACS supports multiple token issuance endpoints, svcutil.exe simply picks the first one. We need to change that manually to the one we want to use for our scenario. For this example I’m going to use the UserName endpoint so I’ll change following section of the binding:

<issuedTokenParameters keySize=256 keyType=SymmetricKey tokenType=“”>
    <additionalRequestParameters>
        <trust:SecondaryParameters xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>
            <trust:KeyType xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</trust:KeyType>
            <trust:KeySize xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>256</trust:KeySize>
            <trust:Claims Dialect=http://schemas.xmlsoap.org/ws/2005/05/identity
                xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>
                <wsid:ClaimType Uri=http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
                    Optional=true xmlns:wsid=http://schemas.xmlsoap.org/ws/2005/05/identity />
                <wsid:ClaimType Uri=http://schemas.microsoft.com/ws/2008/06/identity/claims/role
                    Optional=true xmlns:wsid=http://schemas.xmlsoap.org/ws/2005/05/identity />
            </trust:Claims>
            <trust:KeyWrapAlgorithm xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p</trust:KeyWrapAlgorithm>
            <trust:EncryptWith xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptWith>
            <trust:SignWith xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://www.w3.org/2000/09/xmldsig#hmac-sha1</trust:SignWith>
            <trust:CanonicalizationAlgorithm xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://www.w3.org/2001/10/xml-exc-c14n#</trust:CanonicalizationAlgorithm>
            <trust:EncryptionAlgorithm xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptionAlgorithm>
        </trust:SecondaryParameters>
    </additionalRequestParameters>
    <issuer address=https://alpha2.accesscontrol.appfabriclabs.com/v2/wstrust/13/issuedtoken
        binding=customBinding bindingConfiguration=https://alpha2.accesscontrol.appfabriclabs.com/v2/wstrust/13/issuedtoken />
    <issuerMetadata address=https://alpha2.accesscontrol.appfabriclabs.com/v2/wstrust/mex />
</issuedTokenParameters>

to

<issuedTokenParameters keySize=256 keyType=SymmetricKey tokenType=“”>
    <additionalRequestParameters>
        <trust:SecondaryParameters xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>
            <trust:KeyType xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</trust:KeyType>
            <trust:KeySize xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>256</trust:KeySize>
            <trust:Claims Dialect=http://schemas.xmlsoap.org/ws/2005/05/identity
                xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>
                <wsid:ClaimType Uri=http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
                    Optional=true xmlns:wsid=http://schemas.xmlsoap.org/ws/2005/05/identity />
                <wsid:ClaimType Uri=http://schemas.microsoft.com/ws/2008/06/identity/claims/role
                    Optional=true xmlns:wsid=http://schemas.xmlsoap.org/ws/2005/05/identity />
            </trust:Claims>
            <trust:KeyWrapAlgorithm xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p</trust:KeyWrapAlgorithm>
            <trust:EncryptWith xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptWith>
            <trust:SignWith xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://www.w3.org/2000/09/xmldsig#hmac-sha1</trust:SignWith>
            <trust:CanonicalizationAlgorithm xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://www.w3.org/2001/10/xml-exc-c14n#</trust:CanonicalizationAlgorithm>
            <trust:EncryptionAlgorithm xmlns:trust=http://docs.oasis-open.org/ws-sx/ws-trust/200512>http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptionAlgorithm>
        </trust:SecondaryParameters>
    </additionalRequestParameters>
  <issuer address=https://alpha2.accesscontrol.appfabriclabs.com/v2/wstrust/13/username
          bindingConfiguration=https://alpha2.accesscontrol.appfabriclabs.com/v2/wstrust/13/username binding=ws2007HttpBinding />
</issuedTokenParameters>

Notice I have changed the issuedtoken endpoint to a username endpoint.

Let’s create a basic client and run it.

class Program
{
    static void Main(string[] args)
    {
        var client = new ServiceReference1.ServiceClient();
        Console.WriteLine(client.GetData(33));
    }
}

Got following exception:

System.ServiceModel.Security.SecurityNegotiationException: SOAP security negotiation with ‘http://localhost:53250/Service1.xamlx’ for target ‘http://localhost:53250/Service1.xamlx’ failed. See inner exception for more details. —> System.IdentityModel.Tokens.SecurityTokenValidationException: The X.509 certificate CN=localhost chain building failed. The certificate that was used has a trust chain that cannot be verified. Replace the certificate or change the certificateValidationMode. A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.

Because I’m using self-signed certificate so trust chain is failing. For now I’ll just disable the “trust chain validation” by adding following endpoint behavior to the client config.

<behaviors>
  <endpointBehaviors>
    <behavior>
      <clientCredentials>
        <serviceCertificate>
          <authentication certificateValidationMode=None/>
        </serviceCertificate>
      </clientCredentials>
    </behavior>
  </endpointBehaviors>
</behaviors>

Running it again, I get a different error:

System.ServiceModel.Security.SecurityNegotiationException: SOAP security negotiation with ‘https://alpha2.accesscontrol.appfabriclabs.com/v2/wstrust/13/username’ for target ‘https://alpha2.accesscontrol.appfabriclabs.com/v2/wstrust/13/username’ failed. See inner exception for more details. —> System.InvalidOperationException: The username is not provided. Specify username in ClientCredentials.
Of course I have chosen the userName endpoint on the ACS so WCF is asking about username/password for talking to this endpoint. Let’s specify one.

static void Main(string[] args)
{
    var client = new ServiceReference1.ServiceClient();
    client.ClientCredentials.UserName.UserName = “test”;
    client.ClientCredentials.UserName.Password = “test”;
    Console.WriteLine(client.GetData(33));
}

Running the sample again, this time a call was indeed issued to ACS and I get an error from ACS.

System.ServiceModel.Security.MessageSecurityException: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail. —> System.ServiceModel.FaultException: ID3034: Authentication failed.
   — End of inner exception stack trace —

So ACS has tried to validate the incoming userName/password and it can’t find a match as there is no such userName exist.  Identities owned and managed by ACS can be created using the “Service Identities” link.

Go back to the portal and click on the “Service Identities” link to add a new service identity and name it as “test” (same as our userId)

image

Add a “Password Credential” with password value again set to “test” (same as password used by client app)

image

Running the client again: this time I get a different error:

System.ServiceModel.Security.MessageSecurityException: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail. —> System.ServiceModel.FaultException: ID3082: The request scope is not valid or is unsupported.

So the authentication with ACS was successful but it can’t find a “Relying Party” matching to my request. Please note, client is making a token issuance request for the workflow service which is identified as “http://localhost:53250/Service1.xamlx”.

So let’s add a new Relying Party once again using the management portal.

image 

By running the application, I get following error.

System.ServiceModel.Security.MessageSecurityException: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail. —> System.ServiceModel.FaultException: ID3037: The specified request failed.

Now this error doesn’t tell us much but there are couple of things we need to do. First of all we created a “Default Rule group” as part of our “Relying Party” but we didn’t added any rules to it. So let’s add a Passthrough rule.

image

For Web Services federation, ACS v2 by default uses Holder of Key confirmation method so a public key certificate is required for encrypting the proof key. This certificate MUST match with the private key certificate configured for the web service (aka Relying Party (RP)).

Ok let’s add an encryption certificate using the “Certificates and Keys” page. Remember to select your corresponding RP.

image

Running the application and hurray it runs without error and I can see the output.

image 

In this sample, I have used a Workflow Service but these exact steps works for a code based WCF service as well. It’s a LONG post but hopefully someone will find it useful as it took me some time to figure few hidden gems (especially the holder of key stuff).

Posted in Windows Azure AppFabric | 4 Comments »

WIF based OAuth WRAP Issuer

Posted by zamd on August 13, 2010

WIF provides an API to develop Security Token Services (STSs) which can then be exposed using either WS-Trust (Active-STS) or WS-Federation(Passive-STS) protocols. As mentioned in last post, WIF currently doesn’t support OAuth WRAP protocol so out of box a WIF based SecurityTokenService cannot be used as an OAuth WRAP issuer. In this post, I’ll show you some extensions I have created to expose a service, based on WIF’s token issuance object model (SecurityTokenService, RequestSecurityTokenRequest etc), as an OAuth WRAP issuer.

1: Create an issuer using the standard WIF approach. The only difference is that I’m using a symmetric key for signatures.

public class OAuthIssuer : SecurityTokenService

{

    public OAuthIssuer(SecurityTokenServiceConfiguration config):base(config){}

 

    protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal, RequestSecurityToken request, Scope scope)

    {

        return new ClaimsIdentity(new Claim[] {

               

            new Claim(ClaimTypes.Name, "John"),

            new Claim("email", "John@test.com") });

    }

 

    protected override Scope GetScope(IClaimsPrincipal principal,

        RequestSecurityToken request)

    {

        var scope =  new Scope

        {

            AppliesToAddress = request.AppliesTo.Uri.AbsoluteUri

        };

 

        scope.TokenEncryptionRequired = false;

        scope.SymmetricKeyEncryptionRequired = false;

        scope.SigningCredentials = new SymmetricSigningCredentials("Sapm9PPZZHlo=");

        return scope;

    }

}

2: Host the issuer using following code:

var config = new OAuthIssuerConfiguration()

{

    SecurityTokenService = typeof(OAuthIssuer)

};

config.TokenIssuerName = "MyCustomIssuer";

 

config.SecurityTokenHandlers.AddOrReplace(new CustomUserNameSecurityTokenHandler

{

    UserNamePasswordValidator = (uid, pwd) =>

    {

        Console.WriteLine(uid + " validated.");

    }

});

 

var sh = new OAuthServiceHost(config, new Uri("http://localhost:9111"));

sh.Open();

That’s it, A WIF based OAuth WRAP issuer is ready.

OAuthServiceHost inherits from WCF WebServiceHost and exposes a fixed OAuth WRAP contract to the outside world.

public class OAuthServiceHost : WebServiceHost

{

    internal OAuthIssuerConfiguration Configuration { get; set; }

 

    public OAuthServiceHost(OAuthIssuerConfiguration config)

        : this(config, null) { }

 

    public OAuthServiceHost(OAuthIssuerConfiguration config, Uri baseAddress)

        : base(typeof(OAuthIssuerContract), baseAddress)

    {

        this.Configuration = config;

    }

}

The implementation of OAuth WRAP contract transforms the incoming token issuance request into WIF’s token issuance object model (RequestSecurityTokenRequest etc) and starts the token issuance pipeline. At the end of the pipeline, it packages the final set of claim in a  Simple Web Token and returns it back.

Source code

Posted in WIF | 6 Comments »

Using WIF for securing REST Service

Posted by zamd on July 31, 2010

OAuth WRAP and SWT (Simple Web Token) have emerged as a standard way for employing claim-based-security to the REST services.  Conceptually this model is very similar to the one used in SOAP world. A client goes to an issuer, authenticates itself using some token and gets back a different token (containing claims) in SWT format. 

WIF provides a rich API and object model to claim-enable your .Net applications but currently it doesn’t natively support OAuth or SWT. In this post, I’ll show how you can extend WIF to bring claim-based-security to REST services.  My goal is to implement this functionality in such a way that all the WIF goodness around claims-transformation (ClaimsAuthenticationManager), claim-based-authorization (ClaimsAuthorizationManager) etc can be used exactly the same way in the REST world.

I have achieved this by introducing an OAuth WRAP channel which sits in the WCF channel stack and perform an almost identical job to its SOAP counterpart WS-Security channel.  I have implemented the OAuth WRAP channel using the interceptor API from the REST Starter Kit.

image WebServiceHost2 host = new WebServiceHost2(typeof(TestService), new Uri(http://localhost:9090));

host.Interceptors.Add(new OAuthWrapSecurityChannel());

host.Open();

The OAuth channel takes care of extracting the token from the incoming message, running it through the validation pipeline (based on WIF SecurityTokenHandler framework), calling ClaimsAuthenticationManager, setting the WCF authorization context so that ClaimsAuthorizationManager can be called, and finally presenting the claims to the service method in the standard WIF way: Thread.CurrentPrincipal :)

Now with OAuth channel plugged in, if I call the service with a token issues by the Windows AppFabric ACS:

clip_image002

I get following output on the service side.

clip_image001

And from the service code, you would notice that standard WIF API is used to access incoming claims.

[WebGet]

string Hello()

{

    Console.WriteLine("Hello called…");

    Console.WriteLine("——————");

    var cp = Thread.CurrentPrincipal as IClaimsPrincipal;

    if (cp != null)

    {

        foreach (var id in cp.Identities)

        {

            Console.WriteLine("Authentication Type: " + id.AuthenticationType);

            Console.WriteLine("Is Authenticated: " + id.IsAuthenticated);

            Console.WriteLine("Name: " + id.Name);

            Console.WriteLine();

            Console.WriteLine("Claims…");

            foreach (var c in id.Claims)

            {

                Console.WriteLine(c.ClaimType + ": " + c.Value);

            }

        }

    }

    return "Hello, World";

}

 

WIF would be configured using exactly same configuration settings required for a SOAP service.

  1. <configuration>
  2.   <configSections>
  3.     <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  4.   </configSections>
  5.  
  6.   <system.serviceModel>
  7.     <behaviors>
  8.       <serviceBehaviors>
  9.         <behavior>
  10.           <federatedServiceHostConfiguration />
  11.           <serviceDebug includeExceptionDetailInFaults="true" />
  12.         </behavior>
  13.       </serviceBehaviors>
  14.     </behaviors>
  15.     <extensions>
  16.       <behaviorExtensions>
  17.         <add name="federatedServiceHostConfiguration" type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  18.       </behaviorExtensions>
  19.     </extensions>
  20.   </system.serviceModel>
  21.   <!–WIF configuration–>
  22.   <microsoft.identityModel>
  23.     <service>
  24.       <securityTokenHandlers>
  25.         <add type="Microsoft.IdentityModel.OAuth.SWTSecurityTokenHandler, Microsoft.IdentityModel.OAuth, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  26.       </securityTokenHandlers>
  27.       <issuerNameRegistry type="SampleService.MySimpleRegistry, SampleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  28.       <claimsAuthorizationManager type="SampleService.MySimpleClaimsAuthorizationManager, SampleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  29.       <audienceUris>
  30.         <add value="http://localhost/" />
  31.       </audienceUris>
  32.       <issuerTokenResolver type="SampleService.WrapIssuerTokenResolver, SampleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
  33.     </service>
  34.   </microsoft.identityModel>
  35.   <startup>
  36.     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
  37.   </startup>
  38. </configuration>

 

In summary, these extensions implement OAuth WRAP protocol head for Windows Identity Foundation and re-uses all the neat WIF APIs for deriving the service behaviour. In the next post, I’ll discuss how to create a local OAuth WRAP issuer using the SecurityTokenService WIF API.

Feel free to download the source and experiment.

Posted in WCF, WIF, Windows Azure AppFabric | 6 Comments »

PasswordDigest authentication in WCF

Posted by zamd on July 12, 2010

WS-Security UsernameToken Profile describes how a client can authenticate to a web service using a "username" and a password. Two variations of the password are defined as part of the specification which includes "PasswordText" and "PasswordDigest". Neither WCF nor WIF out of box support "PasswordDigest" however there are some interop scenarios which might require "PasswordDigest". For example, WSE 3.0 supports "PasswordDigest" and if you have to interop your WSE 3.0 clients with WCF services you might need PasswordDigest functionality. In this post I’ll show you a basic implementation of PasswordDigest closely integrated with WCF API. Please note, this could be much easier to implement using the SecurityTokenHandler based API shipped with WIF.

I have created a new assembly and added all the security extensions in this new assembly named Microsoft.ServiceModel.SecurityExtensions.dll.

Microsoft.ServiceModel.SecurityExtensions.dll extends WCF to support Password Digest authentication while retaining WCF’s public programming model. You need to reference this assembly in all your web service projects where you want to enable PasswordDigest authentication. The security extensions are very closely aligned to the standard WCF model of userName/Password validation so you should be able to leverage all of your existing knowledge. 

Please note this is a trivial implementation primarily focused on WCF integration rather than spec implementation. This example doesn’t contain any countermeasure code against replay attacks. You can add such functionality by maintaining a cache of used nonces on the server side and then checking against the replay.

To use these extensions in your web service(s), you need to do following:

  • Specify the type attribute of serviceCredentials to Microsoft.ServiceModel.SecurityExtensions.ServiceCredentialsEx for the extensions to kick in.
  • Specify your custom validator using the standard WCF syntax. Your custom validator MUST inherit from Microsoft.ServiceModel.SecurityExtensions.UserNamePasswordDigestValidator

<behaviors>

  <serviceBehaviors>

    <behavior>

      <serviceCredentials type="Microsoft.ServiceModel.SecurityExtensions.ServiceCredentialsEx, Microsoft.ServiceModel.SecurityExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">

        <userNameAuthentication userNamePasswordValidationMode="Custom"

                                customUserNamePasswordValidatorType="PasswordDigest.MyValidator, PasswordDigest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

      </serviceCredentials>

    </behavior>

  </serviceBehaviors>

</behaviors>

  • Finally implement your custom validator by inheriting from Microsoft.ServiceModel.SecurityExtensions.UserNamePasswordDigestValidator. This class integrates with various extensions and implements the logic of PasswordDigest validation.

I have attached the source code and sample project with this post.

Posted in Extensibility, Security, WCF | Leave a Comment »

Using WIF with Workflow Services

Posted by zamd on July 4, 2010

Windows Identity Foundation integrates with WCF at the host level (ServiceHost) and then various WIF extensibility points are invoked at different stages of WCF message processing pipeline. In this post, I will show how WIF can be integrated with Workflow Services to enable common security scenarios. Additional rich security scenarios can also be enabled by using activities which are currently part of WF Security Pack project.

Basic Walkthrough

Create a new WCF Workflow Service Application by choosing File -> New Project:

clip_image002[4]

You would notice generated web.config is using simplified WCF 4.0 configuration. There are no explicit endpoint definitions rather service would get default endpoints at runtime.

  <system.serviceModel>

    <behaviors>

      <serviceBehaviors>

        <behavior>

          <!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>

          <serviceMetadata httpGetEnabled="true"/>

          <!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>

          <serviceDebug includeExceptionDetailInFaults="false"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

  </system.serviceModel>

A workflow service is a standard WCF service whose implementation is a workflow, so we should be able to integrate WIF using exactly the same techniques we know for code based WCF services.

Externalize the authentication to an STS

Inside Solution Explorer, right click on your workflow service project and select “Add STS Reference” option to launch FedUtil.exe.

On the Welcome Page, specify the Application URI and click next. On Security Token Service Page, select “Use an existing STS” option and specify the URL of the WS-Federation metadata document. For this example, I’m using AD FS 2.0 as the existing STS.

clip_image002[6]

Leave the default value “Disable certificate chain validation” on next page as I’m using self-signed certificates.

On the “Security token encryption”, choose “Enable encryption” option and specify the private key certificate of your service.

clip_image002[8]

Finish the wizard by choosing default values for the next two pages.

Wizard would generate all the configuration required to enable WIF on this Workflow Service. Lets briefly examine the generated configuration:

A new WIF related section is registered…

  <configSections>

    <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

  </configSections>

 

<microsoft.IdentityModel> configuration section is generated to externalize the authentication responsibility for this service to AD FS 2.0.

 

  <microsoft.identityModel>

    <service>

      <audienceUris>

        <add value="http://localhost:2534/Service1.xamlx" />

      </audienceUris>

      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

        <trustedIssuers>

          <add thumbprint="A1D6790E1CD8EAF2A23768E5789805E1AE58C9D6" name="http://ids.bccoss.com/adfs/services/trust" />

        </trustedIssuers>

      </issuerNameRegistry>

      <certificateValidation certificateValidationMode="None" />

    </service>

  </microsoft.identityModel>

 

A new Service Behaviour is added to the default behaviour collection, which configures WIF on this Workflow Service at the host level (WorkflowServiceHost in this case)

      <serviceBehaviors>

        <behavior>

          <federatedServiceHostConfiguration />

          <!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>

          <serviceMetadata httpGetEnabled="true" />

          <!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>

          <serviceDebug includeExceptionDetailInFaults="false" />

          <serviceCredentials>

            <!–Certificate added by FedUtil.  Subject=’CN=SampleService’, Issuer=’CN=Root Agency’.–>

            <serviceCertificate findValue="F042616A35AD30BE5069B468A67FF1233824F5F1" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" />

          </serviceCredentials>

        </behavior>

      </serviceBehaviors>

 

Default binding for the http scheme is changed to a wizard generated wsFederationHttpBinding. This enables all http based default endpoints to be configured to use this wsFederationHttpBinding.

    <protocolMapping>

      <add scheme="http" binding="ws2007FederationHttpBinding" />

    </protocolMapping>

A new default configuration of ws2007FederationHttpBinding is also generated by the wizard based on the selection made in Wizard. This generated binding has an issuerMetadata element specifying the metadata URL of AD FS 2.0 which would be used by the clients to fetch all the endpoints supported by AD FS 2.0

 

    <bindings>

      <ws2007FederationHttpBinding>

        <binding>

          <security mode="Message">

            <message>

              <issuerMetadata address="https://ids.bccoss.com/adfs/services/trust/mex" />

              <claimTypeRequirements>

                <!–Following are the claims offered by STS ‘http://ids.bccoss.com/adfs/services/trust’. Add or uncomment claims that you require by your application and then update the federation metadata of this application.–>

                <add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="true" />

                <add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" isOptional="true" />

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/claims/CommonName" isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/claims/EmailAddress" isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/claims/Group" isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/claims/UPN" isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant" isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod" isOptional="true" />–>

                <!–<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/denyonlysid" isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarysid" isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/denyonlyprimarygroupsid" isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid" isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid" isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid" isOptional="true" />–>

                <!–<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname" isOptional="true" />–>

              </claimTypeRequirements>

            </message>

          </security>

        </binding>

      </ws2007FederationHttpBinding>

    </bindings>

 

That’s it. Your claim-aware Workflow Service is ready now.

At this stage, clients can generate the required configuration by simply using “Add Service Reference” wizard which would generate config  (endpoint addresses & bindings) for all the different endpoints supported by AD FS 2.0.

The main service endpoint would automatically be configured to acquire a token from AD FS 2.0 before calling the Workflow Service. 

As AD FS 2.0 supports multiple endpoints, generated wsFederationHttpBinding simply picks the first endpoint returned by the AD FS 2.0. This first endpoint choice might not be appropriate in all scenarios and you can easily change it in the client config file.

 

 

        <client>

            <endpoint address="http://localhost:2534/Service1.xamlx" binding="customBinding"

                bindingConfiguration="WS2007FederationHttpBinding_IService"

                contract="ServiceReference1.IService" name="WS2007FederationHttpBinding_IService">

                <identity>

                    <certificate encodedValue="AwAAAAEAAAAUAAAAhxjyEc1MCXsA5XXteMRn0iyQBuwgAAAAAQAAALgBAAAwggG0MIIBYqADAgE==" />

                </identity>

            </endpoint>

        </client>

 

 

Claims Transformation

ClaimsAuthenticationManager can be used to perform claims-transformation exactly in the same way as in code based service.

 

    public class SimpleClaimsAuthenticationManager:ClaimsAuthenticationManager

    {

        public override IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal)

        {

            // Claims transformation…

            return base.Authenticate(resourceName, incomingPrincipal);

        }

    }

 

This class can then be configured on the workflow service using following configuration. All other config except the highlighted line was automatically generated by FedUtil.exe.

 

 

    <service>

      <audienceUris>

        <add value="http://localhost:2534/Service1.xamlx" />

      </audienceUris>

      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

        <trustedIssuers>

          <add thumbprint="A1D6790E1CD8EAF2A23768E5789805E1AE58C9D6" name="http://ids.bccoss.com/adfs/services/trust" />

        </trustedIssuers>

      </issuerNameRegistry>

      <certificateValidation certificateValidationMode="None" />

      <claimsAuthenticationManager type="DeclarativeServiceLibrary1.SimpleClaimsAuthenticationManager"/>

    </service>

 

Claims based Authorization

 

Similarly Claim-Based-Authorization can be enforced at the host level using a ClaimsAuthorizationManager.

 

    public class SimpleClaimsAuthorizationManager:ClaimsAuthorizationManager

    {

        public override bool CheckAccess(AuthorizationContext context)

        {

            if (((IClaimsIdentity)context.Principal.Identity).Claims.Where(c=>

                c.ClaimType== ClaimTypes.Upn &&

                c.Value == "zam1d@bccoss.com").Count() ==0)

                return false;

 

            return true;

        }

    }

 

      <claimsAuthorizationManager type="DeclarativeServiceLibrary1.SimpleClaimsAuthorizationManager"/>

 

With above authorization manager plugged in, you can verify client is failing with “Access is denied” error.

 

clip_image002

 

Summary

Most of the WIF integration simply works with Workflow Services without any issues and is exactly the same as code based services. If you need to access claims inside your workflows or you want to implement more advance security scenarios such as

  • Fine grained control over token issuance and it’s usage
  • Claims-based delegation to other services

You can use WF Security Pack which provides additional activities and accompanying framework code to accomplish above mentioned security scenarios.

Posted in WF4, WFSP | 5 Comments »

 
Follow

Get every new post delivered to your Inbox.