我正在尝试使用自定义绑定使用UsernameToken传递SOAP标头的认证Web服务
ICollection<BindingElement> bindingElements = new List<BindingElement>();
HttpsTransportBindingElement httpBindingElement = new HttpsTransportBindingElement();
CustomTextMessageBindingElement textBindingElement = new CustomTextMessageBindingElement();
SecurityBindingElement securityElement = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
securityElement.IncludeTimestamp = false;
bindingElements.Add(securityElement);
bindingElements.Add(textBindingElement);
bindingElements.Add(httpBindingElement);
CustomBinding binding = new CustomBinding(bindingElements);
EndpointAddress address = new EndpointAddress("https://....");
var client = new WebServiceClient(binding, address);
client.ClientCredentials.UserName.UserName = "USERNAME HERE";
client.ClientCredentials.UserName.Password = "PASSWORD HERE";
using (new OperationContextScope(client.InnerChannel))
{
var req = new WebServiceRequest();
var resp = client.initiate(req);
}
获得例外:
邮件安全验证失败。
无法从'BinarySecurityToken'元素中读取令牌 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' BinarySecretSecurityToken的命名空间,带有'oblix:ObSSOCookie' 值类型。如果预期此元素有效,请确保该元素 安全性配置为使用名称,名称空间和名称来使用令牌 指定的值类型。“}
服务器堆栈跟踪:
at System.ServiceModel.Security.TransportSecurityProtocol.VerifyIncomingMessage(Message&amp; 消息,TimeSpan超时)at System.ServiceModel.Security.SecurityProtocol.VerifyIncomingMessage(消息&安培; 消息,TimeSpan超时,SecurityProtocolCorrelationState [] correlationStates)at System.ServiceModel.Channels.SecurityChannelFactory
1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout) at System.ServiceModel.Channels.SecurityChannelFactory
1.SecurityRequestChannel.Request(消息 消息,TimeSpan超时)at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(消息 消息,TimeSpan超时)at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway,ProxyOperationRuntime操作,Object [] ins, 对象[]出局,TimeSpan超时)at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall,ProxyOperationRuntime operation)at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(即时聊天 消息)
这是fiddler抓住的回应:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="oblix:ObSSOCookie" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:oblix="http://schemas.oblix.com/ws/2004/04/authentication"><!--REMOVED--></wsse:BinarySecurityToken>
</wsse:Security>
</env:Header>
<env:Body>
<MobileAppsLoginSSOProcessResponse xmlns="http://xmlns.oracle.com/MobileAppsLoginSSO">
<ReturnStatus>SUCCESS</ReturnStatus>
</MobileAppsLoginSSOProcessResponse>
</env:Body>
</env:Envelope>
我在http://msdn.microsoft.com/en-us/library/ms751486%28v=vs.100%29.aspx
之后使用CustomTextMessageEncoder修改
正如Yaron所建议的那样,除非我从响应中删除了BinarySecurityToken标记,否则代码将失败并出现上述Message Security Validation Failed异常。
响应中的'oblix:ObSSOCookie'是服务在成功验证后发送回客户端的身份验证cookie,我相信,客户端需要保存此cookie。
解决方案:
正如Yaron在最终编辑中所建议的那样,我从自定义绑定中删除了SecurityElementBinding
并使用自定义消息检查器(IClientMessageInspector
)将安全标记注入标题。
这允许仅从SOAP主体解释响应,我可以在AfterReceiveReply
实现的IClientMessageInspector
中读取SOAP响应头。
答案 0 :(得分:1)
服务器在响应中返回x.509令牌,而WCF不确定如何处理它(在用户名auth中不需要此令牌)。我看到两个选择:
从响应中删除安全标记
或者
根本不使用安全性和编码器(如果您愿意,可以使用消息检查器)将用户/传递标头推送到请求
编辑:你说这个令牌应该由客户端在进一步的调用中使用。我不确定处理这个问题的正确方法是什么,所以我会给出一个快速的方法(但感觉有些不完整)。根本不要定义任何安全性(从绑定中删除安全元素)。然后使用自定义消息检查器(或编码器,但更难)以正确的格式推送用户/传递消息(请参阅使用安全绑定时如何发送它们)。这应该不难。那么WCF将不会在响应时验证令牌。您可以使用已有的相同消息检查器来检查响应并提取令牌。您的主类(初始化代理)也是初始化检查器的类,因此它应该有权访问其数据成员以访问令牌并重新发送它。
如果服务器会在主体内部而不是标头中发送令牌,那将会更加容易。 通过实现自定义令牌/行为,可能还有一种方法可以在非零散的方式中完成它,但在我看来,这会增加更多的抽象,最好是具体的。