DCSIMG
July 2012 - Posts - Manu Cohen-Yashar's Blog

Manu Cohen-Yashar's Blog

July 2012 - Posts

Running WIF Relying parties in Windows Azure

When running in a multi server environment like windows azure it is required to make sure the cookies generated by WIF are encrypted with the same pair of keys so all servers can open them.

Encrypt cookies using RSA

In Windows Azure, the default cookie encryption mechanism (which uses DPAPI) is not appropriate because each instance has a different key. This would mean that a cookie created by one web role instance would not be readable by another web role instance. This could lead to service failures effectively causing denial of the service. To solve this problem you should use a cookie encryption mechanism that uses a key shared by all the web role instances. The following code written to global.asax shows how to replace the default SessionSecurityHandler object and configure it to use the RsaEncryptionCookieTransform class:

void Application_Start(object sender, EventArgs e)
{
    FederatedAuthentication.ServiceConfigurationCreated += OnServiceConfigurationCreated;
}

private void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
{
   List<CookieTransform> sessionTransforms =
       new List<CookieTransform>(new CookieTransform[] 
       {
          new DeflateCookieTransform(), 
          new RsaEncryptionCookieTransform(e.ServiceConfiguration.ServiceCertificate),
          new RsaSignatureCookieTransform(e.ServiceConfiguration.ServiceCertificate)
       });

       SessionSecurityTokenHandler sessionHandler =
         new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());
            e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);
}

next upload the certificate to the hosted service and declare it in the LocalMachine certificate store of the running role.

image

image

Failing to do the above will generate the following exception when running a relying party in azure: "InvalidOperationException: ID1073: A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API". It means that decryption with DPAPI failed. It makes sense because DPAPI key is coupled with the physical machine it is running on.

After changing the encryption policy (like so) make sure to delete all existing cookies other wise you will get the following exception: CryptographicException: ID1014: The signature is not valid. The data may have been tampered with. (It means that an old DPAPI cookie is being processed by the new RSA policy and that will obviously will fail.

Enjoy

Manu

How to use the new Distributed Cache (SDK 1.7) for Asp.Net Session State

Until today AppFabric Distributed cache was used to host Azure web roles Asp.Net Session state. Unfortunately there were many problems with AppFabric Azure Distributed Cache:

  1. It was VERY expensive.
  2. It was not available in all Data Centers.
  3. It was slow.

Fortunately in the new SDK (1.7) we have the opportunity to use our resources (i.e. roles) to host the distributed cache cluster and get a free and performant cache.

So lets see how to use it to host asp.net session:

1. For each role that will donate some resource for the distributed cache cluster we should set the cache configuration. Open the new caching tab in the role configuration and enable the cache.

  • Enable the cache
  • Set the deployment policy (use existing roles or create dedicated ones)
  • Provide a valid connection string to storage
  • set the caching policy (sliding / fix expiration), TTL etc.

image

2. Now it is time to add code to the actual web role. First install the NuGet package by searching
for: "windowsazure.caching" and installing "Windows Azure Caching Preview".

image

The installation will add some configuration to web.config.
Set the name of the role (that hosts the cache) in the identifier property:

image 

Now we have to set the session state provider by overriding the session provider configuration to:

 <sessionState mode="Custom" customProvider="AppFabricCacheSessionStoreProvider">
   <providers>
     <add name="AppFabricCacheSessionStoreProvider"  
          type="Microsoft.Web.DistributedCache.DistributedCacheSessionStateStoreProvider, Microsoft.Web.DistributedCache" 
          cacheName="default" useBlobMode="true" dataCacheClientName="default" />
      </providers>
 </sessionState>

The final step is of course to use the session in our application:

protected void btnClick_Click(object sender, EventArgs e)
{
   if (Session["count"] == null)
      Session.Add("count", 0);            
   // increment the counter
  
Session["count"] = (int)Session["count"] + 1; 
   lblCount.Text = Session["count"].ToString();
}

So Simple…

Enjoy

Manu

Production Debugging Videos

I gave a debugging course today and one of my students asked for recommended resources so I did some searching and I found this series of videos:

.NET Debugging Starter Kit for the Production Environment, Part 1
.NET Debugging Starter Kit for the Production Environment, Part 2
.NET Debugging Starter Kit for the Production Environment, Part 3
.NET Debugging Starter Kit for the Production Environment, Part 4
.NET Debugging Starter Kit for the Production Environment, Part 5
.NET Debugging Starter Kit for the Production Environment, Part 6

Go and watch !!!

A recommended book is : "Advanced .NET Debugging" by Mario Hewardt

Enjoy

Manu

Chrome Support for ACS with ADFS 2.0 Identity Provider

When using Windows Azure's Access Control Service (ACS) to perform user authentication against an Active Directory Federated Service (ADFS) endpoint everything works well when using IE However, when using Chrome or Firefox the site continually prompts for credentials over and over again.

Why?

Turns out, the ADFS website that performs authentication of users (this website gets setup in IIS during the installation of ADFS v2.0) is by default configured for Integrated Windows Authentication (IWA). IWA is configured in IIS to use Extended Protection for Authentication (EPA) and therein lies the problem. Apparently, most other browsers don't support EPA yet which is why Firefox & Chrome continually prompt for credentials in a loop.

There are two options to solve this:

  1. Keep using IWA but turn off EPA in IIS for the website (described here)
  2. Turn off IWA in favor of Forms-based Authentication (described here)

Enjoy

Manu

Upload to Shared Access Signature blob using WebClient (REST API)

I want asked by a client how to upload a blob (Put blob) to a SAS (Shared Access Signature) blob using the REST Api.

Here is a simple code snippet demonstrating that using WebClient.

class Program
{
   private static CloudBlobContainer m_container;

   static void Main(string[] args)
   {
      try
      {
         var m_StorageAccount = CloudStorageAccount.DevelopmentStorageAccount;
         var m_BlobClient = m_StorageAccount.CreateCloudBlobClient();
         m_container = m_BlobClient.GetContainerReference("myContainer");
         m_container.CreateIfNotExist();

         BlobContainerPermissions permissions = new BlobContainerPermissions();
         // The container itself doesn't allow public access.
         permissions.PublicAccess = BlobContainerPublicAccessType.Off;
                
         // The container itself doesn't allow SAS access.
         var containerPolicy = new SharedAccessPolicy() { Permissions = SharedAccessPermissions.None };
         permissions.SharedAccessPolicies.Clear();
         permissions.SharedAccessPolicies.Add("TestPolicy", containerPolicy);
         m_container.SetPermissions(permissions);
             
         var uri = GetSharedAccessSignature("b1", DateTime.Now.AddDays(1));
         var client = new WebClient();
         client.UploadFile(uri,"PUT", "b1.txt");
         Console.WriteLine("Done");
      }
      catch (Exception ex)
      {
          Console.WriteLine(ex.ToString());
      }
      Console.ReadLine();
    }


   public static string GetSharedAccessSignature(string objId, DateTime expiryTime)
   {
     CloudBlob blob = m_container.GetBlobReference(objId);

     var blobAccess = new SharedAccessPolicy
     {
         Permissions = SharedAccessPermissions.Write,
         SharedAccessExpiryTime = expiryTime
     };

     return blob.Uri + blob.GetSharedAccessSignature(blobAccess, "TestPolicy");
   }

}
Enjoy
Manu

ACS and OAuth 2.0

I was asked by a customer about the OAuth 2.0 endpoint in the ACS management portal.

image

Well ACS can participate in the OAuth Dance. Its role is to produce authorization code for the user's resource and then produce the actual access token that will enable a client application to access the user's resources at the resource server.

There is a demo provided by the ACS team demonstrating OAuth delegation with ACS. I found a very good blog post explaining the OAuth flow of the sample in great details. I recommend to view the following 10m video to get a better understanding of OAuth before trying to understand this nice demo.

Enjoy

Manu

How web roles can behave like a worker roles

The main difference between web and worker roles is the fact that web roles lives in IIS and so they are running in an application pool. Application pools are going down every X minutes (default is 20) if no request arrived. This is problematic for periodic tasks. For example: If you want a timer to live for a long time and periodically send triggers the application pool must not recycle.

The other day I read a blog post by Steve marx that describe how easy it is to make sure the application pool will not recycle.

All you need to do is run a simple startup task that will execute the following command in elevated mode:

%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00

this command simply set the application pool timeout to zero (which means "never")

This way the most important difference between web role and worker role disappears.

Interesting…

Enjoy

Manu