Nick's Blog

Biztalk gotcha!

Posts Tagged ‘WCF Adapter

Biztalk WCF adapter Security – part 2

leave a comment »

In Part 1, I have created my own behavior class and added it to the receive location. But after that, the test client always gets “access is denied” exception no matter what credentials I used. Then after another hour of head scratching…. I found out that in order for authorization to work, I need to set up all the authentication settings to match it.

First, fire up IIS, and uncheck the anonymous access in Directory Security/Authentication and access control. That handles the corresponding IIS setting for authentication.

Secondly, in biztalk administration console, configure the WCF-CustomIsolated adapter and set the basichttpbindings to use TransportCredentialOnly and windows as the clientCredentialType. That takes care of biztalk’s authentication settings.

Finally, open up the test client again and we should see……………..WHAT THE ****???? RED WORDS!!!!!!

“Security settings for this service require ‘Anonymous’ Authentication but it is not enabled for the IIS application that hosts this service.”

ok..this is because when we created the webservice, the meta data endpoint is the only endpoint exists in the web.config, and meta data endpoint’s mexhttpbinding only supports anonymous authentication.

To solve this, add a binding to the web.config, and modified the HttpMexEndpoint so that it uses the binding which is using Windows authentication. And everything should work……if you are as lucky as me..

<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name=”CustomBasicBinding”>
<security mode=”TransportCredentialOnly”>
<transport clientCredentialType=”Windows” />
</security>
</binding>
</basicHttpBinding>
</bindings>

</system.serviceModel>

<endpoint name=”HttpMexEndpoint” address=”mex” binding=”basicHttpBinding” bindingConfiguration=”CustomBasicBinding” contract=”IMetadataExchange” />

Note: If everything is not working as you would expect it to, you can try the following

1. make sure the dll in the GAC is using the most up to date version. Sometimes biztalk holds the dll in memory and you might need to uninstall it, close biztalk administration console, install it and do it over again.

2. IISreset

Biztalk WCF adapter Security – part 1

leave a comment »

I’ve spent days to try to set up a simple windows authorisation in a WCF webservice published by Biztalk. I will share how I managed to do it here and hope that it might save others sometime when they are trying to do the same thing.

Initially, I knew nothing about webservices when I started this problem, after reading some articles on WCF security, I believe that I could set up the authorization and anthentication in the web.config. And after a frustrating day, I gave up believing that.

The following guide shows how I achieved the goal, even though I don’t fully understand some of the things here and there, this configuration worked for me.

I believe that to add authorization, I have add it in biztalk but not the webservice side.

Firstly, I published the web service through the biztalk WCF publishing wizard, it’s published to use WCF-BasicHttp adapter.

Then I followed the post from

http://www.topxml.com/code/cod-429_15089_biztalk-and-wcf-part-vi-publishing-advanced-services.aspx

And created my own behavior class, I’ve also included a copy of my behavior class at the end of this post because of the code is not properly “codeBlock’d” in that post.

Then, after I have the class built and put into the GAC (Global assembly cache), I set the receive location to use WCF-CustomIsolated adapter as the basichttp doesn’t allow extended behaviors to be added.

So I added my custom behavior class and started my testing client. Then I got this error message which had me scratching my head for nearly 3 hours….

Receive location for address  ‘yourWCFservice.svc’ not found. (BizTalk receive location may be disabled)

The receive location is clearly visible in the Biztalk administration console…what the **** happened here???

Then I found out that I’ve set the adapter to be basichttp at the beginning, so it’s looking for “yourWCFservice.svc” using the WCF-customIsolated adapter, and ofcourse it won’t be able to find it since the “yourWCFservice.svc” recerive port is using WCF-basicHttp.

Not knowing a better way to change it…I simply republished my WCF webservice and my behavior class started to work fine after that :D!!

WcfServiceBehaviors.cs

using System;

using System.Collections.Generic;

using System.Text;

using System.ServiceModel;

using System.ServiceModel.Channels;

using System.ServiceModel.Description;

using System.ServiceModel.Configuration;

using System.IdentityModel.Policy;

using System.IdentityModel.Claims;

using System.Security.Principal;
using System.Configuration;

namespace WcfServiceBehaviors
{

public class MyCustomServiceAuthorizationManager : ServiceAuthorizationManager
{
private string m_windowsgroup;

public MyCustomServiceAuthorizationManager(string windowsgroup)
{
this.m_windowsgroup = windowsgroup;
}

protected override bool CheckAccessCore(OperationContext operationContext)
{

if (!base.CheckAccessCore(operationContext))
{

return false;

}

AuthorizationContext authCtx = operationContext.ServiceSecurityContext.AuthorizationContext;

//print out inbound identities recorded by WCF
System.Diagnostics.Trace.WriteLine(“Primary Identity is ” +
operationContext.ServiceSecurityContext.PrimaryIdentity.Name);
System.Diagnostics.Trace.WriteLine(“Windows Identity is ” +
operationContext.ServiceSecurityContext.WindowsIdentity.Name);
//create Windows principal object from inbound Windows identity
WindowsPrincipal p = new WindowsPrincipal(operationContext.ServiceSecurityContext.WindowsIdentity);
//check user in role
//System.Diagnostics.Trace.WriteLine(“Windows Group is ” + this.m_windowsgroup);

bool isAdmin = p.IsInRole(this.m_windowsgroup);
if (!isAdmin)
{
//System.Diagnostics.Trace.WriteLine(“Windows user ” + operationContext.ServiceSecurityContext.WindowsIdentity.Name + ” not in group ” + this.m_windowsgroup + ” so denying access.”);
return false;
}
return true;

}

}

public class MyCustomBehaviorElement : BehaviorExtensionElement
{
///
/// Want custom config property to show up in the BizTalk receive location
///
[ConfigurationProperty(“windowsgroup”, IsRequired = false, DefaultValue = “”)]
public string WindowsGroup
{
get { return (string)base[“windowsgroup”]; }
set { base[“windowsgroup”] = value; }
}

protected override object CreateBehavior()
{

return new MyCustomServiceBehavior(WindowsGroup);

}

public override Type BehaviorType
{

get { return typeof(MyCustomServiceBehavior); }

}

}

public class MyCustomServiceBehavior : IServiceBehavior
{
private string m_windowsgroup;

public MyCustomServiceBehavior(string windowsgroup) { this.m_windowsgroup = windowsgroup; }

#region IServiceBehavior Members

public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{

}

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{

ServiceAuthorizationBehavior authBehavior = serviceDescription.Behaviors.Find<ServiceAuthorizationBehavior>();

authBehavior.ServiceAuthorizationManager = new MyCustomServiceAuthorizationManager(this.m_windowsgroup);

((IServiceBehavior)authBehavior).ApplyDispatchBehavior(serviceDescription, serviceHostBase);

}

public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{

}

#endregion

}

}