Declan
Declan

Reputation: 1860

Creating a WCF Service utilizing WSSE Security (PasswordDigest)

I need to create a secure WCF Web-service which conforms to the Oasis 2004 standard(http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd)

I have been given example requests, which will be sent to me by a 3rd party. The body of the request is not important, but i will show the header here (some of the data has been changed to protect identities):

<soapenv:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                   xmlns:wssu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsse:UsernameToken>
            <wsse:Username>username</wsse:Username>
            <wsse:Password
                    Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">
                weYI3nXd8LjMNVksCKFV8t3rgHh3Rw==
            </wsse:Password>                
            <wsse:Nonce>WScqanjCEAC4mQoBE07sAQ==</wsse:Nonce>
            <wssu:Created>2013-04-16T01:24:32Z</wssu:Created>
        </wsse:UsernameToken>
    </wsse:Security>
    <urn:ESBMetaData>
        <urn:OriginalServiceCallerID>SuchAndSuch</urn:OriginalServiceCallerID>
    </urn:ESBMetaData>
    <urn1:ESBContext soapenv:mustUnderstand="1">
        <urn1:BusinessContextType>SuchandSuchSomething</urn1:BusinessContextType>
        <urn1:BusinessContextInstanceId>uuid:7dc56353-9069-442d-8b69-163f676dd3e3</urn1:BusinessContextInstanceId>
        <urn1:ServiceRequestId>uuid:7dc56353-9069-442d-8b69-163f676dd3e3</urn1:ServiceRequestId>
    </urn1:ESBContext>
</soapenv:Header>

As can be seen from the Header, the security is utilizing a Password-Digest and a Nonce. I need to be able to authenticate the users with these details in a WCF Service. (the security cannot be changed, as the 3rd party's system is used by many others)

So far i have setup a simple WCF Service with Data-contracts, Operation-contracts and a Service-contract. I have used a wsHttpBinding with a custom MembershipProvider. See relevant parts of WCF service Web.config below:

<system.web>
<compilation debug="true" targetFramework="4.0"/>
<httpRuntime/>
<membership>
  <providers>
    <add name="CustomMembershipProvider" type="SupplierEngagementWCFService.Providers.CustomMembershipProvider" />
  </providers>
</membership>
</system.web>

<system.serviceModel>
<bindings>
  <wsHttpBinding>
    <binding name = "UserNameWS">
      <security mode = "Message">
        <message clientCredentialType = "UserName"/>
      </security>
    </binding>
  </wsHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="false"/>
<services>
  <service name="SupplierEngagementWCFService.SupplierEngagementService" behaviorConfiguration="Internet">
    <endpoint address="" binding="wsHttpBinding" bindingName="UserNameWS" contract="SupplierEngagementWCFService.ISupplierEngagementService"/>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="Internet">
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="CustomMembershipProvider"/>
        </serviceCredentials>
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>
</behaviors>
  </system.serviceModel>

Here is my implementation of a membership provider:

public class CustomMembershipProvider : MembershipProvider 
{
     public override bool ValidateUser(string username, string password)
     {
        throw new NotImplementedException();
     }
}

As you can see it does not provide me with require arguments to check that the password digest is valid. I would need from the header Password-Digest, Nonce, Created date and UserName. So that i may generate a password digest of my own(using the following algorithm) to check that the one sent was generated with the correct password.

Password digest algorithm(pseudo code):

var passwordDigestToCompare = Base64(Sha1(nonce + created + KnownPassword));

if(passwordDigestFromWebServiceCall == passwordDigestToCompare )
{
    // digest is valid
}

Creating a custom membership provider does not give me the functionality i require to work with password-digest security.

What should i be doing differently, and what is best practice for implementing WSSE password digest security in a WCF Service?

Upvotes: 3

Views: 1559

Answers (0)

Related Questions