C# 使用自定义 ClientCredentials 的 WCF 身份验证:要使用的 clientCredentialType 是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/563037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WCF Authentication with custom ClientCredentials: What is the clientCredentialType to use?
提问by CodingWithSpike
I had to ditch the basic WCF UserName/Pwd security and implement my own custom client credentials to hold some more info beyond what is provided by default.
我不得不放弃基本的 WCF UserName/Pwd 安全性并实现我自己的自定义客户端凭据,以保存默认情况下提供的更多信息。
I worked throughthis MSDN article, but I'm missing something because it doesn't work.
我完成了这篇 MSDN 文章,但我遗漏了一些东西,因为它不起作用。
First, I have some custom ClientCredentials that provide a custom ClientCredentialsSecurityTokenManager:
首先,我有一些提供自定义 ClientCredentialsSecurityTokenManager 的自定义 ClientCredentials:
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();
}
}
Now when I run the app, my custom credentials and token manager do get created. However, in the method:
现在,当我运行该应用程序时,会创建我的自定义凭据和令牌管理器。但是,在方法中:
CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
{
...
}
The tokenRequirement.TokenType comes across as something other than my custom token. That brings up my 1st question: How the heck does WCF know what the token requirements are?
tokenRequirement.TokenType 与我的自定义令牌不同。这带来了我的第一个问题:WCF 怎么知道令牌要求是什么?
Also, the method:
还有方法:
public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
{
return new CentralAuthTokenSerializer();
}
Does get called once by the client, but none of the methods on the returned token serializer are ever called. This indicates to me that the custom token is never being sent across the wire. I assume this is because the call to CreateSecurityTokenProvider() never returned my custom token provider, since the SecurityTokenRequirement is never passed in indicating my custom token is needed.
客户端会调用一次,但返回的令牌序列化器上的任何方法都不会被调用。这向我表明自定义令牌永远不会通过网络发送。我认为这是因为对 CreateSecurityTokenProvider() 的调用从未返回我的自定义令牌提供程序,因为 SecurityTokenRequirement 从未传入指示需要我的自定义令牌。
On the client side, I have:
在客户端,我有:
public class CentralAuthorizationManagerClient : ClientBase<ICentralAuthorizationManager>, 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<ClientCredentials>();
this.ChannelFactory.Endpoint.Behaviors.Add(new CentralAuthCredentials(token));
return this.GenerateToken();
}
These methods are basically supposed to remove the default credentials from the endpoint and attach a new instance of my custom CentralAuthCredentials. (I grabbed this Remove/Add combo from an MSDN article somewhere).
这些方法基本上应该从端点删除默认凭据并附加我的自定义 CentralAuthCredentials 的新实例。(我从某处的 MSDN 文章中获取了这个删除/添加组合)。
In the configuration:
在配置中:
<behaviors>
<endpointBehaviors>
<behavior name="Server2ServerEndpointBehavior">
<clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp">
<clientCertificate findValue="localhost" x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My" />
<serviceCertificate>
<authentication certificateValidationMode="None" revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="wsHttpServer2Server">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
Note that the behavior's clientCredentials type is set to my custom client credentials. However, at the moment I still have the binding's clientCredentialType set to "UserName". This brings up my 2nd question: What the heck should clientCredentialType="?" be set to if I'm using custom credentials? According to MSDN, the available values for Messagesecurity are: None, Windows, UserName, Certificate, and IssuedToken.
请注意,行为的 clientCredentials 类型设置为我的自定义客户端凭据。但是,目前我仍然将绑定的 clientCredentialType 设置为“UserName”。这带来了我的第二个问题:clientCredentialType=”到底应该是什么?如果我使用自定义凭据,则设置为?根据 MSDN,消息安全的可用值是:None、Windows、UserName、Certificate和IssuedToken。
Any ideas? Hopefully I'm just missing something simple? There are like 6 more classes to the entire implementation, but I tried to only include the bits needed to understand the situation...
有任何想法吗?希望我只是错过了一些简单的东西?整个实现还有 6 个类,但我试图只包括理解情况所需的位......
UPDATE #1:
更新#1:
I've been working on this all day, and thanks to a few sources, I realized that part of what I was missing was the very last step on this page, which is adding the TokenParameters to the binding, so that the binding knows what the token looks like. That is the answer to my original 1st question; "what the heck sets up the token requirements?" Answer: the TokenParameters assigned to the binding.
我一整天都在研究这个,多亏了一些消息来源,我意识到我缺少的部分是这个页面的最后一步,即将 TokenParameters 添加到绑定中,以便绑定知道什么令牌看起来像。那是我最初的第一个问题的答案;“到底是什么设置了令牌要求?” 答案:分配给绑定的 TokenParameters。
So now I added the following extension which sets the TokenParameters on the binding:
所以现在我添加了以下扩展,它在绑定上设置 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;
}
}
<extensions>
<bindingElementExtensions>
<add name="CentralAuthCreds" type="MyApp.Security.Configuration.CentralAuthTokenBindingExtension, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bindingElementExtensions>
</extensions>
<bindings>
<customBinding>
<binding name="wsHttpServer2Server">
<CentralAuthCreds />
<binaryMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
Well that gets me a step further. Now I get a new exception on the server:
嗯,这让我更进一步。现在我在服务器上收到一个新的异常:
"The security token manager cannot create a token authenticator for requirement ..."
It looks like WCF is using some default token manager to try to deal with my custom token, instead of my custom token handler (my custom token handler's constructor is never called). I thinkthis is happening because for the client, I have this config:
看起来 WCF 正在使用一些默认令牌管理器来尝试处理我的自定义令牌,而不是我的自定义令牌处理程序(我的自定义令牌处理程序的构造函数从未被调用)。我认为这是因为对于客户端,我有以下配置:
<endpointBehaviors>
<behavior name="Server2ServerEndpointBehavior">
<clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp">
But on the serverI don't have any equivalent to let it know about the custom client credentials. So, new question: Where in the config for the server do I tell it what the custom ClientCredentials are?
但是在服务器上,我没有任何等价物可以让它知道自定义客户端凭据。所以,新问题:我应该在服务器的配置中的哪个位置告诉它自定义 ClientCredentials 是什么?
Update #2:
更新#2:
Well, I finally figured out a bit more of the puzzle. I had only implemented a ClientCredentials implementation, thinking that the client sends creds, and thats it. The client doesnt authenticate the service, so I don't need custom ServiceCredentials. Well, I was wrong. The specified ServiceCredentials authenticates the token from the ClientCredentials, and vice-versa. So I just had to add a custom ServiceCredentials implementation that passed the same TokenSerializer and TokenAuthenticator classes.
好吧,我终于想出了更多的谜题。我只实现了 ClientCredentials 实现,认为客户端发送凭据,仅此而已。客户端不验证服务,所以我不需要自定义 ServiceCredentials。好吧,我错了。指定的 ServiceCredentials 验证来自 ClientCredentials 的令牌,反之亦然。所以我只需要添加一个自定义的 ServiceCredentials 实现,它传递相同的 TokenSerializer 和 TokenAuthenticator 类。
On to the next issue: WCF is now ignoring my x509 certs specified in config that were working fine with UserName auth. I'm going to open a whole new question for this one!
关于下一个问题:WCF 现在忽略我在配置中指定的 x509 证书,这些证书与 UserName auth 一起工作正常。我要为这个问题打开一个全新的问题!
回答by Tanner
I ran in to similar issues with an application I'm working on, unfortunately I gave up as I couldn't get the custom credentials working. I'm now using username/password (client credentials) and certificate (service credentials) with custom encrypted soap headers added to service calls to pass around additional info e.g UserID etc.
我在我正在处理的应用程序中遇到了类似的问题,不幸的是我放弃了,因为我无法使自定义凭据正常工作。我现在使用用户名/密码(客户端凭据)和证书(服务凭据),并将自定义加密的soap标头添加到服务调用中以传递附加信息,例如用户ID等。