Ich musste die grundlegende WCF UserName/Pwd-Sicherheit ablegen und meine eigenen benutzerdefinierten Client-Anmeldeinformationen implementieren, um weitere Informationen zu speichern, die über die standardmäßig bereitgestellten Werte hinausgehen.WCF-Authentifizierung mit benutzerdefinierten ClientCredentials: Was ist der zu verwendende clientCredentialType?
Ich arbeitete durch this MSDN article, aber ich vermisse etwas, weil es nicht funktioniert.
Zuerst hat ich einige benutzerdefinierten ClientCredentials, die einen benutzerdefinierten ClientCredentialsSecurityTokenManager bieten:
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();
}
}
Nun, wenn ich die App laufe, meine benutzerdefinierten Anmeldeinformationen und Token-Manager tun erstellt bekommen. bei dem Verfahren jedoch: kommen
CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
{
...
}
Die tokenRequirement.TokenType across als etwas anderes als meine benutzerdefinierten Token. Das bringt meine 1. Frage: Wie zum Teufel weiß WCF, was die Token-Anforderungen sind?
Auch die Methode:
public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
{
return new CentralAuthTokenSerializer();
}
einmal vom Kunden genannt bekommen, aber keine der Methoden auf dem Token Serializer zurückgegeben wird immer genannt. Dies zeigt mir an, dass das benutzerdefinierte Token nie über die Leitung gesendet wird. Ich nehme an, dass das ist, weil der Aufruf von CreateSecurityTokenProvider() meinen benutzerdefinierten Token-Anbieter nie zurückgab, da das SecurityTokenRequirement nie übergeben wird, das angibt, dass mein benutzerdefiniertes Token benötigt wird.
Auf der Client-Seite, die ich habe:
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();
}
Diese Methoden grundsätzlich die Standardanmeldeinformationen von dem Endpunkt entfernen sollen und eine neue Instanz von meinem benutzerdefinierten CentralAuthCredentials befestigen. (Ich habe diese Remove/Add-Combo aus einem MSDN-Artikel irgendwo abgeholt).
In der Konfiguration:
<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>
Beachten Sie, dass die ClientCredentials Typ Verhalten zu meinen benutzerdefinierten Clientanmeldeinformationen festgelegt ist. Im Moment habe ich jedoch noch den clientCredentialType der Bindung auf "UserName" gesetzt. Das bringt meine 2. Frage: Was zum Teufel sollte clientCredentialType = "?" festgelegt werden, wenn ich benutzerdefinierte Anmeldeinformationen verwende? Laut MSDN, die verfügbaren Werte für Nachricht Sicherheit sind: Keine, Windows-, Benutzername, Zertifikat und IssuedToken.
Irgendwelche Ideen? Hoffentlich vermisse ich einfach etwas Einfaches? Es gibt 6 weitere Klassen für die gesamte Implementierung, aber ich habe versucht, nur die Bits einzubeziehen, die benötigt werden, um die Situation zu verstehen ...
UPDATE # 1:
ich an diesem ganzen Tag gearbeitet haben, und dank einiger Quellen, erkannte ich, dass ein Teil dessen, was ich der allerletzte Schritt war auf this page fehlte , die die TokenParameters zur Bindung hinzufügt, damit die Bindung weiß, wie das Token aussieht. Das ist die Antwort auf meine erste Frage. "Was zum Teufel setzt die Token-Anforderungen?" Antwort: Die der Bindung zugewiesenen TokenParameter.
So, jetzt habe ich die folgende Erweiterung, die die TokenParameters auf die Bindung setzt:
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>
Nun, das mich einen Schritt weiter geht. Jetzt habe ich eine neue Ausnahme auf dem Server erhalten:
"The security token manager cannot create a token authenticator for requirement ..."
Es ist wie WCF sieht einen Standard-Token-Manager verwendet, um zu versuchen mit meinen benutzerdefinierten Token zu beschäftigen, statt meinen benutzerdefinierten Token-Handler (meine benutzerdefinierten Token-Handler Konstruktor ist nie namens). Ich denke, dies geschieht, weil für den Client, ich habe diese config:
<endpointBehaviors>
<behavior name="Server2ServerEndpointBehavior">
<clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp">
Aber auf dem Server Ich habe keine gleichwertige es über die benutzerdefinierten Clientanmeldeinformationen wissen zu lassen. Also, neue Frage: Wo in der Konfig für den Server sage ich, was die benutzerdefinierten ClientCredentials sind?
Update # 2:
Nun habe ich endlich ein bisschen mehr von dem Puzzle herausgefunden. Ich hatte nur eine ClientCredentials-Implementierung implementiert und dachte, dass der Kunde Kredits sendet, und das ist es. Der Client authentifiziert den Dienst nicht, daher benötige ich keine benutzerdefinierten ServiceCredentials. Nun, ich habe mich geirrt. Die angegebenen ServiceCredentials authentifizieren das Token von den ClientCredentials und umgekehrt. Daher musste ich nur eine benutzerdefinierte ServiceCredentials-Implementierung hinzufügen, die dieselben Klassen TokenSerializer und TokenAuthenticator übergab.
Zum nächsten Problem: WCF ignoriert jetzt meine in config angegebenen x509-Zertifikate, die mit der UserName-Authentifizierung funktionierten. Ich werde eine ganz neue Frage für diesen eröffnen!
übergeben, also diese Frage liest sich fast genau wie meine letzte zwei Tage! – basscinner