为什么WCF会忽略我的TokenProvider?

时间:2016-12-01 11:41:43

标签: wcf biztalk azureservicebus azure-servicebus-queues

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

public class SasTokenProviderEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
                var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(sharedAccessSecretName, sharedAccessKey);
                bindingParameters.Add(new TransportClientEndpointBehavior { TokenProvider = tokenProvider });         
        }
    }
}
为简洁省略了

参数设置代码

这是根据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],Timestamp: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;
    }

因此从逻辑上考虑,有两个原因会导致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 });

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

1 个答案:

答案 0 :(得分:2)

<强> D'OH!

我忽略了,我们仍然在解决方案中使用的旧版本的Microsoft.ServiceBus.dll与(同样旧的)本地版本的Service Bus(Windows Server的Service Bus)互操作是引用的版本通过我的项目。无论出于何种原因,这个版本都没有做到它应该做的事情,也没有任何迹象表明它绕过了预期的行为。更新以获得Service Bus的当前NuGet包可以解决问题。