22. února 2018

Jak se staví tým


Tenhle článek jsem chtěl napsat už několik let. Pořád jsem to odkládal s tím, že časem ještě získám víc zkušeností a tak to bude mít větší, komplexnější váhu. Že pořád na to bude jednou dost času. Ale tak to v životě nechodí... jednou přijde čas a uvědomíte si, že věci, která vás kdysi extrémně přitahovaly, vám najednou nic neříkají. A že pokud to neuděláte teď, tak už to neuděláte nikdy.

Přesně takovým obdobím teď procházím. Přičinil jsem se o zlom ve své kariéře a tak po 8 letech, kdy jsem dělal team leadera a souběžných 6 letech, kdy jsem se intenzivně věnoval technickému rekruitmentu, tyto dvě oblasti (dobrovolně) opouštím. A tak je tenhle článek jakýmsi rozloučením a předáním štafety.

Na začátku by měla být vize

Když dostanete možnost postavit nový tým, nebo třeba významně doplnit ten stávající, měli byste mít nějakou vizi, jak ten tým bude vypadat. Proč vize? Protože budování týmu nekončí přijímacím pohovorem. Nekončí ani po zkušební době, či úplném zapracování. Ono totiž nekončí nikdy - je to cesta, která je svým vlastním cílem. A proto potřebujete úběžník, ke kterému budete po celou dobu existence týmu směřovat.

Termín z perspektivy jsem si nevybral náhodou:
  • Vize i úběžník jsou virtuální entity, kterých v realitě nejde dosáhnout.
  • Vize i úběžník jsou "lehce pohyblivé cíle" - záleží na perspektivě, úhlu pohledu, času a pozorovateli.
  • O skutečném vývoji/postupu vypovídá historie - to když se ohlédnete zpět a uvidíte, jakou cestu jste urazili.
  • Existují nástroje, které vám ve složitem terénu pomůžou udržet směr.
Smutnou pravdou je, že většina teamleaderů a manažerů - pokud už si dali tu práci a takovou týmovou vizi si definovali - vám nebude schopna tuto vizi popsat. Samozřejmě, takový ty soft-skill/HR/people-management keci vám řekne každý. Ale to jsou jen newspeak keci.

Jestli mě Kanban něčemu naučil, tak "make policies explicit". Pro vizi to platí taky. Nemusíte ji s nikým sdílet. Ale sepište si to. Vyslovte to nahlas. Není to žádná magie, ale funguje to zázračně. Jinak budete po léta bloudit v pustinách. Vy i celý tým.

Přijímací pohovor

O (technických) přijímacích pohovorech jsem tady na blogu psal po léta. Ačkoliv to jsou, nijak překvapivě, ty nejčtenější články, jejich vliv byl minimální. Když jsem se po 5 letech vrátil na pracovní trh, byla to velmi tristní zkušenost.

Tak jako jsem v minulé sekci zdůrazňoval důležitost vize, pro pohovory platí to samé - nepokažte si to hned na začátku. Může vám v tom pomoci pár pravidel:
  • Buďte konzistentní. Všichni lidi v týmu by měli projít stejným procesem. (Ale udělejte výjimku, když to dává smysl.)
  • Udělejte technické kolo co nejbližší skutečné práci, kterou děláte. Tohle většině českých firem ještě nedošlo. Jste SW inženýři, dělejte věci racionálně a nedržte se bludných mýtů.
  • Nedělejte síto příliš úzké a husté. Nemáte ani představu, jak je život rozmanitý. Pravda, čím budete starší, tím méně věcí vás bude překvapovat. Ale stejně vždycky přijde něco, co jste nečekali (pokud jste před tím nezavřeli oči). Výjimkou z tohoto pravidla je, pokud jste si ve vizi definovali, že chcete postavit tým ze samých klonů tzv. ideálního kandidáta (mmch. to chce většina pražských firem).
  • Směřujte k vizi. Ptejte se: bude tenhle kandidát za 1/2 roku, za rok sedět do naší (týmové) vize?
 Neexistuje ideální pohovor. Pokud to s pohovorem myslíte vážně a neberete kohokoli z ulice, stojí za to se inspirovat u zkušených (článků je plný internet), něco seriózního si o tom přečíst a pracovat na tom a pohovor zlepšovat. Za sebe doporučuji třeba Esther Derby, Johanna Rothman, Gerald Weinberg, Andy Lester, či Michael Lopp (Rands in Repose).

Já jsem svůj způsob pohovorování vybrušoval pět let. Je to proces, který odpovídá mé vizi, takže pro někoho může být nevhodný. Některé věci jsou dokonce nepřenosné.

Pokud nevíte kde začít, zkuste 2-a-půl kolové schéma (obsah už si doplníte sami):
  • Phone screen. Krátký a jednoduchý technický filtr - má smysl se vidět tváří v tvář a strávit spolu víc času? (Pro inspiraci, jak jsem to dělal já.)
  • Technické kolo. Viz výše. A opět můžete nakouknout ke mně do kuchyně.
  • Netechnické kolo. Podívejte se na kandidáta i jinak, než přes technologie - není to robot. Pokud si později nebudete sedět, bude to spíš kvůli osobním, netechnickým kvalitám. Ale i tady platí "nedělejte síto příliš husté".

Neúprosná pohovorová statistika

Postavit dobrý tým je těžká makačka. Je to plnohodnotný (IT) projekt. Věc, kterou si členové vašeho týmu nejspíš nikdy neuvědomí (a spousta dalších lidí okolo), je, kolik je za tím práce, dát dohromady 5 až 10 lidí.

Po léta si vedu pohovorovou statistiku. Tady je jeden konkrétní, řekl bych průměrný rok:
  • Phone screen: celkově 46 pohovorů, z toho 33 postoupilo do dalšího kola (úspěšnost 72 %).
  • Technické interview: celkově 29 pohovorů, z toho 20 postoupilo do dalšího kola (úspěšnost 69 %).
  • Personální intervew: pro toto kolo nemám data (v grafu níže extrapoluji).
  • Do týmu nastoupilo 6 lidí. Trvalo to rok.
 
Statistika pohovorů


Ke statistice pár poznámek:
  • To že se lidi dostali na phone screen, znamená, že už byli minimálně profiltrovaný přes CV, buď interním HR, nebo agenturou. Tzn. že většinou už absolvovali headhunterský telefon. A samozřejmě prošli přes moje CV review.
  • Reálně do dalšího kola nastoupí méně kandidátů, než kolik jich bylo úspěšných (z různých důvodů nepokračují dál).
  • Interview byla během roku konzistentně rozvrstvena. Zhruba to znamená udělat za měsíc 4 phone screeny a 2-3 technická interview. A jednou za dva měsíce zapracovat nového člověka.
  • Počítejte, že ze všech lidí, kteří vám projdou pohovory, vám do týmu nastoupí cca 10 % z nich. I míň.
  • Povšimněte si poměrně vysoké úspěšnosti kandidátů v jednotlivých kolech. Domnívám se, že je to dáno tím, že jsem měl celý proces pod kontrolou a zůčastnil jsem se všech pohovorů (vyjma personálních interview). Pokud vám dělají interview různí lidé a nekonzistentně, bude neúspěšnost vyšší.

Zapracování

Fajn. Člověk vám nastoupil a dostal počítač a stravenky. Zpravidla bude nadšený a iniciativní. Neprošvihněte to! Samozřejmě, musí se naučit všechny ty procesy nástroje, projekty a produkty. Zaručeně tím ztráví celou zkušební dobu a velmi pravděpodobně celý úvodní semestr. Pokud je vaše doména složitá, může zapracování trvat i dva roky (true story).

Tohle období ubíhá tak nějak samo od sebe, samospádem. Možná to bude dost překotné. Ale nepodceňte to - je to první čas, kdy budete daného člověka opravdu poznávat. Jak pracuje, jak žije, jak se chová, jak na něj reagují ostatní (členové týmu)?

Je to jedinečné období, kdy můžete zasadit semínko kultury a pomáhat mu zakořenit a růst. Pomůžou vám v tom nástroje jako 1:1 a ochota naslouchat a řešit problémy.

Týmová kultura

Jakmile máte v týmu prvního člověka, je týmová kultura to nejdůležitější, o co byste měli jako team leadeři pečovat. Je otázka, jaká je konstelace a kolik na to budete mít reálně času. Ale pokud má tým zdravě funovat v následujících letech a překoná různé (personální, pracovní a další) krize, bude to díky živoucí kultuře. Pokud týmová kultura churaví, nebo dokonce umře (taky jsem to zažil), bude to jen o tom, jak přinést domů pytel peněz na kus žvance.

Každá kultura funguje na tom, že se lidé potkávají. Čím širší komunikační kanál, tím lepší (zdravější). Nejlépe osobně, když to nejde tak aspoň video, až pak telefon a úplně na konci instant messaging. Pokud si píšete už jen emailem, tak už vlastně nekomunikujete.

Mějte pravidelné týmové schůzky. Potkávejte se nad problémy, u jídla a (v rozumné míře) mimo práci.

Každá kultura, která se rozvíjí, má nějaké (samo)korektivní mechanizmy, historii a způsob zpracování zpětné vazby. V případě SW inženýrství máme skvělý a ozkoušený nástroj: týmové retrospektivy. Retrospektivy nemusí být jen o projektech a iteracích. Můžou mít zaměření i na tým a jeho kulturu.

Retrospektiva: team radar

Mít dobrou týmovou kulturu není nic zas až tak těžkého - chce to jen pár rutinních a pravidelných úkonů. Jako když pečujete o zahrádku. Když to zandedbáte, začne vám zvolna zarůstat plevelem. V určitý moment se může stát, že se vám zahrádka vylidní. Přeju, ať se to nestane.

Související články


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


17. ledna 2018

Spring Security, SAML & ADFS: Konfigurace

Minule jsme se podívali - z obecnějšího pohledu - jak SAML funguje pro autentikaci aplikace. Kromě toho, že byste měli znovu zkouknout ty pěkné barevné diagramy, zobrazující SSO (Single Sign-On) a SLO (Single Logout), by se vám mohl hodit SAML a ADFS slovníček - od teď už očekávám, že termíny máte našprtané ;-)

Tenhle článek se bude zaměřovat na konfiguraci potřebnou pro to, aby nám SAML autentikace fungovala. V realitě pak tato konfigurace půjde nejčastěji ruku v ruce s implementací, protože abyste získali SP (Service Provider) metadata, budete potřebovat ho mít už funkční (pokud nejste SAML-Superman, který to zvládne nabouchat ručně, nebo externím nástrojem).

Registrace metadat

Aby nám SAML fungoval, musíme nejdřív vzájemně zaregistrovat jednotlivé IdP (Identity Providery) a SP (Service Providery). Jak jsme si říkali v minlém díle, vztah IdP - SP může být M:N, nicméně pro zbytek článku (a i v tom následujícím) budeme uvažovat jenom vztah 1:1, tedy náš SP (aplikace) se autentikuje vůči jednomu IdP.

Registrace metadat se může provést dvojím způsobem - buď můžeme poskytnou URL, na kterém si IdP/SP metadata sám stáhne při svém startu, nebo (asi častější) metadata poskytneme jako statický soubor. Zde budeme pracovat s druhým případem.

Registrace (ADFS) Federation metadat

Registrace Federation Metadat je jednoduchá - stáhneme XML soubor z daného URL a protože pro implementaci SP používáme Spring Security SAML, poskytneme ho jako resource pro MetadataProvider.

Metadata na ADFS serveru najdeme na následujícím URL:

Federation Metadata je dlouhý, ošklivý XML soubor. Způsob, jak ho poskytnout naší aplikaci je trojí:
  • dát ho na classpath a načíst třídou ClasspathResource
  • dát ho na file systém a načíst třídou FilesystemResource
  • načíst ho přímo z ADFS třídou HttpResource

Pokud např. soubor FederationMetadata.xml umístíme do adresáře src/main/resource/metadata, můžeme ho načíst následujícím způsobem:


Pokud potřebujete trochu víc (Spring) kontextu, může se podívat do kompletní Spring SAML konfigurace:

Registrace (Spring) SAML metadat

Registraci SAML metadat na ADFS si rozdělíme do dvou kroků:
  • Získání metadat z aplikace.
  • Registraci metadat na ADFS.

Generování SAML metadat (z aplikace)

Tady přichází ke slovu, co jsem předesílal - abyste byli schopný si vygenerovat SAML metadata, budete potřebovat mít Spring SAML aspoň částečně naimplementovaný. O generování metadat se stará Springovský filtr MetadataGeneratorFilter.

Generování metadat out-of-the-box funguje dobře (a s ADFS ho rozchodíte). Pokud chcete, nebo musíte metadata upravit, tohle je to správné místo. Například specifické (SP) Entity ID se dá nastavit tímto způsobem:


Filter pak necháme naslouchat na určitém URL endpointu, kde nám bude metadata poslušně generovat:


Situace je samozřejmě trochu složitější, takže pokud jste netrpělivý, nebo vám chybí potřebné Spring beany, nahlídněte do zmiňované SecurityConfiguration.java.

Ještě než si metadata vygenerujete a stáhnete z daného URL, jedno důležité upozornění! Při nesplnění následujících podmínek vám SAML před ADFS nebude fungovat.
  • Na URL musíte přistoupit přes HTTPS (a mít tedy odpovídajícím způsobem nakonfigurovaný aplikační server/servlet kontejner).
  • Na URL musíte přistoupit přes hostname nebo IP adresu, které jsou z IdP (ADFS) viditelné. (Takže ne https://localhost.)

Registrace metadat na ADFS

Teď se magicky přenesema na ADFS server (typicky přes Remote Desktop), kam si zkopírujeme vygeneraovaný SAML metadata soubor. Spring ho defaultně nazývá spring_saml_metadata.xml, nicméně na jméně nezáleží.

V AD FS Management konzoli nás bude zajímat jediná věc - položka Relying Party Trust, kde metadata našeho SP zaregistrujeme, resp. naimportujeme.

AD FS Management konzole

Import metadat se provádí pomocí wizardu (jak jinak ve Windows). Je to jednoduché a přímočaré: zadáme import ze souboru a pak už se jen doklikáme nakonec:

Import SP metadat ze souboru

V závěrečném shrnutí je dobré si zkontrolovat, že v sekci Endpoints jsou splněny dvě výše uvedené podmínky (HTTPS a hostname/IP adresa):

Kontrolní shrnutí SP endpointů

ADFS defaultně očekává, že hash algoritmus použitý při podepisování SAML zpráv bude SHA-256. Bohužel, Spring SAML posílá out-of-the-box SHA-1. Máte tedy dvě možnosti:
  • Upravit Spring SAML, aby používal SHA-256 (jak to ohackovat vám prozradím příště),
  • nebo říct ADFS, aby očekávalo SHA-1.

Nastavení Secure hash algorithm najdete po rozkliknutí Properties na záložce Advanced (je potřeba to udělat dodatečně - při importu metadat je tato volba nefunkční):

Nastavení Secure hash algorithm

Pokud si to na obou stranách nesladíte, budete na straně Springu dostávat nic neříkající výjimku:
2018-01-17 12:15:01 DEBUG org.springframework.security.saml.SAMLProcessingFilter - Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
        at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100) ~[spring-security-saml2-core-1.0.3.RELEASE.jar:1.0.3.RELEASE]
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) ~[spring-security-core-5.0.0.RELEASE.jar:5.0.0.RELEASE]
Caused by: org.opensaml.common.SAMLException: Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:Responder, status message is null
        at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:113) ~[spring-security-saml2-core-1.0.3.RELEASE.jar:1.0.3.RELEASE]
        at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87) ~[spring-security-saml2-core-1.0.3.RELEASE.jar:1.0.3.RELEASE]

A na straně ADFS nápomocnější:
Microsoft.IdentityServer.Protocols.Saml.SamlProtocolSignatureAlgorithmMismatchException:
    MSIS7093: The message is not signed with expected signature algorithm.
    Message is signed with signature algorithm http://www.w3.org/2000/09/xmldsig#rsa-sha1.
    Expected signature algorithm http://www.w3.org/2001/04/xmldsig-more#rsa-sha256.
Takže, prozatím SHA-1. "Dvě stě padesát šestka" bude příště ;-)

Claim Rules

Poslední věc, kterou zbývá nastavit je mapování claims na assertions. Na naší nově vytvořené Relying Party Trust dáme Edit Claim Rules... a přidáme následující pravidlo, které nám z Active Directory vytáhne Name ID a doménové skupiny daného uživatele:

Editace Claim Rules

To be continued...

Tak a máme hotovo! Teda konfiguraci. Ovšem, jak už jsem naznačoval, v tento moment už stejně většinou máte hotovou i zbývající implementaci, takže pokud jsme nic neopomněli, mělo by nám fungovat jak SSO, tak SLO, přesně podlě těch krásných diagramů z minulého dílu.

V příštím, závěrečném díle, se podíváme, jak nabastlit zbytek Springovských věcí - můžete se těšit na Java konfiguraci (což je zatím vzácnost, protože Reference Documentation stále jede na XML) a samozřejmě pofrčíme na aktuálním Spring 5 (Cože?!? Vy jedete ještě na čtyřce?! No, nekecej 8-)

20. prosince 2017

Spring Security, SAML & ADFS: Úvod

Posledních pár týdnů jsem se teď mordoval se Spring Security, abych v grandiózním finále doiteroval k autentikaci pomocí SAML vůči ADFS.

Mimochodem, přijde mi, že poslední dobou, je to se Springem, jako s jakoukoliv jinou (velkou) dominantní značkou - pokud se pohybujete uvnitř dané domény, na vyhrazeném dvorečku, všechno frčí, jak na drátkách. Jakmile to zkusíte zintegrovat s něčím ne-nativním, začnou probémy. A rozlousknout ty problémy chvilku trvá - zvlášť, když StackOverflow mlčí a oficiální dokumentace se k (technologickým) cizincům moc nezná.

Ale to jsem odbočil, zpátky k tématu. Tentokrát se nebudu věnovat ani aktuálnímu use casu, ani těm problémům, ale zaměřím se jen na to, jak Springovský SAML s ADFS funguje a jak to v aplikaci naimplementovat a celkově nakonfigurovat.

Nicméně, pokud jste se ještě stále nechytli, o čem to mluvím a přemýšlíte, jestli číst dál, tak to bude o: lehce komplikované autentikaci webové aplikace oproti Active Directory (takový Microsoftí LDAP).

SAML slovníček

Neuškodí si trochu prosvištět názvosloví. I když SAML nepřináší nic moc převratného, přeci jenom říká určitým věcem svým vlastním způsobem.
  • SAML - Security Assertion Markup Language
  • User Agent (UA) - software, skrz který uživatel komunikuje se zabezpečeným zdrojem, typicky browser.
  • Service Provider (SP) - systém, který poskytuje zabezpečený zdroj a akceptuje authentication assertions a poskytuje Single Sign-On (viz následující body).
  • Identity Provider (IdP) - systém, který vydává authentication assertions a podporuje Single Sign-On.
  • SAML Assertions - assertions jsou gró SAML zpráv, které lítají mezi SP a IdP. Obsahují bezpečnostní informaci/e trojího typu: authentication statements, attribute statements a authorization decision statements. Nás budou zajímat první dva typy: jestli je uživatel autentikovaný a do jakých Active Directory skupin patří.
  • Single Sign-On (SSO) - přihlášení uživatele do více systémů jedinou akcí.
  • Single Logout (SLO) - odhlášení uživatele z více systémů jedinou akcí.
  •  SAML Metadata - XML data formát pro popis specifického SAML deploymentu, tedy SP nebo IdP.

ADFS slovníček

I ADFS má vlastní okruh termínů:
  • ADFS - Active Directory Federation Services
  • Claims - prohlášení týkající se uživatelů, které se primárně používá pro autorizaci přístupu k aplikacím. Claims jsou to, co potřebujeme dostat do SAML assertions jako attribute statements.
  • Claims Provider - systém, který poskytuje claims.
  • Relying Party Trust - partnerský systém, který zpracovává claims a kterému ADFS důvěřuje.
  • Federation Metadata - XML data formát pro výměnu konfigurace mezi Claims Providerem a Relying Party Trust.

SAML Binding

Následující popis SSO a SLO je poměrně detailní (musím se pochválit, že podrobnější jsem nevygoogloval) a je zaměřený na jednu konkrétní technologickou integraci - Spring Security SAML a ADFS. To znamená, že pro jiné konstelace to může fungovat "trošku" jinak.

Rovněž stojí za zmínku, že SAML specifikace definuje tzv. binding, tj. jak jsou SAML requesty a responsy mapovány na standardní message a komunikační protokoly. Pro SSO v browseru se většinou společně používají HTTP Redirect Binding a HTTP POST Binding. V následujících diagramech byste je měli bez problémů identifikovat. Co je podstatné - u tohoto druhu bindingu teče veškerá komunikace přes User Agent (browser), takže tam např. není žádná komunikace na pozadí mezi SP a IdP.

SAML Single Sign-On

Na následujícím obrázku jsem si dal hodně záležet a věřím, že jeho vysvětlující a informační hodnota je enormní, podaná krystalicky čistým způsobem. Přesto si neodpustím kratičké shrnutí:
  1. Browser (UA) přistoupí na chráněný zdroj na Service Providerovi (SP), který přesměruje UA na svoje login URL.
  2. SP vygeneruje SAML request a přesměruje UA na Identity Providera (IdP), kterému je předán SAML request.
  3. IdP vrátí UA přihlašovací formulář (jméno, heslo).
  4. UA pošle IdP credentials uživatele, spolu se SAML requestem.
  5. IdP předá credentials Claims Providerovi (CP), který ověří uživatele a v případě úspěchu vrátí před-konfigurované claims.
  6. IdP přebalí claims do assertions, které obalí do SAML response a tu pak vloží do HTML formuláře, který pošle UA. Součástí formuláře je i JavaScript, který může formulář automaticky odeslat.
  7. UA automaticky odešle formulář se SAML response na SP. V případě, že je v UA vypnutý JavaScript, musí uživatel odeslat formulář klepnutím na tlačítko.
  8. SP ověří přijaté SAML assertions a pokud je všechno v pořádku, přesměruje UA na původně vyžádaný zdroj.

SAML Single Sign-On

Uvedené schéma zobrazuje komunikaci pro ne-autentikovaného uživatele. V případě, že je uživatel již přihlášen - ať už lokálně na daném SP, nebo díky SSO na jakémkoliv jiném SP (který je registrován u daného IdP) - tak se přeskočí posílání a odesílání ADFS login formuláře (a samozřejmě komunikace s CP) a UA rovnou obdrží SAML response.

IdP Discovery

Uvedený scénář se dá zpestřit ještě o jednu věc. Vztah mezi SP a IdP je m:n
  • jeden IdP může obsluhovat několik SP a stejně tak
  • jeden SP si může vybrat z několika IdP.
V prvním případě se nic zvláštního neděje, právě od toho tu je SSO. V druhém případě je to trochu komplikovanější - jak si UA/SP vybere, vůči kterému IdP se autentikovat?

Tenhle případ řeší IdP Discovery. Místo úvodního přesměrování na login URL aktuálního SP dojde k přesměrování na stránku se seznamem všech zaregistrovaných IdP, z nichž si uživatel explicitně vybere.

Nastavit IdP Discovery pomocí Spring Security SAML není nijak složité, nicméně pro tento a následující články s touto možností nepracuji.

SAML Single Logout

Když jsem se pustil do kreslení předešlého diagramu pro SSO, tak se mi výsledek tak zalíbil, že jsem si střihnul ještě jeden obrázek - pro Single Logout (SLO).

A aby to nebylo triviální, tak jsem si rozchodil dva SP, abych mohl zdokumentovat, jak probíhá odhlášení ze všech zaregistrovaných SP. Protože o tom SLO je: když se odhlásím na jednom SP, tak mě to automaticky odhlásí i ze všech ostatních SP.

SAML Single Logout

To be continued...

Abych udržel článek v rozumné čitelnosti, rozhodl jsem se téma rozdělit do krátkého mini-seriálku. Příště bych se podíval, jak vyměnit metadata mezi SP a IdP, plus jak nakonfigurovat ADFS.

V závěrečném díle bych probral konfiguraci Spring Security SAML. Můžete se těšit na popis Java configuration (ofiko dokumentace jede furt na XML) a samozřejmě to pofrčí na aktuálním Spring 5.

Související články


4. prosince 2017

Nešvary logování

Co se týká softwarového vývoje, logování je jedna z nejvíce zanedbávaných oblastí. Samozřejmě, pokud nejde o něco naprosto amatérského, tak je logování v každé aplikaci. Stejně tak, aby člověk pohledal vývojáře, který si během programování nevypisuje na konzoli potřebné runtime informace.

A bohužel, tak jako každý Javista má v CV napsaný Maven, i když umí jen naimportovat projekt do IDE a z příkazové řádky spustit mvn clean install; tak všichni o sto šest logují: chaoticky, nekonzistentně, bez vize, bez přemýšlení. A občas jsou ty logy dost odpudivé smetiště.

Tenhle pocit se ve mně hromadí léta letoucí. A jelikož jsem teď musel refaktorovat pár špatně designovaných a zanedbaných aplikací, rozhodl jsem se k tomu sepsat pár postřehů.

Obecný vývojářský přístup

To, jak se tým chová k logování se dá obvykle shrnout do tří axiomů:
  • Vývojáři si ad hoc logují to, co momentálně potřebují během vývoje aktuální feature. Co se jednou vloží do zdrojáků, to už tam na věky zůstane.
  • Operations/Support si stěžují, že v produkčním logu nejsou relevantní informace, zato spoustu balastu.
  • Kromě kavárenského stěžování si, s tím nikdo nic nedělá.

Situaci může drobně zlepšit, pokud má zákazník, nebo produktový tým definovanou nějakou explicitní logging policy. Daleko častější ale je, že politika logování je buď vágní, nebo žádná. Dá se to popsat i tak, že chybí vize a kontrola, jak logování provádět a používat.

Za dané situace, jsou největšími "viníky" vývojáři, protože jsou to právě oni, kdo do kódu logovací zprávy zanášejí, stejně tak jako je na jejich libovůli jakou severitu zprávám nastaví. Záleží na kontextu, ale někdy/často(?) existuje dokonce "logovací super-padouch"... technical leader, který tuto oblast buď zanedbává, nebo rovnou ignoruje. Je to nejspíš on, kdo by měl způsob logování definovat a kontrolovat.

Ponechme však stranou analýzu "kdo za to může" a pojďme se podívat, jak se špatné logování projevuje.

Špatný mindset

Již jsem naznačil, že za špatný stav logování můžou většinou vývojáři. To není nic překvapivého - jedním ze základních znaků echt vývojáře je, že trpí chronickým tunelovým viděním. U logování se to projevuje tak, že programátoři nepřemýšlí, co se s aplikací stane, jakmile opustí jejich vývojové prostředí.

Ačkoliv aplikace poběží roky na produkci, tak většina logování reflektuje relativně krátkou vývojovou fázi.

Chybějící konvence a postupy

Tohle je obecný problém, který se vyskytne kdykoli mají lidé volnost v zápisu textu zprávy. Kromě logování jsou to typicky commit komentáře. Číst historii je pak (masochistický) požitek, kdy člověk, jako archeolog, prozkoumává hranice lidské kreativity.

"Všechno je relativní", tak proč ne úrovně logování? Každý vývojář dokáže sám, subjektivně a správně posoudit, jaká má být pro danou zprávu severita logování. Trace/Debug/Info, vždyť se to na produkci odfiltruje, tak co?

Co takhle zmapovat flow nějaké entity, jak prochází procesem a systémem? Někdy jo, někdy ne, někdy tohle ID, jindy tamto. Stejně je to všechno "Request ID", bez ohledu na počet requestů, vrstev a systémů. Anebo radši "Session ID", co na tom, že je to bezstavový? "Korelační" je sprosté a zakázané slovo. A vůbec, aby to někdo pochopil, musí na tom pár týdnů/měsíců dělat, takže je jedno, jak se to bude jmenovat.

Nesmyslné logování v testech

Když spustíte testy, viděli byste na konzoli radši takovýhle výpis?
:clean
:compileJava
:processResources
:classes
:compileTestJava
:processTestResources
:testClasses
:test

BUILD SUCCESSFUL in 42s
6 actionable tasks: 6 executed

Nebo byste raději viděli 20 obrazovek balastu, který lítá z logů Hibernate a Spring testů? Předešlý výpis tam samozřejmě bude geniálně ukrytý jak hrst jehel v kupce sena.

Přitom pomoc je triviální - vypněte pro testy logování:


Výpisy na konzoli

Kdo by si čas od času nezahřešil starým dobrým:
System.out.println("Bla bla");
Výpisy na konzoli do logu nepatří. Ani když je to v testech. Samozřejmě, záleží na nastavení vašeho logovacího frameworku - někdy jsou výpisy na sdtout přešměrovaný do logu, někdy ne. Používat by se ale neměly (téměř) nikdy.

Jedinou výjimkou by mohlo být, pokud píšete CLI aplikaci. Ale i tam bych zvážil, jestli místo println nepoužívat logování s vhodným formátem a severitou zprávy. Minimálně to půjde vypnout v testech.

Dedikovaný logger z interního frameworku

Zažili jste někdy, že by si firma vyvíjela vlastní framework? Já už jsem si tím párkrát prošel. Možná jsem jen neměl štěstí... ale pokaždé to byl průser - tam kde vám to 1/3 práce ušetřilo, tam vám to později 2/3 práce přidalo. K internímu frameworku samozřejmě patří custom logger. Jinak by to nebylo ono.

Ona je to vlastně dobrá myšlenka - některé z výše zmíněných problémů by se daly takovým speciálním loggerem podchytit. Bohužel, v realitě to bylo stejně úspešný jak implementace Scrumu v kovaným enterprise-korporátním prostředí. No, možná jsem jen neměl štěstí.

Zapomeňte na custom/interní/proprietární loggery! Vykašlete se na to a použijte vanilla logování svého srdce.

Jak z toho ven?

Tak jako na dovolený poznáte na hned první pohled rozdíl mezi rozvinutou a rozvojovou zemí, tak u funkčních aplikací poznáte, jestli někdo přemýšlel i kousek za kompilaci kódů. Pročetli jste si někdy logovací zprávy když vám startuje čistý aplikační server, nebo rozumný buildovací nástroj (ne, Maven to není)?

Zkuste někdy taky psát takové pěkné logy. Chce to jenom:
  • Mít vizi, jak má logování vypadat.
  • Dělat code review.
  • Čas od času udělat na logování audit.

Jaký je váš oblíbený logovací nešvar?

13. listopadu 2017

vimdiff, nástroj drsňáků


Musím se vám k něčemu přiznat... Už patnáct let je Vim můj nejoblíbenější textový editor. A občas, čas od času, i hlavní nástroj na programování.

Umím si poeditovat vimrc, který po léta udržuju a vylepšuju. Dokonce jsem se i naučil trochu Vim script/VimL a napsal dva zanedbatelné a nedotažené pluginy (pro Gradle a WSDL).

Ale vždycky jsem se jako čert kříži vyhýbal jedné věci - používání vimdiff. Nicméně na každého jednou dojde. Z určitých (pro článek nepodstatných) důvodů jsem si nemohl pro nové vývojové prostředí nastavit P4Merge a tak jsem vstoupil do zapovězené komnaty.

Disclaimer: Tenhle článek píšu jako shrnutí toho, jak jsem práci s vimdiff pochopil. Pokud máte víc zkušeností, budu rád, když se podělíte v komentářích.

2-way merge

Nejjednodušší způsob, jak používat vimdiff - pokud pomineme, že umí dělat i "plain old" diff - je 2-way merge: máme vedle sebe dvě okna se zvýrazněnými rozdíly a chceme mezi nimi tyto změny propagovat.

vimdiff, 2-way merge

Stav na předešlém obrázku, který je výchozí pro merge, se dá dosáhnout několika způsoby:
  • Příkazem: vimdiff myFile.txt theirFile.txt
  • Příkazem: vim -d myFile.txt theirFile.txt
  • Kombinací příkazů:
    • vim myFile.txt
    • :diffsplit theirFile.txt
  • Kombinací příkazů
    • vim -O myFile.txt theirFile.txt (vsplit obou souborů)
    • :diffthis (zapne diff na aktuálním bufferu)
    • Ctrl-W Ctrl-W (skok do druhého bufferu)
    • :diffthis(zapne diff v druhém bufferu)

Základní příkazy

Tak, diff máme zobrazený, co s ním? První věc - je potřeba se v diffu umět pohybovat. Kromě toho, že můžete použít jakýkoli skok, který znáte z běžného Vimu, jsou tu dva příkazy, které umožňují skákat po jednotlivých rozdílech:
  • ]c skočí na následující diff
  • [c skočí na předcházející diff

Za druhé - chceme propagovat změny z/do aktuálního bufferu: skočíme na diff, který chceme upravit a:
  • do, nebo :diffget natáhne změny z "druhého" bufferu do toho aktuálního.
  • dp, nebo :diffput propaguje změny z aktuálního bufferu do "toho druhého".

Za třetí - změny uložíme. Kromě příkazů na standardní ukládání (:w, ZZ atd.) se může hodit:
  • :only zavře všechny ostatní buffery kromě toho aktuálního
  • :qall zavře všechny otevřené buffery
  • :only | wq zavře ostatní buffery + uloží stávající + ukončí Vim. Cool!

Eventuálně začtvrté - pokud věci nejdou hladce, může se šiknout:
  • :diffupdate znovu proskenuje a překreslí rozdíly (u komplikovanějších mergů nemusí Vim správně pochopit danou změnu)
  • :set wrap nastavení zalamování řádků (hodí se při velmi dlouhých řádcích, typicky některá XML)
  • zo/zc otevře/zavře skryté (folded) řádky

3-way merge

Nemusím vám říkat, že 2-way merge je pro školáky - profíci makaj v Gitu, či v Mercurialu a tam je dvoucestný merge nedostačující. Ke slovu přichází 3-way merge. Co to je?

Schéma 3-way merge

3-way merge není nic složitého. V podstatě jde o to, že máme dvě verze, které mají společného předka. V mergovacím nástroji pak vidíme všechny tři verze vedle sebe a většinou máme k dispozici ještě čtvrté okno s aktuálním výsledkem merge.

3-way merge v aplikaci


Nastavení Gitu

Nastavení spolupráce Gitu a vimdiff je jednoduché - stačí spustit z příkazové řádky následující sadu příkazů:
$ git config --global merge.tool vimdiff
$ git config --global merge.conflictstyle diff3
$ git config --global mergetool.prompt false
$ git config --global mergetool.keepBackup false

Pokud se podíváte do ~/.gitconfig, měli byste tam vidět:


Nastavení Mercurialu

Nastavení Mercurialu je podobně jednoduché. Otevřeme soubor ~/.hgrc příkazem
$ hg config --edit
a vložíme následující řádky


Sekce [extensions] a [extdiff] nejsou pro merge nutné, ale hodí se, pokud chceme vimdiff používat jako dodatečný externí diff nástroj. Sekundární diff spustíme příkazem hg vimdiff.

Základní příkazy

Základní příkazy jsou stejné jako v sekci 2-way merge, s výjimkou příkazů dp/do (:diffput/:diffget) - pokud bychom je nyní použili, vimdiff nám zahlásí chybu:
More than two buffers in diff mode, don't know which one to use
To je v pořádku: u 3-way merge se ve vimdiff otevřou 4 buffery, všechny v diff módu. Takže do té doby, než se vimdiff naučí komunikovat telepaticky, je potřeba mu říct, ze kterého bufferu chceme danou změnu natáhnout.

vimdiff, 3-way merge v Gitu

Klasické merge flow vypadá následovně:
  1. Začínáme v dolním "výsledkovém" bufferu.
  2. ]c (skočit na následující diff, který chceme mergovat)
  3. :diffget <identifikace-bufferu> získáme změnu z daného bufferu (viz dále)
  4. Opakujeme 2-3.
  5. :only | wq uložíme merge.

Obecně, identifikátor bufferu získáme příkazem :ls. To je ale dost nepraktické a nepřehledné. Další možnost je identifikovat buffer částečným názvem souboru. Tady přichází na pomoc jak Git, tak Mercurial, který přidávají k názvům souborů příhodný suffix.

Merge v Gitu

Git přidává do názvů mergovaných souborů následující suffixy, v pořadí zleva doprava: LOCAL (vlevo), BASE (uprostřed), REMOTE (vpravo). Pro natažení změny z (levého) bufferu LOCAL můžeme použít příkaz :diffg LO.

Výpis bufferů pro Git:
:ls
  1 #a   "./myFile_LOCAL_7424.txt"      line 1
  2  a   "./myFile_BASE_7424.txt"       line 0
  3  a   "./myFile_REMOTE_7424.txt"     line 0
  4 %a   "myFile.txt"                   line 12

Merge v Mercurialu


vimdiff, 3-way merge v Mercurialu

Mercurial přidává do názvů mergovaných souborů následující suffixy, v pořadí zleva doprava: orig (vlevo), base (uprostřed), other (vpravo). Pro natažení změny z (levého) bufferu orig můžeme použít příkaz :diffg orig.

Výpis bufferů pro Mercurial:
:ls
  1 %a   "myFile.txt"                   line 2
  2  a-  "myFile.txt.orig"              line 0
  3  a-  "/tmp/myFile.txt~base.iZwwuA"  line 0
  4  a-  "/tmp/myFile.txt~other.km9Itr" line 0

Co mi (zatím) schází?

Musím říct, že potom, co jsem si vimdiff osahal, pochopil jeho logiku a naučil se jeho příkazy, jsem si ho docela oblíbil.

Jediná výtka zatím jde za jeho neschopností skákat přímo po konfliktech - Git i Mercurial dělají výborně automatické merge a ty jsou samozřejmě vidět ve vimdiffu taky, jako pouhá změna bez konfliktu. Mít nějaký příkaz, který rozlišuje pouhý diff a konflikt, by bylo fajn.

Související články


1. listopadu 2017

Trampoty s JUnit 5

Poslední dobou jsem nepsal moc unit testy... v Javě. Jednak jsem posledního půl roku hodně prototypoval - a tam moc testů nenapíšete - a když už jsem testy psal, tak to bylo převážně ve Scale, nebo v Clojure.

Teď ale naše firma projevila sklony k evoluci, se snahou trochu více zautomatizovat vytváření prostředí a zakládání projektů. Sice to jde mimo mě, ale když jsem byl požádán, ať napíšu testovací projekty v Javě pro Gradle a Maven, chopil jsem se příležitosti a ponořil se do (povrchního) studia JUnit 5.

Vyznání

Obecně musím říct, že pro JUnit mám slabost - začal jsem ho používat na začátku své Java kariéry ve verzi 4.2 (pro pamětníky únor 2007) a tak vlastně celý můj Java-produktivní věk jsem strávil se čtyřkovou verzí. Naučilo mě to hodně - za to, že jsem dnes takový skvělý programátor (ha, ha, ha) vděčím tomu, že mě unit testy naučily psát dobrý design.

Samozřejmě jsem si k tomu občas něco přibral. Už v roce 2008 jsem si mistrně osvojil (tehdy progresivní) jMock 2 a naplno se oddával neřesti BDD. Taktéž TestNG jsem si na pár projektech zkusil. Ale gravitační síla tradičního JUnit a TDD mě vždy přivedla zpátky.

A teď zažívám něco jako déjà vu. Je to podobný, jako když přišla Java 5 - skoro všechny nástroje s tím mají menší nebo větší problém. Java komunita to ještě moc neadaptovala. Když narazíte na problém, StackOverflow často nepomůže. Atd.


Pár aktuálních problémů JUnit 5 se mi podařilo vyřešit ke své spokojenosti. Tady je máte na stříbrném podnose.

Zadání

Zadání, které jsem dostal, bylo triviální - napsat miniaturní Java projekt, buildovatelný Gradlem a Mavenem, který bude mít unit testy. Projekt se bude buildovat na Jenkinsu, potřebuje změřit pokrytí testy pomocí JaCoCo a projít statickou analýzou kódu na SonarQube.

Jak říkám, bylo by to triviální, kdybych si pro testy nevybral JUnit 5.

Gradle

Odpírači pokroku a milovníci XML se mnou nebudou souhlasit, ale já považuju Gradle za základ moderní automatizace na JVM. Včetně (a primárně) buildů. Jak tedy zkrotit Gradle, aby se kamarádil s JUnit 5?

Zatím jsem se v tom nějak moc nevrtal, pač nemám ambice se stát JUnit 5 guru, jen potřebuju běžící testy. Ale je dobré vědět, že:
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage (JUnit 5 User Guide)
JUnit Vintage je pro JUnit 4, což nás dnes nezajímá. Zbývá tedy JUnit Platform pro spouštění unit testů a JUnit Jupiter pro samotné psaní testů.

Protože JUnit 5 změnilo pravidla hry, nestačí do Gradlu jenom přidat závislosti - současný Gradle novým unit testům nerozumí a zůstaly by nepovšimnuty. Naštěstí je k dispozici je nový plugin, který přidá do build life-cyclu nový task junitPlatformTest a který umí testy spustit.

Bohužel, plugin ještě pořád není dostupný na Gradle Plugins Portal, ale jen v Maven Central. Tím pádem se zatím nedá použít Plugins DSL :-(

V následujícím minimalistickém Gradle skriptu si povšimněte různých konfigurací pro jednotlivé závislosti:
  • testCompile pro api
  • testRuntime pro engine.


Závislost apigurdian-api je optional a je tam jenom proto, aby se ve výstupu nevypisovalo varování:
warning: unknown enum constant Status.STABLE
    reason: class file for org.apiguardian.api.API$Status not found

Task juPlTe je "zahákovaný" na standardní test task, který se dá použít také.

Spuštění JUnit 5 testů Gradlem

Jedna z killer feature Gradlu je incremental build - pokud nešáhnete na produkční kód, nebo na testy, Gradle testy nespouští. Je prostě chytrej ;-)

Gradle incremental build přeskočí testy, pokukd se kód nezměnil


Maven

Tradicionalisti milují Maven a protože jsem shovívavý lidumil, podělím se i o toto nastavení. Pro Maven platí totéž, co pro Gradle:
  • nový plugin (přesněji Surfire provider)
  • závislost na api a engine v různém scopu


Velký rozdíl mezi Mavenem a Gradlem je, že Maven incremental build (moc dobře) neumí - tupě spouští testy, kdykoliv mu řeknete.

Spuštění JUnit 5 testů Gradlem


JaCoCo pokrytí testy

Zbuildovat a spustit JUnit 5 testy byla ta jednodušší část. S čím jsem se trochu potrápil a chvilku jsem to ladil, bylo pokrytí testy. Vybral jsem JaCoCo, protože mi vždycky přišlo progresivnější, než Cobertura (jen takový pocit, či preference).

Dále budu uvádět jen nastavení pro Gradle, protože Maven je hrozně ukecaný. Pokud vás ale Maven (ještě pořád) zajímá, podívejte se do pom.xml v projektové repository.

Zkrácená JaCoCo konfigurace vypadá takto:


V předešlém výpisu jsou podstatné tři věci: (1) generování JaCoCo destination file je svázáno s taskem junitPlatformTest. (2) Definujeme název destination file. Název může být libovolný, ale aby fungovalo generování JaCoCo reportů, je potřeba, aby se soubor jmenoval test.exec. A za (3), pokud chceme některé soubory z reportu exkludovat, dá se to udělat trochu obskurně přes life-cycle metodu afterEvaluate. (Tohle by chtělo ještě doladit.)

JaCoCo pokrytí testy


SonarQube statická analýza

Sonar vlastně s JUnit nesouvisí. Pokrytí testy už máme přece vyřešeno. No, uvádím to proto, že opět je potřeba jít tomu štěstíčku trochu naproti.

Zkrácená verze Sonar konfigurace je následující (Maven opět hledejte v repo):


Tady jsou důležité dvě věci: (1) říct Sonaru, kde má hledat coverage report (klíč sonar.jacoco.reportPath) a za (2) naznačit, co má Sonar z coverage ignorovat (sonar.coverage.exclusions) - bohužel, JaCoCo exkluduje jenom z reportu, v destination file je všechno a tak to Sonaru musíte říct ještě jednou.

SonarQube statická analýza


Má smysl migrovat?

Jak je vidět, popsal jsem spoustu papíru, není to úplně easy peasy. A tak se nabízí hamletovská otázka: má smysl upgradovat z JUnit 4 na verzi 5?


Výše už jsem zmínil velmi přesnou analogii s Javou 5. Tehdy šlo hlavně o anotace a generické kolekce. Můj povrchní dojem je, že u JUnit 5 může být tahákem Java 8 (na nižších verzích Javy to neběží), takže primárně lambdy a streamy.

Pokud máte stávající code base slušně pokrytou pomocí JUnit 4, tak se migrace nevyplatí. Protože ale JUnit 5 umí (pomocí JUnitPlatform runneru) spouštět obě verze simultánně, je možné na verzi 5 přecházet inkremenálně.

Projekt repository

Na Bitbucket jsem nahrál repozitory jednoduchého projektu, kde si můžete v Gradlu a v Mavenu spustit JUnit 5 testy, vygenerovat JaCoCo report a publikovat výsledek do SonarQube.