Phidiax Tech Blog

Adventures in custom software and technology implementation.

Securing BizTalk WCF Receive Locations

As I am sure you are aware, securing WCF services in .NET 4.0 can be "easy" when you already have access to the service's source code: you can just decorate the service interface/class with the ASP.NET Compatibility attribute and enable compatibility mode in the web.config's serviceModel section. But what happens when you don't have access to that source code? Just enabling that mode in web.config does not work unless the source code is built to allow or require that compatibility mode. Unfortunately for us, the BizTalk Service Factories are not setup with compatibility mode turned on, so that doesn't work. However, we do have a few options:

  1. Build a custom behavior to use the SSO Database to store groups or users who can access the service (See Victor Fehlberg's excellent post here: http://fehlberg.wordpress.com/2009/10/06/biztalk-r2-authorization-using-wcf/)
  2. Build a custom behavior to use the ASP.NET URL Authorization Module

Thanks to Victor Fehlberg for providing an excellent solution for SSO: we're going to expand upon that and create a custom behavior that makes use of the ASP.NET URL Authorization Module. What that means for administrators of your BizTalk WCF Services is that they will be able to use familiar tools to secure these services (i.e. the IIS .NET Authorization Rules). To simplify following this post, many of the steps taken in creating the SSO behavior are used in creating the ASP.NET Authorization behavior, and will be reposted here as well instead of referencing individual steps.

ASP.NET URL Authorization

The module used by IIS and ASP.NET to determine who is authorized to access a URL (and optionally a verb for that URL) is in the System.Web library, and easily called using a Windows Principal from the Security namespace. Determining if the authenticated user can access the service is done by:

  1. Determining the current Windows Identity
  2. Instantiating a Windows Principal using that identity
  3. Determining the SVC file URL by using the VirtualPathExtension
  4. Verifying the access using System.Web.Security.UrlAuthorizationModule's CheckUrlAccessForPrincipal method, passing the SVC URL, the Windows Principal, and the verb (i.e. GET)

Authorization Source Code

//Get the WindowsPrincipal of who is calling.
WindowsPrincipal wp = new WindowsPrincipal(ServiceSecurityContext.Current.WindowsIdentity);
            
//Use IIS' authorization rules module to check rights of the current user against the virtual directory.
if (!UrlAuthorizationModule.CheckUrlAccessForPrincipal(instanceContext.Host.Extensions.Find<VirtualPathExtension>().VirtualPath, wp, "GET"))
       throw new AddressAccessDeniedException("Access Denied to service " + instanceContext.Host.Description.Name);

WCF Stack Injection

To make this happen at each call to a BizTalk WCF service, we need to create a Message Inspector to wrap the above code, and a Service Behavior to add the inspector to all endpoint dispatchers, and register that behavior in the machine.config so that the BizTalk WCF Custom Isolated Configuration Editor knows about it.

Message Inspector Source Code

The message inspector source code makes use of the authorization source code above, and throws any necessary exceptions and sends any error messages back to the client. This should inherit from IDispatchMessageInspector, which means that the authorization check should occur during the AfterReceiveRequest method, and the denial message should be sent during the BeforeSendReply method.

class ASPNETCustomAuthorizationInspector : IDispatchMessageInspector
    {
        public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {
            
            //If the user is anonymous, don't bother with the rest, just deny!
            try
            {
                if (ServiceSecurityContext.Current.IsAnonymous)
                    throw new Exception();
            }
            catch 
            {
                //If there's an exception, it is probably ServiceSecurityContext being null.
                //Deny the user the same.
                return false;
            }

            //Get the WindowsPrincipal of who is calling.
            System.Security.Principal.WindowsPrincipal wp = new System.Security.Principal.WindowsPrincipal(ServiceSecurityContext.Current.WindowsIdentity);
            
            //Use IIS' authorization rules module to check rights of the current user against the virtual directory.
            if (!System.Web.Security.UrlAuthorizationModule.CheckUrlAccessForPrincipal(instanceContext.Host.Extensions.Find<System.ServiceModel.Activation.VirtualPathExtension>().VirtualPath, wp, "GET"))
                throw new AddressAccessDeniedException("Access Denied to service " + instanceContext.Host.Description.Name);

            return true;
        }

        public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            //This is to catch any fallout from uncaught exceptions in the AfterReceiveRequest
            if (correlationState==null) correlationState=false;

            if (!(bool)correlationState)
            {
                //When correlationState is false, we need to reply with a fault that the user is not authorized
                reply = Message.CreateMessage(MessageVersion.Soap11, MessageFault.CreateFault(FaultCode.CreateSenderFaultCode("Unauthorized", "http://phidiax.com/wcf/authorization"), new FaultReason("User not authorized to access service")), reply.Headers.Action);
            }
        }
    }

Behavior Source Code

The behavior injects the Inspector into the Dispatch Runtime for each endpoint.

    class ASPNETCustomAuthorizationBehavior : System.ServiceModel.Description.IServiceBehavior
    {
        public void AddBindingParameters(System.ServiceModel.Description.ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<System.ServiceModel.Description.ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            
            
        }

        public void ApplyDispatchBehavior(System.ServiceModel.Description.ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher cDispatcher in serviceHostBase.ChannelDispatchers)
                foreach (EndpointDispatcher eDispatcher in cDispatcher.Endpoints)
                    eDispatcher.DispatchRuntime.MessageInspectors.Add(new ASPNETCustomAuthorizationInspector());            
        }

        public void Validate(System.ServiceModel.Description.ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
                
        }
    }

Behavior Element Source Code (for Machine.config)

The Behavior Element provides instantiation and type information of the behavior for use in the machine.config file.

    class ASPNETCustomAuthorizationBehaviorElement : System.ServiceModel.Configuration.BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(ASPNETCustomAuthorizationBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new ASPNETCustomAuthorizationBehavior();
        }
    }

Machine.config Updates

To make the behavior known to the BizTalk configuration dialogs, the library containing these classes must be strong named and stored in the GAC, and added to the.NET 4.0 machine.config files in the system.serviceModel/extensions/behaviorExtensions section. (both 32 and 64 bit).

    <add name="ASPNETCustomAuthorizationBehavior" type="Phidiax.WCF.SecurityMessageInspectorExtensions.ASPNETCustomAuthorizationBehaviorElement, Phidiax.WCF.SecurityMessageInspectorExtensions, Version=1.0.1.0, Culture=neutral, PublicKeyToken=61337eeaf44284be" />

Publishing the BizTalk WCF Endpoint

Now that the behavior is created and setup in the machine.config, the BizTalk WCF Receive Location can be published and have this behavior used to authorize users to access the service.

Publish WCF Wizard

When publishing the schema or orchestration as a service, two key items must be accounted for:

Use WCF-CustomIsolated binding types to allow additional configuration

Use WCF-CustomIsolated binding types to allow additional configuration

Do not allow anonymous access to the service during the publish process

Do not allow anonymous access to the service during the publish process

WCF Receive Location Configuration

Once the wizard completes, the receive location will exist within the indicated application within BizTalk. Before using the receive port, the binding information needs to be configured. Configure the transport of the receive location for basicHttpBinding, and set the security mode to TransportCredentialOnly:

Setting binding to basicHttpBinding and security mode to TransportCredentialOnly

Setting binding to basicHttpBinding and security mode to TransportCredentialOnly

 

Also set the Security Transport clientCredentialType to Windows:

Set the Security Transport clientCredentialType to Windows

Set the Security Transport clientCredentialType to Windows

 

On the behavior tab, right-click ServiceBehavior and select Insert. The newly created behavior that was setup in the machine config should be present. Select it and click OK:

Select the new behavior

Select the new behavior

IIS and Web.config Setup

The final setup involved is to setup the IIS Application that BizTalk created to Disable Anonymous Authentication and Enable Windows Authentication:

Enable Windows Authentication and Disable Anonymous Authentication

Enable Windows Authentication and Disable Anonymous Authentication

 

Create any necessary allow or deny rules to authorize the proper users and groups using IIS .NET Authorization Rules setup:

Setup any allow or deny rules using IIS .NET Authorization Rules

Setup any allow or deny rules using IIS .NET Authorization Rules

 

Finally, examine the web.config for the BizTalk WCF Service. If the HttpMexEndpoint or HttpsMexEndpoint is enabled, comment that out: MEX endpoints cannot use Windows Authentication, and this will cause obscure errors if left enabled.

Test it out!

To test out the service authentication, open that Service WSDL in your favorite test utility (or even in your favorite browser: the WSDL itself should also be blocked when accessed by unauthorized users), enter your authentication details, and run a request as an unauthorized user. You should not have access, and the underlying method in the service should not have run. Run a request or access the WSDL as an authorized user, and you should get the expected results and be good to go!

Comments (4) -

  • Brandon

    9/23/2016 10:31:36 AM | Reply

    This has been one hell of an article to look up and find, but has a lot of good material on this silly subject of not being able to apply the asp.net compatibility requirement to the biztalk service. Thanks for the information on how to proceed with getting around it.

    • Jason Sauers

      10/18/2016 11:15:48 AM | Reply

      Thanks for your reply.. glad this helped. Post back any new findings that can help the community.

      -Jason

  • Chandan

    3/24/2017 7:17:34 AM | Reply

    Thanks for sharing this article and it has helped us to implement user authorization for BizTalk WCF services.
    We are able to open the WSDL only to legal user now. But some services are not getting consumed at end user system or in soapUI we are getting blank response.

    It would be grate if you can help us to test this behavior in soapUI

    Regards,
    Chandan

    • Dean

      4/24/2017 8:03:44 AM | Reply

      A few recommendations based on experience of possible issues using Windows Auth on WCF services...

      If you are using SoapUI, it doesn't properly implement full Windows authentication, you will need to use SoapUI 4.5.2 or newer, and ensure that the IIS application is enabled to negotiate back to NTLM. As long as your end application properly uses Windows auth, this should only be necessary during testing.

      Also, make sure that the service location falls within trusted or intranet security zones to facilitate Windows authentication in browsers.

      If you still have issues, please email additional details and I will assist as much as possible.

      Thanks,
      Dean

Pingbacks and trackbacks (1)+

Loading

Privacy Policy  |  Contact  |  Careers

2009-2017 Phidiax, LLC - All Rights Reserved