为什么WCF会忽略我的TokenProvider?

Tom*_*m W 9 wcf biztalk azureservicebus azure-servicebus-queues

我有一个BizTalk WCF自定义接收位置,我已添加自定义行为:

public class SasTokenProviderEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
                var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(sharedAccessSecretName, sharedAccessKey);
                bindingParameters.Add(new TransportClientEndpointBehavior { TokenProvider = tokenProvider });         
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

为简洁起见,省略了参数设置代码

这是根据https://code.msdn.microsoft.com/How-to-integrate-BizTalk-07fada58#content中的示例改编的- 该作者在BizTalk社区中受到广泛尊重,此类代码已被使用好几年了.我正在做的就是调整他使用的方法,这被证明有效,可以替换不同的TokenProvider.

我可以通过调试看到此代码运行并且具有正确参数的TransportClientEndpointBehavior被添加到通道中.但是,当BizTalk接收位置轮询Service Bus时,我在事件日志中看到以下内容:

适配器"WCF-Custom"引发了错误消息.详细信息"System.UnauthorizedAccessException:40102:缺少授权令牌,资源:sb:// [namespace] .servicebus.windows.net/[queue] .TrackingId:452c2534-d3e6-400f-874f-09be324e9e11_G27,SystemTracker:[namespace]. servicebus.windows.net:[queue],时间戳:12/1/2016 11:38:56 AM ---> System.ServiceModel.FaultException:40102:缺少授权令牌,资源:sb:// [namespace] .servicebus .windows.net/[queue] .TrackingId:452c2534-d3e6-400f-874f-09be324e9e11_G27,SystemTracker:[namespace] .servicebus.windows.net:[queue],时间戳:12/1/2016 11:38:56 AM

我看不出Azure Service Bus端点会返回此错误消息的任何原因,因为没有使用令牌提供程序.为什么频道会忽略TokenProvider,我必须做什么才能正确传递令牌?

编辑:

我已经检查了有问题的端口的原始WCF消息流量以及使用SB-Messaging适配器的流量,该适配器按预期工作.区别在于SB-Messaging适配器的消息包含SOAP标头,如:

<Authorization xmlns="http://schemas.microsoft.com/servicebus/2010/08/protocol/">SharedAccessSignature sr=[really long encoded string]</Authorization>而我的自定义绑定端口的消息没有.所以问题是缺少授权SOAP标头; 但问题仍然存在 - 为什么通道不添加此标题?

编辑#2:

我已经反编译了Microsoft.ServiceBus.dll,我相信我已经找到了实际创建WCF消息的类,Microsoft.ServiceBus.Messaging.Sbmp.SbmpMessageCreator.它有这个方法:

private Message CreateWcfMessageInternal(string action, object body, bool includeToken, string parentLinkId, RetryPolicy policy, TrackingContext trackingContext, RequestInfo requestInfo)
    {
      Message message = Message.CreateMessage(this.messageVersion, action, body);
      MessageHeaders headers = message.Headers;
      headers.To = this.logicalAddress;
      string sufficientClaims = this.GetSufficientClaims();
      if (this.linkInfo != null)
      {
        if (!string.IsNullOrEmpty(this.linkInfo.TransferDestinationEntityAddress))
        {
          SecurityToken authorizationToken = this.GetAuthorizationToken(this.linkInfo.TransferDestinationEntityAddress, sufficientClaims);
          if (authorizationToken != null)
          {
            SimpleWebSecurityToken webSecurityToken = (SimpleWebSecurityToken) authorizationToken;
            if (webSecurityToken != null)
              this.linkInfo.TransferDestinationAuthorizationToken = webSecurityToken.Token;
          }
        }
        this.linkInfo.AddTo(headers);
      }
      if (includeToken)
      {
        ServiceBusAuthorizationHeader authorizationHeader = this.GetAuthorizationHeader(sufficientClaims);
        if (authorizationHeader != null)
          headers.Add((MessageHeader) authorizationHeader);
      }
      if (this.messagingFactory.FaultInjectionInfo != null)
        this.messagingFactory.FaultInjectionInfo.AddToHeader(message);
      if (!string.IsNullOrWhiteSpace(parentLinkId))
        message.Properties["ParentLinkId"] = (object) parentLinkId;
      if (trackingContext != null)
        TrackingIdHeader.TryAddOrUpdate(headers, trackingContext.TrackingId);
      MessageExtensionMethods.AddHeaderIfNotNull<RequestInfo>(message, "RequestInfo", "http://schemas.microsoft.com/netservices/2011/06/servicebus", requestInfo);
      return message;
    }
Run Code Online (Sandbox Code Playgroud)

因此,从逻辑上考虑它,有两个原因会丢失Authorization标头:

  • includeToken 是假的(为什么会这样?)
  • GetAuthorizationHeader() 返回null(为什么?)

编辑#3:

我编译并运行示例代码,这是有效的.我的代码和他的代码之间的唯一重要区别是我的代码包含一个调用Azure Key Vault的行:

var kv = new KeyVaultClient(this.GetAccessToken);
var key = kv.GetSecretAsync(this.KeyVaultUri.AbsoluteUri, this.SharedAccessSecretName).Result;
var sharedAccessKey = key.Value;
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
            this.SharedAccessSecretName, 
            sharedAccessKey);
bindingParameters.Add(new TransportClientEndpointBehavior { TokenProvider = tokenProvider });
Run Code Online (Sandbox Code Playgroud)

这是一个返回Task的异步方法.是否阻止对此任务的结果以某种方式不能在某些情况下执行预期,这会以某种方式搞乱WCF通道的配置?正如我所说的,我确信这段代码会运行并分配TokenProvider.我现在只是不确定它何时运行.

Tom*_*m W 2

天啊!

我没有意识到,我们在与(同样旧的)本地版本的服务总线(Windows Server 的服务总线)进行互操作的解决方案中仍然保留了非常旧的 Microsoft.ServiceBus.dll 版本,这就是我的项目所引用的版本。不管出于什么原因,这个版本只是没有做它应该做的事情,并且没有给出任何迹象表明它绕过了预期的行为。更新到服务总线的最新 NuGet 包可以修复该问题。