I have a WCF client connecting to a Java based Axis2 web service (outside my control). It is about to have WS-Security applied to it, and I need to fix the .NET client. However, I am struggling to provide the correct authentication. I am aware that WSE 3.0 might make it easier, but I would prefer not to revert to an obsolete technology.

Similar issues (unsolved), include thisthis and this.

The SOAP message should look like this:

<wsse:UsernameToken>
<wsse:Username><!-- Removed--></wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"><!-- Removed--></wsse:Password>
<wsse:Nonce><!-- Removed--></wsse:Nonce>
<wssu:Created>2010-05-28T12:50:33.675+01:00</wssu:Created>
</wsse:UsernameToken>

However, mine looks like this:

<s:Header>
<h:Security xmlns:h="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"></h:Security>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="_0">
<u:Created>2010-06-23T10:31:23.441Z</u:Created>
<u:Expires>2010-06-23T10:36:23.441Z</u:Expires>
</u:Timestamp>
<o:UsernameToken u:Id="uuid-d329b3b2-6a1f-4882-aea6-ec6b8a492de7-1">
<o:Username>
<!-- Removed-->
</o:Username>
<o:Password>
<!-- Removed-->
</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>

My client looks like this: P.S. Note the required SecurityHeaderType param. What is that?

public MyAck SendRequest(MyRequest request)
{
RemoteServicePortTypeClient client = new RemoteServicePortTypeClient(); client.ClientCredentials.UserName.UserName = "JAY";
client.ClientCredentials.UserName.Password = "AND"; // what is the difference between the two different Credential types??
//client.ClientCredentials.HttpDigest.ClientCredential.UserName = "SILENT";
//client.ClientCredentials.HttpDigest.ClientCredential.Password = "BOB"; SecurityHeaderType sht = new SecurityHeaderType();
//sht.Any = ???; // How do I use this???
//sht.AnyAttr = ???; // How do I use this ??? // SecurityHeaderType is a required parameter
return client.RemoteServiceOperation_Provider(sht, request);
}

Current binding is as follows:

<basicHttpBinding>
<binding name="CustomBinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None"></transport>
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>

I've also tried a custom binding and got a similar error:

<customBinding>
<binding name="myCustomBindingConfig">
<security authenticationMode="UserNameOverTransport"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11"
securityHeaderLayout="Strict"
includeTimestamp="false"></security>
<textMessageEncoding messageVersion="Soap11"></textMessageEncoding>
<httpsTransport />
</binding>
</customBinding>

And endpoint (Address obviously changed...):

<endpoint address="https://www.somecompany.com/uat/axis/services/RemoteServiceOperation_Provider"
binding="basicHttpBinding" bindingConfiguration="CustomBinding"
contract="RemoteService.RemoteServicePortType"
name="RemoteService_UAT" />

The custom fault that is being returned is as follows:

<ErrorID>0</ErrorID>
<ErrorType>UNEXPECTED</ErrorType>
<ErrorDescription><![CDATA[Array index out of range: 0]]></ErrorDescription>
<TimeStamp>2010-06-23T13:28:54Z</TimeStamp>

I've read lots about custom headers, tokens, bindings and my brain is completely confused. Can anyone suggest a step by step process for sending the message in the right format?

This appears to be the way forward for WCF, using custom tokens, but how should one apply the digest and nonce as required?

Any help welcomed.

UPDATE

I've had some limited success. I've used the Microsoft.Web.Services3 library to create a UsernameToken with the correct digest. I've then created my own custom behavior and in the BeforeSendRequest method I've done the following to inject the header:

object IClientMessageInspector.BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
UsernameToken ut = new UsernameToken("USERNAME", "PASSWORD", PasswordOption.SendHashed); XmlElement securityElement = ut.GetXml(new XmlDocument()); MessageHeader myHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", securityElement, false);
request.Headers.Add(myHeader); return Convert.DBNull;
}

I add the behavior like so:

CustomBehavior behavior = new CustomBehavior("USERNAME", "PASSWORD");
client.Endpoint.Behaviors.Add(behavior);

I can now see the headers going across:

<s:Header>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="SecurityToken-c6aeb72d-4d36-4650-abd3-33cc66caac6d" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>
<!-- Removed-->
</wsse:Username>
<wsse:Password>
<!-- Removed-->
</wsse:Password>
<wsse:Nonce>
<!-- Removed-->
</wsse:Nonce>
<wsu:Created>2010-06-24T16:23:58Z</wsu:Created>
</wsse:UsernameToken>
</Security>
</s:Header>

But I'm getting the error:

<soapenv:Fault>
<faultcode xmlns="">soapenv:Server</faultcode>
<faultstring xmlns="">WSDoAllReceiver: security processing failed; nested exception is:
org.apache.ws.security.WSSecurityException: General security error (WSSecurityEngine: Callback supplied no password for: USERNAME)</faultstring>
<faultactor xmlns="">urn:Remote_Provider</faultactor>
<detail xmlns="">
<CUSTOMError xmlns="urn:customerror:v01">
<ErrorID>0</ErrorID>
<ErrorType>UNEXPECTED</ErrorType>
<ErrorDescription><![CDATA[WSDoAllReceiver: security processing failed; nested exception is:
org.apache.ws.security.WSSecurityException: General security error (WSSecurityEngine: Callback supplied no password for: USERNAME)]]></ErrorDescription>
<TimeStamp>2010-06-24T17:23:59Z</TimeStamp>
</CUSTOMError>
</detail>
</soapenv:Fault>

There appears to be a missing Type attribute on the password node:

Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"

However, I'm not sure if the security tracing and logging settings are blanket removing the attributes and content of those nodes. I've attempted to use the logKnownPii setting in the diagnostics logging, but the security information remains obscured. Any ideas on that one?

asked Jun 23 '10 at 14:47
Junto

7,57975393
 

3 Answers

I can confirm that the UPDATE from my question actually works:

object IClientMessageInspector.BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
UsernameToken ut = new UsernameToken("USERNAME", "PASSWORD", PasswordOption.SendHashed); XmlElement securityElement = ut.GetXml(new XmlDocument()); MessageHeader myHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", securityElement, false);
request.Headers.Add(myHeader); return Convert.DBNull;
}

And the client:

CustomBehavior behavior = new CustomBehavior("USERNAME", "PASSWORD");
client.Endpoint.Behaviors.Add(behavior);

The error message was unrelated. The security header works with a very simple basicHttpBinding:

<basicHttpBinding>
<binding name="BasicSOAPBinding">
<security mode="Transport" />
</binding>
</basicHttpBinding>

Code sample of this in action can be found on my blog: http://benpowell.org/supporting-the-ws-i-basic-profile-password-digest-in-a-wcf-client-proxy/

answered Jul 15 '10 at 16:35
Junto

7,57975393
 

This question is well written -- many thanks. In reference to @Junto's "How do I use this" comment, it turns out that the SecurityHeader param on the service method can be used to add the header. I've included an example below. I believe that what's happening is that the SvcUtil.exe tool is barfing when trying to read the WS* DTDs. This is not obvious when you use the "Add Service Reference" wizard. But it is very obvious when you run svcutil.exe from the command line. Because svcutil.exe fails to read the WS* DTD's, the SecurityHeader object is not well developed. But Microsoft gives you an out with the .Any property. You can serialize the UsernameToken class right into the .Any property and your header will be added to the message. Again, thanks for this excellent question.

How to use the SecurityHeader parameter to add a UsernameToken security header:

Required tools:

Fiddler2 (or similar) -- you really can't figure any of this out without inspecting the http headers.

Required Reference:

Microsoft.Web.Services3.dll -- you can reference this 2.0 framework assembly from your 4.0 assembly

WCF service call:

// Initialization of the service...
_service = new MyService("MyEndpoint", RemoteUri); // etc. // Calling the service -- note call to GetSecurityHeader()
_service.ServiceAction(GetSecurityHeader(), "myParam1"); // etc. /// <summary>
/// Construct the WSE 3.0 Security Header
/// </summary>
private SecurityHeader GetSecurityHeader()
{
SecurityHeader h = new SecurityHeader();
UsernameToken t = new UsernameToken(RemoteLogin, RemotePassword, PasswordOption.SendPlainText);
h.Any = new XmlElement[1];
h.Any[0] = t.GetXml(new XmlDocument());
return h;
}

App.config:

  <system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MyBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:10:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="1048576" maxBufferPoolSize="524288" maxReceivedMessageSize="1048576"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://myservice.com/service.asmx"
binding="basicHttpBinding" bindingConfiguration="MyBinding" contract="MyContract"
name="MyEndpoint" />
</client>
</system.serviceModel>
answered Sep 12 '11 at 12:41
Brett

4,84921530
 
    
GetSecurityHeader() did it for me, thanks! – Robotron Apr 24 '14 at 13:44

I had a similar problem recently and gave up searching for a non-WSE solution. After a couple days of pulling my hair out I ended downloading the WSE 3.0 SDK, generating a proxy class using WseWsdl3.exe, and creating a new policy for the UsernameToken. I was up and running in 15min. The following is currently working for me.

RemoteService service = new RemoteService();  //generated class

UsernameToken token = new UsernameToken(username, password, PasswordOption.SendPlainText);
Policy policy = new Policy();
policy.Assertions.Add(new UsernameOverTransportAssertion()); service.SetClientCredential(token);
service.SetPolicy(policy); var result = service.MethodCall();
answered Jun 26 '10 at 21:26

Error in WCF client consuming Axis 2 web service with WS-Security UsernameToken PasswordDigest authentication scheme的更多相关文章

  1. 应用Apache Axis进行Web Service开发

    转自(http://tscjsj.blog.51cto.com/412451/84813) 一.概述 SOAP原意为Simple Object Access Protocol(简单对象访问协议),是一 ...

  2. Axis开发Web Service

    可以自动生成代码的 一.Axis环境的安装 1.安装环境 J2SE SDK 1.4,Tomcat 5.0,eclipse 3.2. 2.到 http://xml.apache.org 网站下载Axis ...

  3. iOS 中client和server的 Web Service 网络通信 (1)

    当你打开你手机上新浪微博应用或者知乎应用是.你是否会去想这些显示在手机上的图片和数据时从哪里来的?又是通过如何的方法实现的?好.那么接下来就介绍是如何实现的.过程又是怎么样的.      当我们浏览着 ...

  4. 使用axis开发web service服务端

    一.axis环境搭建 1.安装环境 JDK.Tomcat或Resin.eclipse等. 2.到 http://www.apache.org/dyn/closer.cgi/ws/axis/1_4下载A ...

  5. WCF、Net remoting、Web service概念及区别

    Windows通信基础(Windows Communication Foundation,WCF)是基于Windows平台下开发和部署服务的软件开发包(Software Development Kit ...

  6. Consuming a RESTful Web Service

    本篇文章将介绍使用Spring来建立RESTful的Web Service. 我们通过一个例子来说明这篇文章:这个例子将会使用Spring的RestTemplate来从Facebook的提供的API中 ...

  7. WCF、.Net Remoting、Web Service概念及区别

    此文章主要参考http://www.cnblogs.com/weiweibtm/archive/2013/06/21/3148583.html 参考书籍<WCF全面解析上册>.<WC ...

  8. iOS 中client和server的 Web Service 网络通信 (2)

    在实际的应用开发过程中,同步请求的用户体验并非非常好:我们都知道.Apple是非常重视用户体验的.这一点也成为了行业的标杆,没实用户哪里来的好产品.所以用户体验是极其重要的.貌似废话有点多.接下来进入 ...

  9. Part 17 Consuming ASP NET Web Service in AngularJS using $http

    Here is what we want to do1. Create an ASP.NET Web service. This web service retrieves the data from ...

随机推荐

  1. Python:执行精确的浮点数运算

    需要对浮点数执行精确的计算操作,并且不希望有任何小误差的出现. 浮点数的一个普遍问题是它们并不能精确的表示十进制数.并且,即使是最简单的数学运算也会产生小的误差,比如: >>> a ...

  2. DB 异常

    1. ORA-00947: Not enough values 没有足够的值  执行insert的时候出现这个错误. 例如:insert into 表1 values (?,?,?); 表1的结构有4 ...

  3. Qt的信号和槽是如何工作的

    用Qt做过开发的朋友,不知道是否曾为下面这些问题疑惑过:我们知道Qt是基于C++的,Qt写的代码最终还是要由C++编译器来编译,但是我们的Qt代码中有很多C++里没有的关键字,比如slots\sign ...

  4. 20155201 2016-2017-2 《Java程序设计》第一周学习总结

    20155201 2016-2017-2 <Java程序设计>第一周学习总结 教材学习内容总结 每一章的问题: 第一章 Java ME都有哪些成功的平台? 第二章 哪些情况可以使用impo ...

  5. #include <ntifs.h>出现PEPROCESS redefinition问题处理

    转载:http://blog.csdn.net/ytfrdfiw/article/details/23334297 如果在自己的程序中,即包含ntddk.h和ntifs.h的时候,编译的时候会出现如下 ...

  6. Anaconda ubuntu16.04 Cuda 8.0安装pytorch

    Pytorch 安装 Pytorch安装真的太让人省心了,在anaconda的环境下进行安装,只需要一个命令 具体命令请查看官网pytorch 找到适合你的版本进行安装 本机环境: anaconda3 ...

  7. SPOJ - PGCD Primes in GCD Table(莫比乌斯反演)

    http://www.spoj.com/problems/PGCD/en/ 题意: 给出a,b区间,求该区间内满足gcd(x,y)=质数的个数. 思路: 设f(n)为 gcd(x,y)=p的个数,那么 ...

  8. HDU 3572 Task Schedule(最大流判断满流)

    https://vjudge.net/problem/HDU-3572 题意: 有N个作业和M台机器,每个作业都有一个持续时间P,工作的日期为S~E.作业可以断断续续的在不同机器上做,每台机器每次只可 ...

  9. BZOJ 4012 【HNOI2015】 开店

    题目链接:开店 这道题显然一眼树分治,维护点分的结构,在每个点上,对每种年龄到这个点\(u\)以及他在点分树上父亲的距离和建一棵线段树,查询的时候一路往上跳即可. 但是我太懒了(其实你要说我不会也可以 ...

  10. python 执行字符串中的python代码

    mycode = 'print("hello world")' code = """ def mutiply(x,y): return x*y pri ...