Archive

Archive for October, 2009

Switch from WCF-BasicHttp to WCF-WSHttp in BizTalk?

October 30, 2009 8 comments

I learned a new trick that I know someone out there will appreciate…

First, here’s a little background. Some time ago, when I hosted my first BizTalk service with WCF, I ran the BizTalk WCF Service Publishing Wizard and was prompted for an adapter name.  I chose WCF-BasicHttp, assuming that I could easily change this later (as most of you out there, it’s nice to start with no security, get things working, and then progress to enable more complicated security schemes).
BizTalk WCF Publishing Wizard

And for those that I haven’t done this before: After finishing the wizard, the next steps involve verifying/fixed the IIS app pool settings and enabling the receive location.  After that, you should be able to browse the service.  Something like this should appear:

Browse WCF Service

If you click on the link to browse the WSDL, you’d find that there is no advanced policy configuration.

Great, we’ve got our basic http service up.  At some point, you might want something a little more secure, and this was my initial frustration.  I opened up the BizTalk Admin Console, found the receive location hosting the service, and switched from WCF-BasicHttp to WCF-WSHttp.  As part of this, in my case, I added the URI, specified a Security mode of Transport, and a Transport client credential type of Basic.

WCF-WSHttp Receive Location

I accepted the changes, made sure the receive location was enabled, and tried browsing my service again.

Error Browsing the WSHttp Service

But, as you can see, it didn’t work.  At the time, not knowing how to fix this, I re-ran the wizard, chose WSHttp, etc.  That made the WSHttp service browsable, but I was frustrated that I had to re-run the wizard, and I happened to have chosen a slightly different naming for the operation, which caused additional headache and rework, etc.

That’s why I’m writing this post.  There’s a better way.  Let’s go back in time… instead of re-running the wizard and choosing the WSHttp adapter (or Custom-Isolated), I could have simply changed the .svc file, i.e. C:\Inetpub\wwwroot\HelloWorldService\HelloWorld.svc.  The file originally had this inside it:

<%@ ServiceHost Language=”c#” Factory=”Microsoft.BizTalk.Adapter.Wcf.Runtime.BasicHttpWebServiceHostFactory, Microsoft.BizTalk.Adapter.Wcf.Runtime, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ %>

I changed the HelloWorld.svc ever so slightly to read:

<%@ ServiceHost Language=”c#” Factory=”Microsoft.BizTalk.Adapter.Wcf.Runtime.WSHttpWebServiceHostFactory, Microsoft.BizTalk.Adapter.Wcf.Runtime, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ %>

I saved the file, and… (drum roll please)

WSHttp WSDL

It works!  Here I’m showing the WSHttp WSDL.  You’ll notice that you see the corresponding policy information in the file.

So, in conclusion, yes you can start with one WCF adapter type and switch it later by 1) updating the receive location in the Admin Console, and 2) updating the .svc file.  For reference here are factory values for the .svc file that the wizard allows you to pick from:

BasicHttp: Microsoft.BizTalk.Adapter.Wcf.Runtime.BasicHttpWebServiceHostFactory

WSHttp: Microsoft.BizTalk.Adapter.Wcf.Runtime.WSHttpWebServiceHostFactory

Custom-Isolated: Microsoft.BizTalk.Adapter.Wcf.Runtime.CustomWebServiceHostFactory

Good luck!

Advertisements
Categories: BizTalk Server

BizTalk R2 Authorization using WCF

October 6, 2009 4 comments

As some of you may have noticed, I gave a rather scathing review of how WCF implements authorization (and hence how R2 implements authorization for WCF services).  To see that post, click here.  Although I’m still very disappointed, I’d like to share an approach that accomplishes the goal I had in mind: being able to dynamically specify, via means of configuration, the users that should have access rights to the service.  This approach was built by Vijay Naidu, a colleague of mine.

Vijay read my first blog, and took the time to “code” authorization into his web service.  With a little tuning, the solution you’re about to see resulted, which I think is much better than the out-of-the-box solution.  This solution leverages the SSO database to store the authorized users (the code example you’ll see in this post is written to authorize a single user, but hopefully you wouldn’t have trouble using a delimited list of users).  In addition, Vijay’s solution creates a shared component that can be leveraged by multiple projects without recoding the initial setup.  When mixed with Richard Seroter’s SSO storage tool (I use the variant by Paul Petrov), you’ll find that you can set up authorization dynamically.  Hence, I figured you might be interested.  Here were the steps involved:

First, the machine.config file was modified adding this entry:

<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name=”AcmeWCFCustomAuth” type=”Acme.WcfServiceBehaviors.CustomBehaviorElement, Acme.WcfServiceBehaviors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=02ae73d8d306f338″ />
</behaviorExtensions>
</extensions>
</system.serviceModel>

Secondly, this code was written and added to an assembly (the one mentioned above in the machine.config file).

if (context.PrimaryIdentity.IsAuthenticated)
{
userName = context.PrimaryIdentity.Name;
//Get the application name for parsing the Endpoint Uri Absolutepath (ex: /Acme.GlobalSafety.EnsureSafety/ImportantAuth.svc)
ApplicationName = operationContext.EndpointDispatcher.EndpointAddress.Uri.AbsolutePath.ToString();
WcfUriAbsolutePath = ApplicationName.Split(‘/’);
ApplicationName = WcfUriAbsolutePath[1].ToString();(ex: Acme.GlobalSafety.EnsureSafety)
//Get the SSO Config entry for the user to authenticate (ex: domain\LoginUser).  This call refers to the SSO tool mentioned earlier
wcfAuthUserName = Acme.SSO.Utility.SSOConfigHelper.Read(ApplicationName, “WCFClientAuthUserName”);
if (string.Compare(userName.ToUpper(), wcfAuthUserName.ToUpper()) != 0)
return false; //this returns an access denied error
}

This assembly was then compiled, installed in the GAC, and the BizTalk host was restarted. Next, using the BizTalk Administrator, a Request/Response WCF-Custom receive location was created.  Under the Service Behavior tab the AcmeWCFCustomAuth binding was added.

Next, the WCFClientAuthUserName property was added to the SSO Config database (using the tool mentioned earlier).

That’s it.  It may have seem like a bunch of work (and I admit that I don’t want developers redoing this entire thing), which is the beauty of this solution.  Subsequent applications that want to leverage this solution only need to repeat the steps in the last two paragraphs, which isn’t bad.  The other advantage of this approach, as opposed to putting the username in some configuration file out on disk, is that the SSO databases are part of the BizTalk daily backup job.  In the event of a disaster, they will be recovered, along with all of your beautiful authorization configurations.  🙂

Categories: BizTalk Server