使用自定义ClientCredentials的WCF身份validation:要使用的clientCredentialType是什么?

我不得不放弃基本的WCF UserName / Pwd安全性并实现我自己的自定义客户端凭据,以保留超出默认提供的更多信息。

我参与了这篇MSDN文章 ,但我遗漏了一些东西,因为它不起作用。

首先,我有一些自定义ClientCredentials,它们提供自定义ClientCredentialsSecurityTokenManager:

public class CentralAuthCredentials : ClientCredentials { public override System.IdentityModel.Selectors.SecurityTokenManager CreateSecurityTokenManager() { return new CentralAuthTokenManager(this); } } public class CentralAuthTokenManager : ClientCredentialsSecurityTokenManager { private CentralAuthCredentials credentials; public CentralAuthTokenManager(CentralAuthCredentials creds) : base(creds) { this.credentials = creds; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE) return new CentralAuthTokenProvider(credentials.UserId, credentials.UserPassword, credentials.ImpersonateId, credentials.LoginType); else return base.CreateSecurityTokenProvider(tokenRequirement); } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { outOfBandTokenResolver = null; if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE) return new CentralAuthTokenAuthenticator(); else return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { return new CentralAuthTokenSerializer(); } } 

现在,当我运行应用程序时,我的自定义凭据和令牌管理器就会被创建。 但是,在方法中:

 CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { ... } 

tokenRequirement.TokenType与我的自定义令牌不同。 这提出了我的第一个问题 :WCF如何知道令牌要求是什么?

另外,方法:

 public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { return new CentralAuthTokenSerializer(); } 

是否由客户端调用一次,但返回的令牌序列化程序中的所有方法都不会被调用。 这向我表明自定义令牌永远不会通过网络发送。 我假设这是因为对CreateSecurityTokenProvider()的调用从未返回我的自定义令牌提供程序,因为从未传递SecurityTokenRequirement指示我需要自定义令牌。

在客户端,我有:

 public class CentralAuthorizationManagerClient : ClientBase, ICentralAuthorizationManager, IDisposable { public PFPrincipal GenerateToken() { if (!this.ChannelFactory.Endpoint.Behaviors.Contains(typeof(CentralAuthCredentials))) throw new ArgumentException("Must set CentralAuthCredentials before calling this method."); return base.Channel.GenerateToken(); } public PFPrincipal GenerateToken(CentralAuthToken token) { this.ChannelFactory.Endpoint.Behaviors.Remove(); this.ChannelFactory.Endpoint.Behaviors.Add(new CentralAuthCredentials(token)); return this.GenerateToken(); } 

这些方法基本上应该从端点中删除默认凭据并附加我的自定义CentralAuthCredentials的新实例。 (我从某处的MSDN文章中抓取了这个删除/添加组合)。

在配置中:

                       

请注意,行为的clientCredentials类型设置为我的自定义客户端凭据。 但是,目前我仍然将绑定的clientCredentialType设置为“UserName”。 这提出了我的第二个问题 :clientCredentialType =“是什么?” 如果我使用自定义凭据,请设置为? 根据MSDN, Message安全性的可用值包括: NoneWindowsUserNameCertificateIssuedToken

有任何想法吗? 希望我只是错过了一些简单的东西? 整个实现中还有6个类,但我试图只包含理解情况所需的位…


更新#1:

我一整天都在努力,感谢一些消息来源,我意识到我遗漏的部分是这个页面的最后一步,即将TokenParameters添加到绑定中,以便绑定知道什么令牌看起来像。 这是我原来的第一个问题的答案; “什么设置了令牌要求?” 答案:分配给绑定的TokenParameters。

所以现在我添加了以下扩展,它在绑定上设置TokenParameters:

 public sealed class CentralAuthTokenBindingExtension : BindingElementExtensionElement { public CentralAuthTokenBindingExtension() : base() { } public override Type BindingElementType { get { return typeof(SymmetricSecurityBindingElement); } } protected override System.ServiceModel.Channels.BindingElement CreateBindingElement() { X509SecurityTokenParameters protectionParams = new X509SecurityTokenParameters(); protectionParams.InclusionMode = SecurityTokenInclusionMode.Never; SymmetricSecurityBindingElement innerBindingElement = new SymmetricSecurityBindingElement(); innerBindingElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CentralAuthTokenParameters()); //innerBindingElement.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt; innerBindingElement.ProtectionTokenParameters = protectionParams; return innerBindingElement; } }               

那让我更进一步。 现在我在服务器上得到一个新的exception:

 "The security token manager cannot create a token authenticator for requirement ..." 

看起来WCF正在使用一些默认令牌管理器来尝试处理我的自定义令牌,而不是我的自定义令牌处理程序(我从不调用自定义令牌处理程序的构造函数)。 我认为这是发生的,因为对于客户端 ,我有这个配置:

    

但是在服务器上我没有任何等同于让它知道自定义客户端凭据。 所以, 新问题 :在服务器的配置中,我告诉它自定义ClientCredentials是什么?


更新#2:

好吧,我终于想出了更多的谜题。 我只实现了ClientCredentials实现,认为客户端发送了信用证,就是这样。 客户端不会对服务进行身份validation,因此我不需要自定义ServiceCredentials。 好吧,我错了。 指定的ServiceCredentials从ClientCredentialsvalidation令牌,反之亦然。 所以我只需要添加一个自定义的ServiceCredentials实现,该实现传递相同的TokenSerializer和TokenAuthenticator类。

转到下一个问题:WCF现在忽略我在配置中指定的x509证书,这些证书与UserName auth一起正常工作。 我打算为这个开一个全新的问题!

我遇到了与我正在处理的应用程序类似的问题,不幸的是我因为无法获得自定义凭据而放弃了。 我现在使用用户名/密码(客户端凭证)和证书(服务凭证),并在服务调用中添加自定义加密soap标头以传递其他信息,例如UserID等。