Paolo's Notes

BA by day, sleepy coder by night...

WS POLICY SI TEH WIN!!111

In the comments on my previous post, John Bristowe gently offered his help to guide me across the Dead^H^H^H^H WSE 2.0 Marshes...

Fool! He didn't know what was expecting him! But in the end, he provided me with invaluable knowledge, tips and simply buckets of code big enough to drive into my thick skull a faint glimmer of comprehension about this whole new way to deal with web services.

So, what was my initial take, based on a cursory reading of the few web pages I was able to find? A procedural based, hardcoded approach to the authentication/signature/authorization/encryption problem. Plenty of code (to be tested) and lots of possible failure points. Plus, it wasn't really working anyways...

So John introduced me to the marvels of Policies. A declarative approach, how novel! Basically this removed all the ugly plumbing code from my web methods and put all the business knowledge about, say, authorization into a series of XML files that can be edited at runtime.

So, what about some samples? Sure thing! After having enabled WSE 2.0 on both Nfftiws (the web service) and Test Harness (the, duh, test harness), I modified Test Harness' app.config file thusly (sorry, I always wanted to use this word...):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="microsoft.web.services" type="Microsoft.Web.Services.Configuration.WebServicesConfiguration, Microsoft.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </configSections>
  <microsoft.web.services>
    <policy>
      <send>
        <cache name="policyCache.xml" />
      </send>
    </policy>
  </microsoft.web.services>
</configuration>

The section "microsoft.web.services" enables WSE 2.0 for this project and the element named the same way defines a send policy to be defined in the policyCache.xml file. That, by the way, is filled by these characters:

<?xml version="1.0" encoding="utf-8"?>
<policyDocument xmlns="
http://schemas.microsoft.com/wse/2003/06/Policy">
  <mappings xmlns:wse="
http://schemas.microsoft.com/wse/2003/06/Policy">
    <mapDefault policy="#policy-b298142f-0c50-446b-8938-079b27891512" />
  </mappings>
  <policies xmlns:wsu="
http://schemas.xmlsoap.org/ws/2002/07/utility">
    <wsp:Policy wsu:Id="policy-b298142f-0c50-446b-8938-079b27891512" xmlns:wsp="
http://schemas.xmlsoap.org/ws/2002/12/policy">
      <wsse:Integrity wsp:Usage="wsp:Required" xmlns:wsse="
http://schemas.xmlsoap.org/ws/2002/12/secext">
        <wsse:TokenInfo>
          <SecurityToken xmlns="
http://schemas.xmlsoap.org/ws/2002/12/secext">
            <wsse:TokenType>wsse:UsernameToken</wsse:TokenType>
          </SecurityToken>
        </wsse:TokenInfo>
        <wsse:MessageParts Dialect="
http://schemas.xmlsoap.org/2002/12/wsse#part">wsp:Body()</wsse:MessageParts>
      </wsse:Integrity>
    </wsp:Policy>
  </policies>
</policyDocument>

Pretty ugly, eh? Luckily this file was generated automatically by the same property dialog where you enable WSE 2.0, by going to the Policy tab and clicking on the Create/Edit... button in the Sending Side Policy Cache group. When the Wse Security Policy Editor dialog pops up, click on Add Policy, select "default" as the Service Location, select the Require Signature checkbox, enter UserNameToken as the token Type, leave all the other fields untouched and click Ok. The file policyCache will be created and dropped in the wrong place. You will have to manually copy it from the project top folder to bin/debug for the purpose of development. We'll see in later posts how to deal with deployment.

Ok, what have we achieved? Now we have a client application that knows how to speak WSE and will make sure to authenticate its method calls to the target web service.

Now we have to configure the web service... Again, enable WSE 2.0 for this project. Then modify web.config like this:

just after <configuration>, before <system.web>, add:

  <configSections>
    <section name="microsoft.web.services" type="Microsoft.Web.Services.Configuration.WebServicesConfiguration, Microsoft.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </configSections>

Just before </system.web> add:

    <webServices>
      <soapExtensionTypes>
        <add type="Microsoft.Web.Services.WebServicesExtension, Microsoft.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0" />
      </soapExtensionTypes>
    </webServices>

Finally, after </system.web>, add:

  <microsoft.web.services>
    <security>
      <securityTokenManager type="Nfftiws.SecurityPassword, Nfftiws" xmlns:wsse="
http://schemas.xmlsoap.org/ws/2002/12/secext" qname="wsse:UsernameToken" />
    </security>
    <policy>
      <receive>
        <cache name="path to the project folder\NFFTIWS\bin\inboundPolicy.xml" />
      </receive>
    </policy>
  </microsoft.web.services>

While the first two pieces of XML are basically boilerplate (I already feel the wrath of the More Competent Developers(tm) out there), the last fragment defines the method that implements the authentication (Nfftiws.SecurityPassword) and points to the file defining the authorization policy that will be applied on the incoming messages. But that's all for web.config, in the next post we'll see what's in inboundPolicy.xml.

Comments

No Comments