29. ledna 2018

Spring Security, SAML & ADFS: Implementace

Posledně jsme se vyřádili na konfiguraci, tak teď už jen zbývá to nabouchat v tom Springu, ne? Dobrá zpráva je, že pokud budete následovat Reference Documentation, bude vám Spring SAML a ADFS fungovat out-of-the-box.

Špatná zpráva je, že pokud budete chtít použít Java configuration, nemáte se moc kde inspirovat. Pokud vím, tak k dnešnímu dni jsou k dispozici jen dva příklady:
Dalším benefitem mého příspěvku a ukázkového projektu je, že používají aktuální verzi Spring Frameworku a Spring Security, tedy verzi 5 (v tomhle asi budu chviličku unikátní). Třešničkou na dortu je pak buildování pomocí Gradle (protože kdo by ještě chtěl v dnešní době používat Maven, že jo? ;-)

Závislosti

Pro zdar operace budeme potřebovat následující závislosti:

Drobná Gradle poznámka: Protože používám současnou verzi Gradlu, používám konfiguraci implementation. Pro starší verze Gradle (2.14.1-) použijte původní (nyní deprecated) konfiguraci compile.

Spring SAML Configuration

Ať už se použije XML, nebo Java konfigurace, bude to v každém případě velmi dlouhý soubor. Velmi. I když nebudu počítat téměř 40 řádek importů, i tak zabere ta nejzákladnější konfigurace zhruba 5 obrazovek. Víc se mi to ořezat nepodařilo.

Ale nebojte se, nebudu vás oblažovat každým detailem. Jen vypíchnu to zajímavé, vynechám co jsem zmiňoval v minulém díle o konfiguraci a pro zbytek konfigurace vás odkážu do svého repozitáře, kde si to můžete vychutnat celé: SecurityConfiguration.java.

Nastavení HttpSecurity

Nebudu příliš zabíhat do podrobností, jak funguje samotné Spring Security (prostě chrání pomocí filtrů určité URL/zdroje) a podívám se na jedno konkrétní nastavení:

Uvedené nastavení definuje:
  • Vypnuté CSRF. U SAMLu nedává CSRF moc smysl - SAML requesty jsou podepsané privátním klíčem daného SP, jehož veřejný klíč je zaregistrován na použitém IdP.
  • Přídání dvou filtrů: jeden pro SAML metadata (metadataGeneratorFilter), druhý řeší samotný SAML mechanismus (samlFilter).
  • Definice URL, které vyžadují autentikaci (/user). 
  • Podstrčení SAML entry pointu namísto přihlašovacího formuláře (loginPage("/saml/login")).
  • Přesměrování na root kontext aplikace po úspěšném odhlášení (logoutSuccessUrl("/")).

SAML filtry

Základem jak Spring Security, tak Spring Security SAMLu jsou filtry - odchytí HTTP(S) komunikaci a transparentně aplikují zabezpečení aplikace. V případě SAMLu je těch filtrů celá smečka, ale v zásadě řeší jen tři věci: přihlášení (SSO), odhlášení (SLO) a metadata. Čtvrtým mušketýrem může být ještě IdP discovery, ale tu v našem případě nemáme.


Key manager

Všechny SAML zprávy, jež si IdP a SP vyměňují jsou podepsané privátním klíčem dané strany. Doporučuji mít pro SAML podpisový klíč separátní key store (nemíchat ho třeba s key storem, který potřebuje aplikační server pro HTTPS).

V naší ukázkové aplikaci je SAML key store na classpath - v jakémkoli jiném, než lokálním vývojovém prostředí, key store samozřejmě externalizujeme (nepřibalujeme do WARu) a hesla kryptujeme.


Podepisování SHA-256

V minulém díle jsem zmiňoval, že Spring SAML defaultně používá při podepisování algoritmus SHA-1, kdežto ADFS očekává SHA-256. Jedna strana se musí přizpůsobit. Doporučuji upravit aplikaci - použít SHA-256 není nic těžkého.

Výběr podpisového algoritmu se provádí při inicializaci SAMLu pomocí třídy SAMLBootstrap, která bohužel není konfigurovatelná. Pomůžeme si tak, že od třídy podědíme a potřebný algoritmus podstrčíme:

V konfiguraci pak třídu instancujeme následujícím způsobem. Mimochodem, povšimněte si, že beana je instancovaná jako static. To proto, aby inicializace proběhal velmi záhy při vytváření kontextu.


That's All Folks!

Tím se náš 3-dílný mini seriál o Spring Security, SAMLu a ADFS uzavírá. Samozřejmě, že bych mohl napsat ještě mnoho odstavců a nasdílet spoustu dalších gistů. Ale už by to bylo jen nošení housek do krámu.

Lepší bude, pokud si teď stáhnete ukázkový projekt sw-samuraj/blog-spring-security, trochu se povrtáte ve zdrojácích a na závěr v něm vyměníte soubor FederationMetadata.xml a zkusíte ho rozchodit vůči vašemu ADFS. Při troše štěstí by to mělo fungovat na první dobrou :-)

Jako bonus pro odvážné - pokud se opravdu pustíte do těch zdrojových kódů - můžete v historii projektu najít další Spring Security ukázky (je to celkem rozumně otagovaný):
  • Výměna CSRF tokenu mezi Springem a Wicketem (tag local-ldap).
  • Multiple HttpSecurity - v jedné aplikaci: autentikace uživatele přes formulář a mutual-autentication REST služeb přes certifikát (tag form-login).
  • Autentikace vůči lokálnímu (embedovanému) LDAPu (tag local-ldap).
  • Autentikace vůči Active Directory (tag remote-ad).

Související články


3 komentáře:

  1. Ahoj,

    myslim, ze SHA256 by melo byt by default v spring-security-saml

    Udelal jsem pull request, uvidime.

    https://github.com/spring-projects/spring-security-saml/pull/239

    OdpovědětVymazat
    Odpovědi
    1. Výborně! Doufám, že se to tam dostane. Už jsem s nimi taky něco řešil (vlastně verzi 1.0.3 vydali v podstatě pro mě :-) a bylo to celkem rychlé.

      Vymazat
  2. Ahoj,

    jak jsi resil, ze IDP metadata ziskane z ADFS jsou podepsane klicem.
    Pridavam ten klic manualne do keystoru, jinak dostanu chybu, ze neni mozny verifikovat podepsana IDP metadata z ADFS.

    Prijde mi zvlastni, ze ten klic je pribaleny do metadat...

    Zacinam mit vic konfiguraci pro ruzne skupiny uzivatelu a chtel bych nejak automatizovat manipulaci s klicema. Moc se mi nechce brat ten verejny klic na verifikaci podpisu metadat z toho vlastniho requestu.

    Muj plan je udelat gui pro manipulaci s klicema pro kazdou skupinu uzivatelu zvlast. Narazim na to, ze nevim jak ty klice pak pouzivat v spring security saml. Tam je k dispozici jen alias a nejsem schopnej si vybrat klic...
    Jak jsi resil manipulaci s klicema?

    Dalsi vec, ktera mi vadi je, ze po pridani noveho klice musim restartovat aplikaci, aby se klic znova nacetl.

    OdpovědětVymazat