Introduction 

Often is a need in the project that some sort of authorization is implemented on the BizTalk services. When doing so the straight forward way is to use the Basic or Windows Authentication on the BizTalk services. In both these cases the users that are available in the active directory will be able to connect to the service and call the BizTalk logic hidden behind the service. But some time it is required that the only one user be given the access to the service. This article aims to discuss the way in which the consumer will be able to invoke the BizTalk logic by using only one user and password.

↑Back To Top


Approach

In this approach, the authorization is enabled for only one userid and password. This can be done by writing a custom service behavior extension which will compare the user id and password from the service header with the pre determined username and the password. These user name and password values can be stored in the Btsntsvc.exe.config file or in the SSO as required. The BizTalk exposed WCF service has Anonymous authentication enabled on the IIS level but at the service level the custom behavior written will limit the actual access to only one user name and password. This behavior can be applied to the BizTalk exposed WCF service by adding it in the receive location configuration.

↑Back To Top


Implementation

The solution can be implemented in three steps.

  1. Creating Custom Service Behavior
  2. Designing BizTalk Solution 
  3. Configuring BizTalk Application 

Creating Custom Service Behavior

To create custom behavior, following steps are to be performed.

  1. Extending the ServiceAuthorizationManager class to create a custom Authorization manager
  2. Implementing the IServiceBehavior interface to create a custom service behavior 
  3. Creating a ServiceBehavior extension element which will be registered in the machine.config and will ultimately be used while configuring the BizTalk recieve location.

Custom Service Authorization Manager

In order to create the custom service authorization manager, the ServiceAuthorizationManager class is overridden. Specifically the CheckAccessCore method is overridden to read the basic authorization header coming the request. Once the authorization string is read, it is decoded to extract out the user name and the password. These can be compared with the custom allowed values and based upon the comparison, the method either return true or false Boolean value to indicate if the user is authorized or not.

The code for the custom service authorization manager is shown below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel;
using System.ServiceModel.Web;
 
 
namespace CustomBasicAuthonRLDemo.Components
{
    public class CustomBasicAuthorizationManger : ServiceAuthorizationManager
    {
        private const string AuthorizationHeaderName = "Authorization";
        //Very Important: The user and password are stored here as this is a sample
        //In real life scenarios, the user id and passsowrd should be stored in the SSO and then fetched from there
 
        private const string Authorizeduser = "Mandar";
        private const string AuthorizedUserPassword = "mandar";
        protected override bool CheckAccessCore(OperationContext operationContext)
        {
            var authHeader = WebOperationContext.Current.IncomingRequest.Headers[AuthorizationHeaderName];
            if ((authHeader != null) && (authHeader != string.Empty))
            {
                //Check if the Authorization is indeed a Basic Authorization
                if (authHeader.Contains("Basic"))
                {
                    //sample header Basic xyz[\r][\n] hence we decode the xyz using the substring starting from 7th position
                    string[] securityHeaderArray = ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(authHeader.Substring(6))).Split(':');
 
                    if (securityHeaderArray[0] == Authorizeduser && securityHeaderArray[1] == AuthorizedUserPassword)
                    {
                        //User is Authenticated
                        return true;
 
                    }
                    else
                    {
                        return false;
                    }
 
                }
                else
                {
                    WebOperationContext.Current.OutgoingResponse.Headers.Add("WWW-Authenticate: Basic realm=\"NameAppenderService\"");
                    throw new WebFaultException(System.Net.HttpStatusCode.Unauthorized);
 
                }
            }
            else
            {
                WebOperationContext.Current.OutgoingResponse.Headers.Add("WWW-Authenticate: Basic realm=\"NameAppenderService\"");
                throw new WebFaultException(System.Net.HttpStatusCode.Unauthorized);
 
            }
        }
    }
}

Custom Service Behavior Class

The custom Service behavior class implements the IServiceBehavior interface. The method ApplyDispathcBehavior needs to be overridden here. The overridden method checks the service description object and extracts out the ServiceAuthorizationBehavior from it. It then checks if this behavior is null or not. If it is null , a new ServiceAuthorizationBehavior is created and the custom Authorization manager created above is attached to this behavior and finally it is added to the service description object. If by default if the behavior is present, then the custom Authorization manager created above is attached to it.

The code for custom behavior class is as follows.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Collections.ObjectModel;
using System.ServiceModel.Channels;
 
namespace CustomBasicAuthonRLDemo.Components
{
    public class CustomBasicAuthorizationServiceBehavior : IServiceBehavior
    {
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            //No Need To implement
        }
 
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            ServiceAuthorizationBehavior authBehavior = serviceDescription.Behaviors.Find<ServiceAuthorizationBehavior>();
 
            //If the authBehavior is null, we add new Service Authorization behavior and assign the  serviceAuthorization manager that we created
            //If the authBehavior is not null, then in that case we assign the custom service authorization manager that we created
 
            if (authBehavior == null)
            {
                authBehavior = new ServiceAuthorizationBehavior();
                authBehavior.ServiceAuthorizationManager = new CustomBasicAuthorizationManger();
                serviceDescription.Behaviors.Add(authBehavior);
            }
            else
            {
                authBehavior.ServiceAuthorizationManager = new CustomBasicAuthorizationManger();
            }
            ((IServiceBehavior)authBehavior).ApplyDispatchBehavior(serviceDescription, serviceHostBase);
        }
 
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            //No Need To implement
        }
    }
}

Creating Custom Behavior Extension Element

In order to access the custom behavior that was created above, it is necessary that a behavior extension element must be created, this extension element can be registered in the machine.config later on to make it accessible in the BizTalk admin console while configuring the receive location. The BehaviorType and CreateBehavior methods are overridden in the custom behavior extension element to point to the custom service behavior created above. The code is as follows.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel.Configuration;
 
namespace CustomBasicAuthonRLDemo.Components
{
    public class CustomBasicAuthorizationExtensionElement : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get
            {
                return typeof(CustomBasicAuthorizationServiceBehavior);
            }
        }
 
        protected override object CreateBehavior()
        {
            return new CustomBasicAuthorizationServiceBehavior();
        }
 
    }
}

Once all the three custom classes are created, the assembly must be added to GAC and the entry for the custom behavior extension created is to be added to the machine.config. A sample entry is shown below.

<add name="CustomBasicAuthorizationExtension" type="CustomBasicAuthonRLDemo.Components.CustomBasicAuthorizationExtensionElement, CustomBasicAuthonRLDemo.Components, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d1c12132208c90cb"/>
 

This entry needs to be added to both the 64 bit and the 32 bit machine.config. BizTalk Admin console runs on 32 bit so for the extension to be accessible from the BizTalk admin console, it is imperative that the key entry be added to 32 bit machine config.

Alternative to above method is to import the configuration on the receive handler which will be attached to the Receive location for the service. Read more at : How to register WCF extensions in BizTalk?

Designing BizTalk Solution

The BizTalk solution to test the custom behavior is quite simple. The orchestration takes the first name and last name and return a full name by concatenating both. Once the solution is deployed, the next task is to expose the BizTalk schemas as WCF service. In order to allow us to implement the custom service behavior on the WCF location, the WCF-CustomIsolated adapter needs to be used. Following screen shot highlights the important configurations while exposing the WCF service.



At IIS level only anonymous authentication is enabled only as shown below.


This allows the IIS to do the routing while the actual authorization to the service is taken care of by the custom service behavior written above.

Configuring BizTalk Application in Admin Console

Once the schemas are exposed as service, the WCF publishing Wizard creates a Receive Port and Location in the BizTalk application. The receive location needs to be configured again manually so that the custom service behavior can be attached to the service.
Following are some of the important configurations that need to be taken care of.

  1. Click on Configure tab of the Receive location.



  2. On the behavior tab Right click on the Service Behaviors to add the extension that was added to machine.config files earlier.



  3. Select the correct behavior element from the pop up and click on OK.

       

    The custom behavior is now attached to the Receive location.



  4. On the bindings tab> Select the custom bindings and set the messageversion property to Soap12



Click on OK to save the configuration.

↑Back To Top


Testing

Following scenarios were tested by consuming the BizTalk exposed service from SOAP UI to examine the custom service behavior.

  1. No Authorization passed
  2. Correct user and Incorrect Password in Authorization
  3. Incorrect User and Correct User Password in Authorization
  4. Correct User Credentials.

No Authorization Passed

When No Authorization header is passed the service replies with an unauthorized message reply and tells the user to implement the basic authentication on their service.

  


  

Correct user and Incorrect Password in Authorization 

In this scenario the service returns "Access is Denied" message.

  


Incorrect User and Correct Password Authorization

In this scenario again the service returns the Access is Denied message.

  

Correct User Credentials

In this case the service allows the user to access and provides a valid response.

  

↑Back To Top


Conclusion

Based upon the approach seen above, it can be concluded that it is very easy to implement custom service as well as service behaviors to extend the current WCF adapters. All that is required is a little brush up on the WCF extension which can be found extensively on the MSDN.

↑Back To Top


See Also

Another article which explains how to implement custom behaviors in BizTalk can be found at Invoke ReSTful Web Services with BizTalk Server 2010 .
A great place to get started on BizTalk is BizTalk Server Resources on the TechNet Wiki 

↑Back To Top


References

Following documentation was referred while writing this article.

  1. Configuring and Extending the Runtime with Behaviors 
  2. IServiceBehavior Interface 
  3. ServiceDescription Class
  4. ServiceAuthorizationManager Class
  5. How to: Create a Custom Authorization Manager for a Service

↑Back To Top