C#Webservice错误:邮件安全验证失败

时间:2013-08-16 12:12:08

标签: wcf c#-4.0

我正在尝试使用自定义绑定使用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响应头。​​

1 个答案:

答案 0 :(得分:1)

服务器在响应中返回x.509令牌,而WCF不确定如何处理它(在用户名auth中不需要此令牌)。我看到两个选择:

    编码器中的
  1. 从响应中删除安全标记

    或者

  2. 根本不使用安全性和编码器(如果您愿意,可以使用消息检查器)将用户/传递标头推送到请求

  3. 编辑:你说这个令牌应该由客户端在进一步的调用中使用。我不确定处理这个问题的正确方法是什么,所以我会给出一个快速的方法(但感觉有些不完整)。根本不要定义任何安全性(从绑定中删除安全元素)。然后使用自定义消息检查器(或编码器,但更难)以正确的格式推送用户/传递消息(请参阅使用安全绑定时如何发送它们)。这应该不难。那么WCF将不会在响应时验证令牌。您可以使用已有的相同消息检查器来检查响应并提取令牌。您的主类(初始化代理)也是初始化检查器的类,因此它应该有权访问其数据成员以访问令牌并重新发送它。

    如果服务器会在主体内部而不是标头中发送令牌,那将会更加容易。 通过实现自定义令牌/行为,可能还有一种方法可以在非零散的方式中完成它,但在我看来,这会增加更多的抽象,最好是具体的。