Aktive Federation mit Windows Identity Foundation
Geschrieben von am 9. September 2011 (3)
Manchmal können Sie aktiv Verband mit Windows Identity Foundation durchführen müssen (zum Beispiel die Authentifizierung gegen ein STS wie ADFS aus einem Verfahren, wie Windows-Dienst oder Konsolenanwendung). Nach viele Stunden die spärliche Dokumentation zum Scheuern konstruierte ich die Lösung, die unten aufgeführt ist. Beachten Sie, dass diese Implementierung verwendet UsernameMixed (weil in diesem Szenario, das ich die Anmeldedaten zur Hand haben), kann aber bei Bedarf geändert werden. Das Endergebnis ist, dass Sie Anmeldung aufrufen können (Benutzername, Passwort) und wenn die Funktion Aufruf abgeschlossen werden Sie eine IClaimsPrincipal gesetzt haben, die alle Ihre Identität enthält Informationen. Beachten Sie, dass dies bei einigen Konfigurationseinträge abhängig ist, nämlich: CertificateIssuerName - Der Name des Zertifikats Emittent STSThumbprint - Der Fingerabdruck des STS STSEndpoint - Der Remote-Endpunkt der STS STSRelyingPartyEndpoint - Die Adresse des RP-Endpunkt mit dem STS DisableRemoteSTSCertificateValidation registriert - Boolean zu aktivieren / deaktivierenZertifikatsüberprüfung (falls Sie es in einem lokalen / DEV-Umgebung zu deaktivieren) Der Prozess dreifach ist: ein X509CertificateValidator erstellen das Zertifikat erstellen IssuerNameRegistry zur Validierung der Daumenabdruck tatsächlich verwenden einige Code zu bestätigen, um den Anruf zu tätigen, die SAML-Token zu entschlüsseln, und konstruieren einen IClaimsPrincipal Das Zertifikat Validator: public class CustomCertificateValidator: X509CertificateValidator { public CustomCertificateValidator () { } public override void Validate (System.Security.Cryptography.X509Certificates.X509Certificate2 Zertifikat) { String allowedIssuerKey = "CertificateIssuerName"; if (string.IsNullOrEmpty (ConfigurationManager.AppSettings [allowedIssuerKey])) { throw new Application (string.Format ( "Issuer Config Schlüssel {0} existiert nicht in der Konfiguration", allowedIssuerKey)); } ob(! Certificate.IssuerName.Name.Equals (ConfigurationManager.AppSettings [allowedIssuerKey])) { throw new Application (string.Format ( "Zertifikat kommt von Emittenten {0}, die nicht erlaubt ist.", certificate.IssuerName.Name)); } } } Die IssuerNameRegistry: public class CustomTrustedIssuerNameRegistry: IssuerNameRegistry { /// <Summary> /// /// </ Summary> public CustomTrustedIssuerNameRegistry () { } /// <Summary> /// /// </ Summary> /// <Param name = "Security"> </ param> /// <Returns> </ returns> public override string GetIssuerName (Securitysecurity) { X509SecurityToken x509Token = Security als X509SecurityToken; if (x509Token! = null) { String thumbprintConfigKey = "STSThumbprint"; ob(String.IsNullOrEmpty (ConfigurationManager.AppSettings [thumbprintConfigKey])) { throw new InvalidDataException (string.Format ( "Thumbprint Config Schlüssel {0} existiert nicht in der Konfiguration", thumbprintConfigKey)); } if (String.Equals (x509Token.Certificate.Thumbprint, ConfigurationManager.AppSettings [thumbprintConfigKey])) { Rückkehr x509Token.Certificate.SubjectName.Name; } } werfen neue SecurityTokenException ( "Nicht vertrauenswürdige Emittenten."); } public override string GetWindowsIssuerName () { Rückkehr base.GetWindowsIssuerName (); } } Und der Hauptcode: /// <Summary> /// Login-Methode von Verfahren verwendet werden, die nicht durch das Netz laufen und eine Mitgliedschaft nutzen können /// Anbieter. Diese Login-Methode wird ein IClaimsPrincipal Objekt an den aktuellen Thread anhängen /// Und alle neuenThemen, die im Rahmen dieser Anwendungsdomäne erstellt wird. /// </ Summary> /// <Param name = "username"> Benutzername. </ Param> /// <Param name = "password"> Kennwort. </ Param> /// <Returns> Ob die Anmeldung erfolgreich war. </ Returns> public static bool Anmeldung (string username, string Passwort) { // Die vorherige Haupt Get (falls die Validierung fehlschlägt, und wir müssen wieder herzustellen) IPrincipal previousPrincipal = Thread.CurrentPrincipal; Versuchen { if (System.Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated) { // Abmelden, wenn nötig Ausloggen(); } String endpointKey = "STSEndpoint"; String rpKey = "STSRelyingPartyEndpoint"; String disableCertValidationKey = "DisableRemoteSTSCertificateValidation"; // Der STS-Endpunkt var adfsEndpoint = ConfigurationManager.AppSettings [endpointKey]; // Der RP-Endpunkt var relyingPartyEndpoint =ConfigurationManager.AppSettings [rpKey]; if (string.IsNullOrEmpty (adfsEndpoint)) { throw new InvalidDataException (string.Format ( "Endpoint '{0}' ist nicht in der Konfiguration definiert und nicht in Anmeldung gelöst werden können ()", endpointKey)); } if (string.IsNullOrEmpty (rpKey)) { throw new InvalidDataException (string.Format ( "Relying Party '{0}' ist nicht in der Konfiguration definiert und nicht in Anmeldung gelöst werden können ()", relyingPartyEndpoint)); } // Anfügen Anmeldung mit Anmeldeinformationen die wir hier haben. adfsEndpoint = String.Concat (adfsEndpoint, "Dienstleistungen / Versicherungen / 13 / UsernameMixed /"); if (! string.IsNullOrEmpty (disableCertValidationKey)) { String disableRemoteSTSCertificateValidation = ConfigurationManager.AppSettings [disableCertValidationKey]; bool disableSTSCertificateValidation; if (Boolean.TryParse (disableRemoteSTSCertificateValidation, ausdisableSTSCertificateValidation)) { if (disableSTSCertificateValidation) { // Geben Sie den Endpunkt für diese Anwendung auf ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback ( delegieren { return true; }); } } } var Fabrik = new WSTrustChannelFactory ( neue UserNameWSTrustBinding (SecurityMode.TransportWithMessageCredential), neue EndpointAddress (adfsEndpoint)); // Stellen Sie die Anmeldeinformationen factory.Credentials.UserName.UserName = Benutzername; factory.Credentials.UserName.Password = Passwort; // Den Emittenten Registrierungssatz des Fingerabdrucks gegen zu validieren FederatedAuthentication.ServiceConfiguration.IssuerNameRegistry = newCustomTrustedIssuerNameRegistry (); FederatedAuthentication.ServiceConfiguration.CertificateValidator = new CustomCertificateValidator (); var Handler = FederatedAuthentication.ServiceConfiguration.SecurityTokenHandlers.Where (e => e.TokenType == typeof (Saml2SecurityToken)) FirstOrDefault (). System.Collections.ObjectModel.Collection <Uri> uris = handler.Configuration.AudienceRestriction.AllowedAudienceUris; if (uris! = null &&! uris.Any (u => u.OriginalString == relyingPartyEndpoint)) { uris.Add (new Uri (relyingPartyEndpoint)); } var channel = factory.CreateChannel (); var rst = new RequestSecurityToken { Request = RequestTypes.Issue, AppliesTo = new EndpointAddress (relyingPartyEndpoint), KeyType = KeyTypes.Bearer }; RequestSecurityTokenResponse rstr = null; GenericXmlSecurityToken Token = channel.Issue (rst, ausrstr) als GenericXmlSecurityToken; DecryptAndAttachTokenToPrincipal (Token); } catch (Exception ex) { if (ex ist Message) { // Benutzer Überprüfung fehlschlägt. Verbrauchen // die Message, zur Wiederherstellung der früheren Haupt und return false. Thread.CurrentPrincipal = previousPrincipal; return false; } sonst { // Sprudeln alle anderen Ausnahmen werfen ab; } } return true; } /// <Summary> /// Entschlüsselt die GenericXmlSecurityToken eingeleitet und misst der Ansprüche Identität der /// Thread des Haupt als ClaimsPrincipal /// </ Summary> /// <Param name = "GenericXmlSecurityToken"> </ param> public static void DecryptAndAttachTokenToPrincipal (GenericXmlSecurityToken GenericXmlSecurityToken) { var Token = FederatedAuthentication.ServiceConfiguration.SecurityTokenHandlers.ReadToken (neuXmlTextReader (neue String (genericXmlSecurityToken.TokenXml.OuterXml))); var Identität = FederatedAuthentication.ServiceConfiguration.SecurityTokenHandlers.ValidateToken (Token) .First (); // Die IClaimsPrincipal bekommen und es auf den aktuellen Thread anhängen IClaimsPrincipal claimsPrincipal = ClaimsPrincipal.CreateFromIdentity (Identität); Thread.CurrentPrincipal = claimsPrincipal; }