April 2012 - Posts

A common scenario for many web applications running in the cloud is to integrate with existing systems through web services (no matter the messaging style they use). Although in these scenarios, an SLA is typically used as an agreement between the two parties to assure certain level of availability, many things can still fail. Therefore, it is always a good idea to have a mechanism in place to handle any possible error condition and retry the execution when it is possible.

As example, you could have a web application that calls an online CRM system (like Salesforce.com or MS Dynamics) for allowing the users to report incidents. In that scenario, we can not assume any possible call to the CRM system will always succeed. On the other hand, this kind of call does not require an immediate response for the user, so it can be scheduled for later execution and retried if something unexpected happens.

A persistent storage for the messages like a queue is always a good choice for decoupling clients from services, and also accomplish the goal previously discussed. When you move to Windows Azure, there are two different queue offerings, Queues as part of the Storage service, and Queues (or Topics) as part of the Service Bus.

The Service Bus SDK provides a programming model on top of WCF for consuming or sending messages to the queues, which makes this solution very appealing for this scenario. The Service Bus also provides Topics, which are an specific kind of queues that supports subscriptions.

By using Service Bus Queues, the calls to any third party service could be eventually wrapped up in WCF services that are invoked by the web application. The following image illustrates the possible architecture,

queues

One of the core classes in the WCF programming model for the Service Bus Queues is BrokeredMessage. This class represents a message that can be sent to/from an existing queue, and contains a lot of  standard properties such as MessageId, ReplyTo, SessionId or Label to name a few. It also contain a dictionary for custom properties that an application can assign to the message.

In the example above, the MessageId property can be used to correlate the input and out messages in the queue and update the corresponding result in the web application. The WCF service can also use the ReplyTo property, which represents the queue name in which the response should go. Sessions is another concept supported in the Service Bus Queues, which are useful for correlating a set of messages as a batch for processing.   This is something optional and requires the queue to support sessions when they are created.

In WCF, the BrokeredMessage is assigned to the service call with a message property BrokeredMessageProperty as it is illustrated bellow,

var channelFactory = new ChannelFactory<ICRMServiceClient>("crminput");
var clientChannel = channelFactory.CreateChannel();
 
// Use the OperationContextScope to create a block within which to access the current OperationScope
using (var scope = new OperationContextScope((IContextChannel)clientChannel))
{
    // Create a new BrokeredMessageProperty object
    var property = new BrokeredMessageProperty();
 
    // Use the BrokeredMessageProperty object to set the BrokeredMessage properties
    property.Label = "Incident";
    property.MessageId = Guid.NewGuid().ToString();
    property.ReplyTo = "sb://xxx.servicebus.windows.net/input";
 
    // Add BrokeredMessageProperty to the OutgoingMessageProperties bag provided 
    // by the current Operation Context 
    OperationContext.Current.OutgoingMessageProperties.Add(BrokeredMessageProperty.Name, property);
    
    //Do the service call here
 
 
}

On the service side, the BrokeredMessageProperty instance can be retrieved in a similar way

var incomingProperties = OperationContext.Current.IncomingMessageProperties;
var property = incomingProperties[BrokeredMessageProperty.Name] as BrokeredMessageProperty;

Another important feature in the programming model for supporting execution retries in our example is the ReceiveContext. By decorating the WCF service contract with the ReceiveContextEnabled attribute, we can manually specify whether the operation was successfully completed or not. If the operation was not completed, the message will remain in the queue and the operation will be executed again next time.

[ServiceContract()]
public interface ICRMService
{
    [OperationContract(IsOneWay=true)]
    [ReceiveContextEnabled(ManualControl = true)]
    void CreateCustomer(Customer customer);
}
 
The following code shows how the operation implementation looks like,
 
var incomingProperties = OperationContext.Current.IncomingMessageProperties;
var property = incomingProperties[BrokeredMessageProperty.Name] as BrokeredMessageProperty;
 
//Complete the Message
ReceiveContext receiveContext;
if (ReceiveContext.TryGet(incomingProperties, out receiveContext))
{
   //Do Something                
   receiveContext.Complete(TimeSpan.FromSeconds(10.0d));
}
else
{
   throw new InvalidOperationException("...");
}

As you can see, the ReceiveContext instance is marked as complete or implicitly set as not complete when an exception is thrown.

The assemblies for the Service Bus SDK are available as part of a Nuget package “Windows Azure Service Bus”. As part of the package registration, all the required configuration extensions for the WCF such as custom bindings and behaviors are also added in the application configuration file.

NetMessagingBinding is the one you need to use for sending or receiving messages from a queue. That binding is constantly polling the queues for detecting new messages, and activating the WCF service when a new message arrives. For that reason, you need to keep the web application App pool running all the time. This can be accomplished in Windows Azure with a simple approach as this one mentioned by Christian Weyer in this post.

Posted by cibrax
Filed under: , ,

Moving to the cloud can represent a big challenge for many organizations when it comes to reusing existing infrastructure. For applications that drive existing business processes in the organization, reusing IT assets like active directory represent good part of that challenge. For example, a new web mobile application that sales representatives can use for interacting with an existing CRM system in the organization.

In the case of Windows Azure, the Access Control Service (ACS) already provides some integration with ADFS through WS-Federation. That means any organization can create a new trust relationship between the STS running in the ACS and the STS running in ADFS. As the following image illustrates, the ADFS running in the organization should be somehow exposed out of network boundaries to talk to the ACS. This is usually accomplish through an ADFS proxy running in a DMZ.

ActiveDirectoryForCloud1

This is the official story for authenticating existing domain users with the ACS.  Getting an ADFS up and running in the organization, which talks to a proxy and also trust the ACS could represent a painful experience. It basically requires  advance knowledge of ADSF and exhaustive testing to get everything right. 

However, if you want to get an infrastructure ready for authenticating your domain users in the cloud in a matter of minutes, you will probably want to take a look at the sample I wrote for talking to an existing Active Directory using a regular WCF service through the Service Bus Relay Binding.

You can use the WCF ability for self hosting the authentication service within a any program running in the domain (a Windows service typically). The service will not require opening any port as it is opening an outbound connection to the cloud through the Relay Service. In addition, the service will be protected from being invoked by any unauthorized party with the ACS, which will act as a firewall between any client and the service. In that way, we can get a very safe solution up and running almost immediately.

To make the solution even more convenient, I implemented an STS in the cloud that internally invokes the service running on premises for authenticating the users. Any existing web application in the cloud can just establish a trust relationship with this STS, and authenticate the users via WS-Federation passive profile with regular http calls, which makes this very attractive for web mobile for example.

ActiveDirectoryForCloud2

This is how the WCF service running on premises looks like,

[ServiceBehavior(Namespace = "http://agilesight.com/active_directory/agent")]
public class ProxyService : IAuthenticationService
{
    IUserFinder userFinder;
    IUserAuthenticator userAuthenticator;
 
    public ProxyService()
        : this(new UserFinder(), new UserAuthenticator())
    {
    }
 
    public ProxyService(IUserFinder userFinder, IUserAuthenticator userAuthenticator)
    {
        this.userFinder = userFinder;
        this.userAuthenticator = userAuthenticator;
    }
 
    public AuthenticationResponse Authenticate(AuthenticationRequest request)
    {
        if (userAuthenticator.Authenticate(request.Username, request.Password))
        {
            return new AuthenticationResponse
            {
                Result = true,
                Attributes = this.userFinder.GetAttributes(request.Username)
            };    
        }
 
        return new AuthenticationResponse { Result = false };
    }
}

Two external dependencies are used by this service for authenticating users (IUserAuthenticator) and for retrieving user attributes from the user’s directory (IUserFinder). The UserAuthenticator implementation is just a wrapper around the LogonUser Win Api.

The UserFinder implementation relies on Directory Services in .NET for searching the user attributes in an existing directory service like Active Directory or the local user store.

public UserAttribute[] GetAttributes(string username)
{
    var attributes = new List<UserAttribute>();
 
    var identity = UserPrincipal.FindByIdentity(new PrincipalContext(this.contextType, this.server, this.container), IdentityType.SamAccountName, username);
    if (identity != null)
    {
        var groups = identity.GetGroups();
        
        foreach(var group in groups)
        {
            attributes.Add(new UserAttribute { Name = "Group", Value = group.Name });
        }
        
        if(!string.IsNullOrEmpty(identity.DisplayName))
            attributes.Add(new UserAttribute { Name = "DisplayName", Value = identity.DisplayName });
        
        if(!string.IsNullOrEmpty(identity.EmailAddress))
            attributes.Add(new UserAttribute { Name = "EmailAddress", Value = identity.EmailAddress });
    }
 
    return attributes.ToArray();
}
As you can see, the code is simple and uses all the existing infrastructure in Azure to simplify a problem that looks very complex at first glance with ADFS.

All the source code for this sample is available to download (or change) in this GitHub repository,

https://github.com/AgileSight/ActiveDirectoryForCloud

Posted by cibrax
More Posts