Zulfiqar's weblog

Middleware, security & random .Net

Archive for the ‘Windows Azure AppFabric’ Category

Using Simple Web Token (SWT) with WIF

Posted by zamd on February 8, 2011

SAML 1.1/SAML 2.0 is the default token format when using ACS as the authentication service for your website. In this model, your website talks to ACS using WS-Federation protocol and what it normally gets back is a Saml token. This scenarios is fairly straight-forward as WIF natively supports WS-Federation protocol & SAML1.1/SAML 2.0 token formats.

There are cases where you might want to return a Simple Web Tokens (SWT) after a successful authentication. For example, you might want to use this same SWT (available as a bootstrap token) to call other downstream REST/OData services as depicted in the following diagram.

image

ACS fully supports returning an SWT token after a successfully WS-Fed authentication but WIF currently doesn’t support SWT tokens. You would have to write a custom Security Token Handler for WIF to process SWT tokens coming back to your website. I have created some extensions which enables this and other OAuth WRAP related scenarios. Feel free to download the code from my SkyDrive.

Posted in WIF, Windows Azure AppFabric | 13 Comments »

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/&#8217;.
          <add claimType=”http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name&#8221; isOptional=”true” />
          <add claimType=”http://schemas.microsoft.com/ws/2008/06/identity/claims/role&#8221; isOptional=”true” />
          <!–<add claimType=”http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier&#8221; isOptional=”true” />–>
          <!–<add claimType=”http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider&#8221; 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 »

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 »

Exposing Service metadata via HTTP Get on the Service Bus

Posted by zamd on June 30, 2010

.Net Service Bus currently doesn’t support exposing metadata via HTTP Get. Currently it only supports WS-MetadataExchange based metadata generation. I explored various options and came with following solution which seems to be working fine.

  • Expose a REST endpoint with HTTP Get enabled
  • From the implementation of this endpoint, forward the request to real HTTP Get endpoint
  • Send the response data back to the client via Service Bus
  • I have also used the new .Net 4.0 UseRequestHeadersForMetadataAddressBehavior to fix the port and host name in the generated WSDL file

I have packaged all of the above in a custom service behaviour and you can now enable this feature by simply adding this behaviour (line 16) to your service host.

 

  1.     var cred = new TransportClientEndpointBehavior();
  2.     cred.CredentialType = TransportClientCredentialType.SharedSecret;
  3.  
  4.     cred.Credentials.SharedSecret.IssuerName = "owner";
  5.     cred.Credentials.SharedSecret.IssuerSecret = "SHARED-SECERET";
  6.  
  7.     var baseAddress = ServiceBusEnvironment.CreateServiceUri("http", "ServiceNAMESpace", "");
  8.  
  9.     var sh = new ServiceHost(typeof(EchoService), baseAddress);
  10.     var binding = new WS2007HttpRelayBinding(EndToEndSecurityMode.None,RelayClientAuthenticationType.None);
  11.     var endpoint = sh.AddServiceEndpoint(typeof(IEchoService), binding, "Echo");
  12.     endpoint.Behaviors.Add(cred);
  13.  
  14.     //Add SBMetadataBehavior to enable http get metadata via ServiceBus
  15.     sh.Description.Behaviors.Add(new SBMetadataBehavior("metadata"));
  16.  
  17.     sh.Open();

I have upload the complete solution so feel free to download and experiment.

Posted in Windows Azure AppFabric | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.