Bei der Implementierung einer Verbundlösung oder der Ablösung einer bestehenden Legacy-Lösung sollten wir uns überlegen, wie wir das Problem anders angehen" können.
Ein aktueller Kunde hat eine bestehende "Legacy"-SSO- und Federation-Plattform, die relativ komplex ist. Es handelt sich dabei um eine Siteminder-Implementierung, der die CA-Föderationskomponenten hinzugefügt wurden. Obwohl die Lösung funktioniert, möchte der Kunde Lizenzkosten vermeiden und seine Infrastruktur vereinfachen. Wir implementieren AD FS für ihn, um als Federation Engine zu dienen. Zu den längerfristigen Zielen gehört die Migration der SSO-Anwendungen auf SAML 2.0, und die Anwendungen werden nach Möglichkeit claims aware sein. Wenn dies nicht möglich ist, können einige Anwendungen auf Kerberos oder die integrierte Windows-Authentifizierung umgestellt werden.
Ein Teil meiner Architekturphilosophie konzentriert sich auf die Vereinfachung. Einfachheit ist, wenn sie klug umgesetzt wird, stabiler und zuverlässiger, leichter zu unterstützen und (sollte) leichter zu verstehen sein.
Obwohl die bestehende Siteminder-Architektur einige Vorteile und Stärken aufweist, nutzte der Kunde die in der CA-Lösung verfügbaren Funktionen nicht. Diese Funktionen werden nicht benötigt, um die Projektziele zu erreichen. Warum sollte man für Funktionen bezahlen, die man nicht nutzt und auch nicht vorhat, sie jemals zu nutzen?
In der neuen Lösung übernimmt AD FS über seine Federation-Engine die Richtlinienlogik und die nachgelagerten föderierten Anwendungen handhaben ihre eigene Autorisierungslogik (genau wie bei der alten Lösung). Nicht föderationsfähige Anwendungen werden hinter einem ISAPI-Filter von Siteminder rückwärts projiziert und verwenden eine einfache Header-Variable mit einer Mitarbeiter-ID als Wert. Das ist keine sichere oder moderne Art, Dinge zu tun.
Den Status des Siteminder-Cookies ständig über den Proxy zu überprüfen, ist schön und gut, aber wie lösen wir das Problem des Durchreichens des Mitarbeiter-ID-Headers? Ist SSL "genug"? Ich fühle mich mit diesem Sicherheitsniveau (oder dem Mangel daran) nicht wohl, aber wir müssen vorerst mit dem arbeiten, was die nachgelagerten Anwendungen unterstützen.
Ein Schlüssel zu meiner Lösung ist, dass sie nicht von AD FS abhängig ist - wenn unser Kunde beschließt, zu einem anderen Produkt zu migrieren oder die Identitätsanbieterfunktionalität an einen Cloud-Anbieter auszulagern, funktioniert diese Lösung ohne zusätzlichen Code oder Änderungen! Der Kundenadministrator aktualisiert einfach zwei Zeilen in einer Konfigurationsdatei und schon ist er bereit, SAML-Assertions von einem neuen Identity Provider zu verwenden!
Schauen wir uns die wichtigsten Architektur- und Designelemente dieser Lösung an:
- Ich habe WIF (Windows Identity Foundation) nicht verwendet. WIF ist zwar das Herzstück der anforderungsbasierten Entwicklung für .NET-Anwendungen, aber es passte nicht zu den Schlüsselkonzepten meines Entwurfs. Ich habe bereits erwähnt, dass wir eine Bindung an AD FS vermeiden wollen.
- Ich wollte die Leistung steigern, indem ich kompilierten Code anstelle von interpretiertem ASP verwende. Ich hatte vor, die Anwendung in C# zu schreiben, wollte sie aber als Assembly haben. Es gibt noch weitere Gründe für die Kompilierung des Codes, die wir gleich sehen werden.
- Bei dem Code handelt es sich um einen benutzerdefinierten HTTP-Handler und nicht um einen Filter oder eine andere Schnittstelle. Die Verarbeitung erfolgt, ohne dass irgendwelche html- oder aspx-Dateien oder Skripte erforderlich sind. Die Schnittstelle zum Handler akzeptiert Verbindungen, die an einen virtuellen Dateityp gerichtet sind.
- Die Lösung ist einfach ein Dienstanbieter oder "SP" in der SAML 2.0-Terminologie, was Microsoft in der AD FS-Sprache als "Relying Party" bezeichnen würde. Beachten Sie, dass zusätzliche Komponenten einer typischen Föderationsplattform nicht vorhanden sind, da sie nicht Teil des Entwurfsziels sind - wir lösen ein bestimmtes Problem und versuchen nicht, eine Multikomponenten-Föderationslösung zu schaffen. Insbesondere habe ich beabsichtigt, dass der Entwurf mehrere Identity Provider-Verbundpartner unterstützt.
- Ich wollte, dass die Lösung so leicht und unabhängig von anderen Komponenten wie möglich ist. Wenn ich von "leichtgewichtig" spreche, denke ich zum Beispiel daran, dass der Code kein SQL-Datenbank-Backend verwendet oder benötigt! Es besteht keine Notwendigkeit dafür, wie ich noch erläutern werde! Bedenken Sie, wie dies die Leistung verbessern kann - es gibt einfach keine Wartezeiten für eine Datenbankverbindung, Abfrage und Antwort. Ganze Kategorien von Fehlermöglichkeiten werden durch diese Vereinfachung eliminiert.
- Natürlich ist der Code erweiterbar - wenn eine weitere nachgelagerte Anwendungsschnittstelle gewünscht wird, kann sie dem Code hinzugefügt werden, ohne dass der bereits vorhandene Code umgeschrieben werden muss.
- Abgesehen von der offensichtlichen Anforderung, dass der Server des HTTP-Handlers IIS sein und .NET 3.5 oder neuer unterstützen muss, habe ich den Code nicht an eine bestimmte Webserver-Anwendungssprache gebunden - der Webserver, mit dem mein SP-Code zusammenarbeitet, könnte VB, C# oder vielleicht PHP, Python oder eine andere Sprache verwenden. Unabhängig davon, ob sich die Anwendung, die wir SAML-fähig machen, auf demselben IIS-Server oder auf einem separaten Server befindet, auf dem Weblogic oder Apache läuft - die Lösung ist plattformunabhängig."
- Wie Sie sich denken können, wollte ich nicht, dass sich die Lösung in einer einzigen Active Directory-Domäne mit dem IdP befindet und dass sie Active Directory nicht einmal benötigt. Bedenken Sie, dass es als eigenständiger SP keine inhärente Anforderung gibt, dass die Anwendung, die föderiert wird, überhaupt ein Verzeichnis verwendet! Zugegeben, eine der Verbindungsoptionen, die ich hinzugefügt habe, ist ein LDAP-Lookup, das ein ASPX-Benutzerkontext-Token erstellt, da dies für eine Implementierung erforderlich war.
- Im Zusammenhang mit Punkt 5 wird der SP über eine einfache web.config-Datei konfiguriert - je einfacher, desto besser, war mein Ziel. Ein IIS-Server mit den folgenden Voraussetzungen: .NET 3.5 oder höher, ein Dienstkonto, das dem App Pool zugewiesen werden kann, Informationen über den IdP (oder mehrere IdPs!) kann in weniger als 5 Minuten konfiguriert und in Betrieb genommen werden!
- Skalierbarkeit. Ich hoffte, dass ich unter Einhaltung der hier beschriebenen Designziele eine leicht skalierbare Lösung schaffen könnte. Wir werden die Vor- und Nachteile meines "einfachen" Ansatzes sehen. Keine zentrale Konfigurationsdatenbank bedeutet zwar, dass für jeden hinzugefügten SP-Server eine Konfigurationsdatei verwaltet werden muss (jeder Server hat eine web.config), aber das System wird auch mit nur wenigen Servern sehr gut funktionieren, und das Problem, wie man einige wenige Dateien synchronisiert, wurde gründlich gelöst und sollte gut verstanden werden. Selbst wenn Sie eine zentrale Konfigurationsdatenbank hätten, müssten einige Elemente der n-Server-Konfiguration immer noch auf jedem System bearbeitet werden.
Beschränkungen:
Derzeit wird mit der POST-Bindung nur IdP-initiiertes SSO unterstützt. Dies ist eigentlich keine große Einschränkung, da ein IdP dies sicher unterstützt - es ist die am häufigsten verwendete SAML-Bindung. Der Code kann aktualisiert werden, um SP-initiiertes SSO oder sogar HTTP-Redirect-Binding zu unterstützen (die Fähigkeit zur Unterstützung von Query-Strings ist bereits vorhanden), aber ich habe nicht die Absicht, Artifact-Resolution oder SOAP-Binding zu unterstützen - sie erhöhen nur die Komplexität und sind nicht so häufig. In all meinen Föderationsprojekten hat noch nie jemand auf Artifact Resolution bestanden oder gar nach SOAP gefragt.
Anmerkungen:
Die .dll-Datei hat derzeit eine bescheidene Größe von 20 KB. Die typische SAML-Assertion-Verarbeitungszeit beträgt nur 5 ms mit einem beobachteten Durchschnitt von etwa 20-27 ms. Diese Messungen wurden auf verschiedenen VM-Konfigurationen durchgeführt, darunter eine "Micro"-Amazon AWS EC2-Instanz. Diese Verarbeitungszeit umfasst den vollständigen Verbrauch der SAML 2.0-Assertion einschließlich der erforderlichen Schritte wie die Überprüfung der kryptografischen Signatur(en) und der gesamten Logik für die Übergabe an die nachgeschaltete Anwendung.