我不得不放弃基本的WCF用户名/Pwd安全性,实现我自己的自定义客户端凭据,以保存一些超出默认设置的更多信息。
我努力了
this MSDN article
,但我错过了一些东西,因为它不起作用。
首先,我有一些自定义ClientCredentials,它们提供了一个自定义clientcredentialsecuritytokenmanager:
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)
{
...
}
这个令牌需求.令牌类型不是我定制的代币。这就引出了我的问题
第一个问题
:WCF如何知道令牌要求是什么?
此外,方法:
public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
{
return new CentralAuthTokenSerializer();
}
在客户方面,我有:
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();
}
在配置中:
<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>
请注意,行为的clientCredentials类型设置为“我的自定义客户端凭据”。但是,目前我仍然将绑定的clientCredentialType设置为“UserName”。这就引出了我的问题
:clientCredentialType=“”到底该怎么办如果我使用自定义凭据,是否设置为?根据MSDN,可用的
信息
没有
窗户
用户名
,
证书
.
有什么想法吗?希望我错过了一些简单的事情?整个实现还有6个类,但是我试着只包含理解情况所需的部分。。。
我花了一整天的时间来研究这个问题,多亏了一些消息来源,我意识到我所缺少的一部分是最后一步
this page
,将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;
}
}
<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>
这让我更进一步。现在服务器上出现了一个新异常:
"The security token manager cannot create a token authenticator for requirement ..."
看起来WCF正在使用一些默认的令牌管理器来尝试处理我的自定义令牌,而不是我的自定义令牌处理程序(我的自定义令牌处理程序的构造函数从未被调用)。我
这是因为
,我有以下配置:
<endpointBehaviors>
<behavior name="Server2ServerEndpointBehavior">
<clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp">
但是在
我没有任何等价物让它知道自定义客户端凭据。所以,
新问题
更新#2:
嗯,我终于猜出了更多的谜题。我只实现了一个ClientCredentials实现,认为客户端发送creds,就这样。客户机不验证服务,因此我不需要自定义ServiceCredentials。我错了。指定的ServiceCredentials从ClientCredentials验证令牌,反之亦然。所以我只需要添加一个自定义ServiceCredentials实现,它传递相同的TokenSerializer和TokenAuthenticator类。