Självständigt arbete på grundnivå Independent degree project - first cycle Datorteknik Computer science Inloggning Lösenordskryptering och Brute force attack Emil Strandberg Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg MITTUNIVERSITETET Programvaruteknik Examinator: Ulf Jennehag, [email protected] Handledare: Börje Hansson, [email protected] Författare: Emil Strandberg, [email protected] Utbildningsprogram: Programvaruteknik, 180 hp Huvudområde: Datateknik Termin, år: VT, 2015 ii 2015-06-16 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Sammanfattning Denna rapport är resultatet av en deluppgift i ett större projekt att skapa en plattform för undervisning av matematik. Uppgiften fokuserar på inloggning med tillhörande säkerhet. Projektets miljö är Java EE 6 med Glassfish 4.0 som server. Projektet har delats upp i tre underkategorier; Lösenordskryptering, Java EE inloggning och Brute force attacks. Lösenordskrypterings delen fokuserar på att undersöka olika hashfunktioners exekveringshastighet, resultatet visar att ingen av de algoritmer som undersöks lämpar sig att användas direkt. Istället rekommenderas system som PBKDF2 med SALT för att kryptera lösenord. Java EE avsnittet konstruerar en fungerande applikation där användare kan registrera sig och logga in med mera. Arbetet utförs som en studie av vilka säkerhetsverktyg som finns tillgängliga i Java EE. Resultatet uppfyller kravspecifikationen och ett avsnitt om Java EEs verktyg presenteras. Brute force attack-avsnittet är en teoretisk studie av vad som kan göras för att skydda sig mot Brute force attacker. Resultatet visar att robotfilter inte är rekommenderat av OWASP och ett förslag på ett system som använder kakor och en form av användarblockering presenteras. De olika delarna är separerade så långt som möjligt genom rapporten med undantaget att resultatet av lösenordskrypterings avsnittet tillämpas i Java EE applikationen. Nyckelord: Säkerhet i Java EE, Auktorisering, Autentisering, Lösenordskryptering -hashning, Brute force attack iii Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Abstract This report is the result of a sub-project of a larger project to create a platform for mathematical education. The sub-project focuses on authentication with associated security, where security is emphasized. The project environment is Java EE 6 where GlassFish 4.0 acts as the server. The project has been divided into three parts; password encryption, Java EE authentication and brute force attack. The password encryption part focuses on examining different hash functions execution speed, the result shows that none of the examined hash algorithms is suitable for direct use. Instead its recommended to use PBKDF2 with salt to encrypt passwords. The Java EE section constructs a working application where users can register and login etc. This is performed as a study of the security tools available in Java EE. The result meets the requirement specification and a section on Java EE security tools is presented. The brute force attack section is a theoretical study of what can be done to protect against a brute force attack. The result shows that CAPTCHAs is not recommended by OWASP and a system using cookies and a form of userblocking is purposed. The various parts are separated as far as possible through the report with the exception that the result of the password encryption section is applied in the Java EE application. Nyckelord: Security in Java EE , Authorization , Authentication , Password Encryption -hashning , brute force attack iv Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Innehållsförteckning Sammanfattning................................................................................................iii Abstract..............................................................................................................iv 1 Inledning....................................................................................................1 1.1 Bakgrund.................................................................................................1 1.2 Problemmotivering..................................................................................1 1.3 Syfte........................................................................................................2 1.4 Problemformulering................................................................................3 1.4.1 Lösenordskryptering...........................................................................3 1.4.2 Java EE – Inloggning..........................................................................3 1.4.3 Brute force attack...............................................................................4 1.5 Översikt..................................................................................................4 2 Teori...........................................................................................................5 2.1 Lösenordskryptering...............................................................................5 2.1.1 Allmänt..............................................................................................5 2.1.2 Historiskt............................................................................................5 2.1.3 Algoritmer..........................................................................................5 2.2 Java EE – Inloggning..............................................................................6 2.2.1 Java EE...............................................................................................6 2.2.2 Inloggning..........................................................................................6 2.3 Brute force attack....................................................................................7 3 Metod.........................................................................................................8 3.1 Lösenordskryptering...............................................................................8 3.1.1 Tillvägagångssätt................................................................................8 3.1.2 Verktyg...............................................................................................9 3.2 Java EE – Inloggning..............................................................................9 3.2.1 Tillvägagångssätt................................................................................9 3.2.2 Verktyg.............................................................................................10 3.3 Brute force attack..................................................................................10 3.3.1 Tillvägagångssätt..............................................................................10 4 Konstruktion............................................................................................11 4.1 Lösenordskryptering.............................................................................11 4.1.1 Testprogram.....................................................................................11 4.2 Java EE – Inloggning............................................................................12 4.2.1 Grafiskt gränssnitt.............................................................................12 4.2.2 Datalagring.......................................................................................16 4.2.3 Domänlogik......................................................................................18 4.2.4 Serverkonfiguration..........................................................................19 4.2.5 Kryptering av lösenord.....................................................................20 4.2.6 Utveckling och testning....................................................................21 v Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 5 Resultat....................................................................................................22 5.1 Lösenordskryptering.............................................................................22 5.2 Java EE – Inloggning............................................................................24 5.2.1 Genomgång säkerhetsverktyg...........................................................24 5.2.2 Kravspecifikation..............................................................................25 5.3 Brute force attack..................................................................................26 6 6.1 6.2 6.3 Diskussion................................................................................................28 Lösenordskryptering.............................................................................28 Java EE – Inloggning............................................................................29 Brute force attack..................................................................................30 Källförteckning.................................................................................................33 Bilaga A: Dokumentation av Java EE källkod.................................................1 Bilaga B: Källkod Java EE.................................................................................1 EJB projekt.............................................................................................1 Webb projekt...........................................................................................2 Webbsidor...............................................................................................3 Konfigurations filer..................................................................................4 Bilaga C: Källkod Lösenordskryptering...........................................................1 vi Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 1 Inledning 1.1 Bakgrund 2015-06-16 Detta arbetet är en del i ett större projekt. Det större projektet är en beställning av ett privatägt företag. Ägaren av företaget är Rasmus Nim. Företaget har varit i kontakt med en person vid en grundskola i Karlstad som ser ett behov av stödverktyg för undervisning av matematik på lägre nivå. Enligt denne finns verktyg för högre nivå av matematik redan tillgängliga, även om han inte tycks hitta någon komplett utbildningsplattform. För att fylla detta behov har ett projekt planlagts i samarbete med Rasmus Nim, som i sin tur har använt sin kontakt som informationskälla. Målet med projektet är att skapa en utbildningsplattform för matematik. Detta arbete är ett mindre projekt vi utarbetat som del i utbildningsplattforms projektet. Detta delprojekt kommer fokusera på autentisering och dess tillhörande säkerhet. 1.2 Problemmotivering Internet är en av människans största uppfinningar och är idag en knytpunkt, inte bara för att dela kunskap, utan även som mötesplats. Många människor har stora delar av sitt liv centrerat runt internet och lägger där upp information om dem själva och andra, som skulle kunna vara skadlig om den kom i orätta händer. Internets snabba framfart och dess ökade informationsinnehåll medför problem och frågor som måste granskas. Ett av de allvarligaste problemen som finns på internet idag är tyvärr inte knutet till varesig mjukvara eller hårdvara utan grundar sig i internetanvändarna själva. Många tar inte tillräckligt stort ansvar för vad de laddar upp på internet och tycks anse att det är någon annans problem. Det finns studier som visar att det ibland är just så att personer identifierar sig på olika sätt på internet och i verkligheten[1]. När något destruktivt händer så är det lätt för användare av internet att beskylla ägaren av de system som har förorsakat dem olycka. Tyvärr tycks det inte vara många som läser de ansvar och licenser de godkänner när de registrerar sig på online tjänster[2]. 1 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Ett gott och berömt citat som kan appliceras i detta sammanhang är taget ur en av Rich Cooks böcker: Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning.[3] Men frågan är om det verkligen är programmerarnas ansvar. I detta fall tycks det vara så att programmerarna i alla fall försöker förebygga oansvarigt internetanvändande och att göra så mycket det går för att öka säkerheten för alla. Tyvärr är internetsäkerhet ett grumligt ämne där de som försöker skapa säkra system ofta inte är desamma som de som normalt bryter ner sådana system. Denna studie fokuserar på några av de mer tekniska delarna av autentisering och säkerhet förknippat med detta. Många frågeställningar relaterat till människor har inget svar, eller har svaret inget tillämpningsområde. Den mänskliga psykologin och beteenden är i sanning ett intressant område, men detta undersöks inte i denna studie. 1.3 Syfte Projektets syfte är undersöka möjligheten till att skapa en säker inloggningstjänst med Java EE som bas. De säkerhetsaspekter som granskas är hur kryptering av lösenord ska göras samt en undersökning om vad som kan göras för att skydda sig mot Brute force attacks. 2 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 1.4 2015-06-16 Problemformulering Projektet har delats upp i tre olika områden. Här följer problemen som detta projekt har för avsikt att lösa kopplat till varje område. 1.4.1 Lösenordskryptering De vanligaste algoritmerna för lösenordskryptering är designade för att de ska vara snabba, vilket normalt inte är rekommenderat för lösenordskryptering då detta gör det möjligt att snabbt skapa databaser med dekrypterade lösenord. En undersökning kommer göras som visar hur snabbt tabeller kan skapas med olika algoritmer, och motiverar val av krypteringsalgoritm. Undersökningen ska resultera i tabeller som presenterar olika algoritmers egenskaper. Resultatet kommer visa olika algoritmers hastighet, dvs. den tid det tar att utföra krypteringen. Undersökningen kommer göras på en persondator och hastigheten beror på antalet uträkningar som kan utföras, därför kan inte hastigheten hos algoritmerna betraktas som ett konstant resultat. Men förhållandet mellan de olika resultaten kommer vara sant oberoende av system. 1.4.2 Java EE – Inloggning Projektet ska leda till ett system som tillåter hantering av användare på en Java EE webbplats. Systemet ska användas av ett annat projekt som består av att skapa en plattform för utlärning av matematik. Detta projekt är fristående från utbildningsplattformsprojektet men kommer att skapas med tanke på det, så konfigurationer och sidor som skapas kommer vara ämnade att passa in med det andra projektet. Systemet ska stödja följande: • Användare ska kunna registrera sig. • Användare ska kunna avregistrera sig (detta innebär att inloggningen inte längre går att använda. Inte att allt användaren har gjort tas bort.) • Användaren ska kunna logga in/ut. • Innehåll ska kunna specialiseras beroende på användarroll. • Resurser ska gå att begränsa till roller. • Olika roller ska gå att definiera. • Privilegierade användare ska kunna höja icke privilegierade användares till en annan roll. 3 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 1.4.3 Brute force attack Brute force attack (BFA) [14] är en beskrivning av en attackform, medan brute force är en strategi. Detta arbete kommer innehålla en teoretisk studie som undersöker vilka skydd som finns, och vad som kan göras, för att motverka intrång genom att ett stort antal inloggningsförsök skickas mot en server. Studien förväntas leda till en lista som summerar olika problem och lösningar relaterat till BFA. Strategin är sedermera omnämnd som BFA i rapporten. 1.5 Översikt Kapitel 2 innehåller information som är nödvändig för att korrekt tolka rapportens innehåll. Där introduceras även vad läsaren anses ska ha för förkunskap. Kapitel 3 är instruktioner på hur målen som satts upp i första kapitlet ska uppnås och krav på hur de ska presenteras. Kapitel 4 granskar programmens utförande och visualiserar viktigare delar med med klassdiagram och figurer. Kapitel 5 summerar resultatet av arbetet och kontrollerar hur det uppfyller kriterierna som definierats i kapitel 1. Kapitel 6 innehåller en avslutande diskussion av personliga erfarenheter och granskar aspekter som är intressanta men inte ingår i projektets kravspecifikation. 4 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 2 Teori 2.1 Lösenordskryptering 2.1.1 Allmänt Lösenordskryptering som vi säger på svenska hänvisar oftast till det engelska passwordhashing. Det är viktigt att förstå skillnaden på kryptering (en. encryption), hashning (en. hashing) och kodning (en. encoding). • Kryptering – är att omarbeta data till en oanvändbar form, originalet kan återställas med en nyckel. • Hasning - är en icke vändbar typ av krypteringar. • Kodning – är formatet på data som säger hur det ska tolkas. När lösenordskryptering omnämns så är det oftast lösenordshashning som borde användas, och när man hashar lösenord så kodas ofta resultatet om till något lämpligt format. Det kan anses att lösenord borde krypteras istället för att hashas, fördelen med hashning är att det inte går att vända, vilket gör det mer säkert genom att ingen felaktig implementation kan leda till ökad säkerhetsrisk i frågan. I denna rapport avser kryptering alltid hashning när det omnämns i lösenordssammanhang, rubriken har valts för att kryptering, som tidigare nämnt, är det vanliga sättet att referera till ämnet. 2.1.2 Historiskt Daniel V. Klein nämner i artikeln Foiling the Cracker[4] och Improving system security via proactive password checking[5] att det historiskt har varit ett problem med att hårdvaruutvecklingen i sig gör att krypteringsalgoritmer föråldras. Bland annat så ges ett exempel på en algoritm som användes på 1970-talet och kallades M-209. Algoritmen var för snabb då 800 lösenord kunde krypteras per sekund på den tidens maskiner, vilket tillät en databas med ord att snabbt krypteras för att testa olika hashvärden mot varandra. Algoritmen ersattes av DES1975 vilken då tillät ca 4 krypteringar per sekund med en iterativ implementation. Även denna algoritm är givetvis föråldrad i skrivandets stund. 2.1.3 Algoritmer Här följer en sammanfattning av de algoritmer som granskas i projektet. • MD5 (Message-digest 5)[6] är en algoritm som använts flitigt sedan 1991. Hashvärdet som algoritmen producerar är 128 bitar lång och är inte vändbar. Under årens gång har många brister uppdagats i algoritmen så den är 5 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 inte längre rekommenderad att använda. Enligt Poul-Henninh Kamp, skaparen av MD5crypt (vilket använder sig av MD5) så är algoritmen inte längre säker för att den är för snabb [7] trotts en iterativ implementation. • SHA1 (Secure hash algorithm 1)[8] är efterträdaren till SHA0 som snabbt visade sig ha stora säkerhetsproblem. SHA1 genererar ett 160 bitars hashvärde och har använts sedan 1995. Google online security [9]Error: Reference source not found har valt att avveckla användandet av SHA-1 i certifikat fram till 2016 , motivationen är att kollisioner sker oftare än väntat. • SHA2 som släpptes 2001 är inte särskilt lik de tidigare versionerna implementationsmässigt men är ändå nästa generation i SHA familjen. I SHA2 ingår både SHA256 och SHA512 som undersöks i detta arbete. Den största skillnaden mellan versionerna är att SHA-256 arbetar internt med 32bits ord medan SHA-512 arbetar med 64bitar. Även hashvärdet skiljer sig i att SHA-256 ger en 256 bitar lång värde, medan SHA-512 ger en 512 bitars hash, därav namnen. Enligt OWASP (The Open Web Application Security Project )[10] är SHA-256 den sämsta algoritm som ska användas idag tillsammans med SALT. 2.2 Java EE – Inloggning Avsnittet som rör Java EE förutsätter att läsaren är bekant med Java EE. Java EE har många förkortningar vilka skrivs i sin helhet första gången de omnämns och refererar till källor där läsaren kan finna vidare information. 2.2.1 Java EE Java EE är en specifikation för hur olika teknologier ska fungera. Detta för att skapa en standard för hur nätverksbaserade applikationer ska konstrueras. En Java EE plattform är en miljö som tillåter användandet av ett antal teknologier som stöds av Java EE specifikationen. En av grundprinciperna i Java EE är att applikationer delas upp i lager för att skapa tydliga avgränsningar och koppla isär beroenden i programmet. 2.2.2 Inloggning Inloggning är en handling där en användare intygar att denne är den användare som den uppger sig att vara genom att autentisera sig. Autentisering kan ske på olika sätt men den grundläggande strategin är att användaren uppger information som endast denne känner till och tidigare registrerat i systemet. Detta kan ske genom att skriva in ett lösenord eller mata in ett fingeravtryck, men båda metoderna är del i autentiseringsprocessen. 6 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Eftersom hårdvarukrav ställs på många autentiseringsmetoder så är inloggning med lösenord den vanligaste metoden i publika applikationer då de flesta system har någon metod för att skriva in tecken. 2.3 Brute force attack Eftersom arbetet är en studie av BFA så krävs ingen större förkunskap, då resultatet presenterar konceptet. Om läsaren är bekant med attacken och grundläggande webbutveckling ska avsnittet inte vara svårt att förstå. Brute force är en strategi som går ut på att ett arbete utförs med ingen, eller mycket liten, intelligens. En Brute force attack är en attackform som är en av de mest primitiva attackerna och går ut på att testa många kombinationer av lösenord för att så småningom kanske hitta en som kan logga in i systemet. Teoretiskt så skulle en BFA kunna komma in i vilket (statiskt, där lösenord ej uppdateras) system som helst men oftast inte på en acceptabel tid. Brute force attack ska inte förväxlas med Brute force search, BFA har en inloggningstjänst som mål medan BFS har någon form av data som mål. I det fall BFS kan förväxlas med BFA är så målet krypterade lösenord. En dictionary attack (DA) är en form av BFA men med utökad intelligens i det att den testar en uppsättning med troliga lösenord som sparats i en databas, och även kombinationer och modifikationer av dessa lösenord. Anledningen till att attacken omnämns är att det ofta är denna formen av attack som utgör störst hot mot ett system då den mycket snabbt kan hitta rätt lösenord, men inte kan hitta alla lösenord. P. Gauravram nämner i Security analasys of salt[11] att attacken är framgångsrik när det finns ett stort antal användare att attackera. Finns det många användare så har DA god chans att mycket snabbare hitta ett lösenord är en ren BFA, men eftersom en DA arbetar med en form av sannolikhet är inget resultat garanterat. Det är denna attackform som gett upphov till behovet av att utbilda användare så att de väljer ett bra lösenord. Tyvärr är det lättare sagt än gjort då en DA kan konfigureras så det testar många olika strukturer, och användare är duktiga på att memorera strukturer men dålig på att memorera slumpmässiga teckenföljder. 7 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 3 Metod 3.1 Lösenordskryptering 3.1.1 Tillvägagångssätt 2015-06-16 Ett experiment ska utföras för att testa algoritmers exekveringshastighet, från detta resultat kommer matematiska modeller fastställas som representerar sambandet mellan ökad kvantitet i invärdet och den resulterande exekveringstiden. Experimentet utförs genom att data krypteras upprepade gånger med olika längd för att nå ett genomsnittsvärde på den tid en kryptering tar. Genom att olika långa indata används kan det undersökas om krypteringshastigheten beror på lösenordets längd. Resultatet kan sedan användas för att kontrollera att de framställda matematiska modellerna ger ett närmevärde till de värden som experimentet resulterar i. Programmet och hur det används för att beräkna exekveringshastigheten finns beskriven i kapitlet 4.1. När algoritmens hastighet fastställts så kan det användas för att uppskatta hur lång tid det skulle ta att framställa en tabell med de dekrypterade värdena, eller utföra en brute force search efter ett lösenord. Formel (1) är den matematiska formeln för att tillämpa algoritmens hastighet i syfte att uppskatta den tid det tar att få fram ett lösenord med en viss längd. N Time=t∗∑ nChar n (1) n=1 Där t = en körnings tid, N = antalet tecken att kombinera, nChar = antalet tecken att välja bland, Time = tiden körningen kommer ta. Utifrån resultatet av ovanstående experiment kommer ett resonemang skapas kring vilka algoritmer som är att rekommendera som lösenordskrypterings algoritm på en webbplats. I resonemanget ingår det exempel på existerande databaser med dekrypterade lösenord. Dessa tilldelas ett uppskattat värde på framställningstid, återigen är det inte tiden som är relevant utan hur algoritmerna förhåller sig till varandra. Denna tid kan räknas om för att få en överblick på hur lång tid det skulle ta att skapa lik nande databaser men med andra algoritmer. Resonemanget kommer även värdera den kostnaden som en server måste betala för att implementera en specifik krypteringsalgoritm. 8 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 De algoritmer som kommer testas är MD5, SHA-1, SHA-256, SHA-512 [15]. Algoritmerna har valts för att de på olika sätt är relevanta. • MD5 är med för att det är den algoritm som var mest känd i PHP när studier av detta gjordes, och därför den algoritm som skulle används i projektet. • SHA-1 har valts för att beställaren av detta projekt fått kunskap om att MD5 är föråldrad och att denna algoritm ska användas istället. • SHA-256 har testats för det är standardkonfigurationen i Glassfish 4.0. • SHA-512 testas för att se skillnaden mellan Glassfish standardalgoritm och vad som bör vara ett steg säkrare. Eftersom endast hastighet betraktas så kan inte en slutsats om en algoritms totala värdighet bestämmas utifrån resultaten, det enda som går att säga är om de lämpar sig för lösenordskryptering med krypteringshastighet som utgångspunkt. 3.1.2 Verktyg De verktyg som används är Eclipse Luna för utveckling i Java SE 8. 3.2 Java EE – Inloggning 3.2.1 Tillvägagångssätt Avsnittet är ett konstruktivt arbete där problemet inte är nytt och lösningar finns i många former. En inledande studie rörande vilka verktyg som finns tillgängliga för att implementera säkerhet i systemet har lett till att JAAS (Java Authentication and Authorization Service)[16] valts för att fungera som underliggande säkerhetssystem. Anledningen till att JAAS har valts är: • JAAS är standardiserat i java EE 6 (JAAS är grundsystemet som används även i Java SE men med funktionalitet unik för Java EE [17]). • JAAS med tillhörande funktionalitet kommer med Java EE 6 och därför krävs ingen ytterligare integrering med projektet. • JAAS tillåter användande på rätt nivå för projektet utan allt för hög inlärningskurva. • JAAS är en del i Java och bör därför utvecklas aktivt i framtiden. När JAAS omnämns i denna rapport så är det inte endast JAAS som är målet utan även den funktionalitet som finns i Java EE 6 standarden för arbete med systemet. 9 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Genom att använda JAAS så har stora delar av ansvaret rörande användarsäkerhet lagts på ett väl beprövat system. Detta har även minskat arbetsinsatsen avsevärt när det gäller att implementera användarhantering. Istället för implementation leder detta till en teoristudie om vilka funktioner som finns tillgängliga och hur JAAS konfigureras för att fungera på servern. Utvecklingen kommer ske genom att en grundmodell byggs upp som efterliknar den tänkta utbildningsplattformen. Därefter implementeras inloggning och registrering följt av de kontorelaterade operationerna. Utvecklingen görs i steg där manuella tester utförs efter varje färdig del. Detta leder till ett rekursivt arbete men då projektet inte är stort är den belastningen acceptabel. När lösenordsstudien nått ett resultat kommer denna användas för att implementera ett gott system för lösenordshantering i applikationen. 3.2.2 Verktyg Utvecklingen av inloggningssidan görs i Eclipse Kepler konfigurerad för webbapplikationsutveckling, detta genom en plugin som kallas Web tools platform. Utvecklingen sker mot Java EE 6 med Primefaces grafiska komponenter, applikationen testas på en Glassfish 4 server med hjälp av Glassfish tools plugin till Eclipse. För att inspektera sidan användes Firefox med Firebug. 3.3 Brute force attack 3.3.1 Tillvägagångssätt En teoretisk, kvalitativ studie ska göras om BFA som summerar problem och lösningar kopplade till ämnet. Internet används för att hitta intressanta källor, vikt kommer läggas på OWASPs utlåtanden. Resultatet presenteras på en problem – lösningsbasis. 10 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 4 Konstruktion 4.1 Lösenordskryptering 4.1.1 Testprogram Programmet som används för att testa olika hashfunktioner är mycket enkelt. Hela programmet är implementerat i en fil där konstanter konfigurerar hur programmet ska köra. För att skapa hash värden så används java.security.MessageDigest [18] vilken tillhandahåller de vanligaste algoritmerna som används vid icke vändbar kryptering. Programmet kan konfigureras så att det: • Upprepar test. • Kör fler olika algoritmer. (De som stöds av MessageDigest) • Skriver till fil. • Använder definierade tecken. • Testar alla kombinationer av de definierade tecknen till ett vist djup, där djupet är antalet tecken i ordet som ska producera ett hash. När programmet exekveras skrivs den tid en algoritm tog att utföra ut i konsolen, tiden är medelvärdet av antalet test som konfigurerats att de ska köras. Kod i bilaga C. 11 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 4.2 Java EE – Inloggning 4.2.1 Grafiskt gränssnitt Applikationens grafiska gränssnitt är skrivet i JSF (JavaServer Faces)[19] med Primeface 5.2 (JSF ramverk)[20]. Gränssnittet är en representation av hur matteplattformens sida skulle kunna vara uppbyggd men är inte den färdiga produkten. Gränssnittet har skapats på detta sätt endast för att projektet ska få en miljö som efterliknar den tänkta miljön. Detta innebär att webbsidorna som inte är kopplade till projektet antingen har ett nummertecken som adress eller en sida med en kort förklarande text. Sidor som är relevanta för projektet: 1. /faces/pages/signin.xhtml 2. /faces/pages/authenticated/account.xhtml 3. /faces/pages/authenticated/groupManager/recruitTeacher.xhtml 4. /faces/defaultCompositions/userMenu.xhtml Sidornas syfte i nummerordningen från ovanstående lista: 1. signin.xhtml är en sida som tillåter användare att logga in på webbapplikationen, se figur 1. Detta sker genom att en hjälpklass som skapats för att fungera med JSF anropas med önskan om att logga in. Om inloggningen lyckas, skickas användaren till applikationens förstasida. Om inloggningen misslyckas så läggs ett lämpligt meddelande till sidans kontext. Inloggningssidan tillåter även att användare registrerar sig på applikationen, se figur 2. För att utföra detta har en registrerings klass skapats som kopplats till registrerings formuläret och tillåter på så sätt att användaren registrerar sina uppgifter. Om en framgångsrik registrering genomförs så loggas användaren in och skickas till applikationens förstasida, om inloggningen misslyckas så skrivs meddelanden ut som förklarar vad som gått fel. 2. account.xhtml summerar användarens kontouppgifter. Under utvecklingen så presenterar sidan vilka grupper användaren tillhör. Detta ska tas bort i en verklig applikation men så länge endast användarhantering finns på sidan så är det ett sätt att kontrollera att förändringar rörande användarens grupper verkligen genomförs. Kontosidan tillåter användaren att förnya sitt lösenord genom att en klass har kopplats till formuläret och vid ändring kontrollerar om det gamla lösenordet är korrekt och uppdaterar isåfall till det inskickade lösenordet, se figur 3. 12 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Att inaktivera kontot görs enkelt från kontosidan genom att klicka på knappen ”Avregistrera”. Användaren får då en chans att avbryta avregistreringen med en förklaring att alla privilegier kommer att tas bort och att kontot inte längre går att logga in på, se figur 4. Om användaren verkställer avregistreringen så kommer kontot att markeras som inaktivt och inloggningen kommer inaktiveras. Hur detta ska hanteras vidare är upp till sidans ägare att avgöra men nuvarande implementation tillåter flera möjligheter. Bland annat kan kontot ligga inaktiverat en tid och om användaren inte ber om att det ska återaktiveras så tas det bort. Kontot kan tas bort omedelbart eller vara inaktivt i en obestämd framtid. För närvarande sker endast en inaktivering av kontot. 3. recruitTeacher.xhtml är en sida som används av användare som fått rollen grupp hanterare. Denna sida tillåter att registrerade användare ges rollen lärare. Detta har skapats mest som ett bevis på att det går att göra och har för närvarande inte mycket praktiskt värde då grupphanterare måste läggas in programmatiskt. Sidan använder en klass som kopplats till presentationen för att hämta användarens namn och lägga till denne till gruppen lärare. Denna sida ska bara gå att nå av användare som är grupphanterare och därför blockeras alla förfrågningar till sidan från användare som inte tillhör den gruppen. Detta görs via konfigurationer och kan ses i figur 5. 4. userMenu.xhtml är ett verktygsfält som visas på toppen av sidan. Verktygsfältets innehåll renderas om användaren uppfyller de roller som krävs för att visa innehållet, se figur 6. Detta görs genom att en hjälpklass för säkerhetsrelaterade funktioner anropas direkt i HTML-koden via EL (unifed expression language)[21] som på så vis kontrollerar användarens roller. Dokumentation av hjälpklasserna i bilaga A. Kod finns i bilaga B. 13 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg Figur 1: signin.xhtml - Inloggningssidan Figur 2: signin.xhtml – Registreringssidan Figur 3: account.xhtml –Förnya lösenord 14 2015-06-16 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Figur 4: account.xhtml – Avregistrera <security-constraint> <display-name></display-name> <web-resource-collection> <web-resource-name></web-resource-name> <url-pattern> /faces/pages/authenticated/groupManager/* </url-pattern> </web-resource-collection> <auth-constraint> <role-name>GROUP_MANAGER</role-name> </auth-constraint> </security-constraint> Figur 5: web.xml – Begränsar tillgången till alla filer i groupManager mappen. Figur 6: userMenu.xhtml – Inloggad som elev så endast elevverktyg finns tillgängliga. 15 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 4.2.2 2015-06-16 Datalagring Datalagringen i applikationen användare JPA(Java persistence API)[22] som är del i Java EE standarden. Designen av datalagringsdelen i applikationen har inspirerats av designmönstret Active Record(AC, Ett objekt med både lagrad data och uppförande)[23]. Den huvudsakliga skillnaden mellan den implementerade varianten och Active Record är att ingen domänlogik ska utföras av objektet. Objektet fungerar som en Java Bean (getters och setters för fält)[24] men utökat med funktioner för att hantera datalagringen. Projektet innehåller endast en entitetklass, denne representerar en användare, figur 7. Till detta finns det en klass som implementerar samma gränssnitt som entitetklassen men som även implementerar ett wrap gränssnitt. Wrap gränssnittet tillhandahåller metoder för att data ska kunna synkroniseras med databasen, se figur 8. Namnet wrap används för att implementationen ska omsluta en entitet. För att CDI(Context dependency injection)[25] ska fungera, så har gränssnitten för användare och wrap slagits samman i ett tredje gränssnitt som i sin tur implementeras av wrapper klassen. Entitetklassen har bara skyddade konstruktorer och instansieringen sker därför endast genom wrapper klassen som omsluter entiteten. Detta görs för att ge en central plats att begränsa tillgången till användarentitetens data. Ett alternativ som övervägdes under designen var att skapa en gateway (ett designmönster där kommunikation sker genom en klass)[26] till databasen. Detta realiserades dock inte p.g.a. att en gateway komplicerar säkerhetshanteringen. Några punkter om val av design: • En gateway skulle kräva någon form av kontroll vid synkronisering mot databasen för att säkerställa att inte förbjudna egenskaper ändras. AC begränsar detta redan när egenskapen ändras. • Vid utläsning från databas kan AC enkelt begränsa åtkomsten till egenskaper. En gateway måste välja vad som ska läsas ut. • En gateway är mer dynamisk i det att man hanterar vanliga java objekt på normalt sätt. AC begränsar vad som går att göra och kräver mer specifika lösningar för varje fall. Dokumentation i bilaga A. Kod finns i bilaga B. 16 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Figur 7: UserEntity – Klassen som representerar en användare i databasen. Klassen har endast metoder för att manipulera dess fält så dessa har filtrerats. Figur 8: Wrap – Gränssnitt för att hantera en UserEntity som omslutits av en annan klass. 17 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 4.2.3 2015-06-16 Domänlogik Projektet innehåller ingen egentlig domänlogik eftersom inget konstruktivt utförs. Det som anses vara domänlogik i detta projekt är det som i normala fall skulle betraktas som säkerhetsverktyg. I kapitel 4.2.1 nämns det att säkerhetsverktyg används för att avgöra om en användare ska presenteras med specifikt innehåll. Det verktyget är en klass som heter securityBean (figur 9) och befinner sig i säkerhetsprojektet. Det är alltså inte en java bean direkt kopplad till JSF, utan den kan användas överallt i applikationen där containern kan tillhandahålla ett sessions kontext objekt. Klassen tillhandahåller metoder för att utföra säkerhetskontroller och funktioner som är vanligt förekommande: • Kontrollera om användaren är inloggad. • Avgöra om en användare är medlem i en av flera angivna roller. • Få den inloggade användarens användarnamn. I webbdelen av projektet finns en klass som heter AuthJSF som används för att logga in och ut. Klassen har JSF i sitt namn för den kräver att det finns ett associerat FacesContext (ett objekt som bär data relaterat till JSF för den aktuella förfrågan)[27] som den kan använda för att utföra sina operationer. Klassen felhanterar även allt genom att fånga alla undantag och skriva meddelanden till användaren genom att skapa ett FacesMessage (ett objekt som används för att registrera meddelanden i kontext)[28] objekt som registreras i kontext och sedan kan hanteras i HTML-filen. Figur 9: SecurityBean – Hjälpklass för att upprätthålla säkerhet i applikationen. 18 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 4.2.4 2015-06-16 Serverkonfiguration I projektet används Glassfish 4.0 som server för att utveckla projektet. När ett projekt skapas som använder Java EEs säkerhetsfunktioner kopplat till en databas så måste servern konfigureras så att den kan hitta åt användarna och deras grupper. I detta projekt har Glassfish administrationssida använts för att utföra denna konfigurering, konfigurationen kan ses i figur 10. Konfigurationen kan även göras med terminalen, eller iallafall delvis manuellt genom att manipulera konfigurations filer. De steg som utförts är: 1. Skapa en databasresurs. Detta måste göras globalt så att JAAS kan använda det och inte bara applikationen. 2. Koppla resursen till ett JNDI-namn (Java naming and Directory interface, används för att koppla en resurs till ett namn som kan användas i programmet.)[29] 3. Skapa ett säkerhetsområde (en. realm) som kopplas mot dess databasschema för att identifiera de olika egenskaper som behövs. I detta projekt används sedan en konfigurationsfil i webbprojektet för att överföra användarnas grupper till de roller som avses användas i applikationen. Detta kan även göras automatiskt av Glassfish om namnen på grupperna är desamma som namnen på rollerna. Figur 10: Urklipp ur domain.xml – Inställningarna för säkerhets området (en. realm). Dokumentation i bilaga A. Kod i bilaga B. 19 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 4.2.5 2015-06-16 Kryptering av lösenord I Glassfish finns möjlighet att ställa in vilken krypteringsalgoritm som ska användas för lösenord. De inbyggda systemet används dock inte i detta projekt p.g.a. att resultatet av krypteringsalgoritm undersökningen (Kapitel 5.1) visar att de inte är lämpligt att använda algoritmerna utan vissa modifieringar. Därför har ett tillägg gjorts till programmet som tillåter mer avancerade inställningar för lösenordskrypteringen. Tillägget är en klass som heter PasswordService (figur 11). Klassen tillhandahåller funktioner som används för att utföra kryptering av lösenord beroende på en specifikation. Specifikationen skapas av PasswordService och lagras tillsammans med det lösenord som krypterats med specifikationen. Detta upplägg används för att programmet ska kunna byta algoritmer och annan data kopplat till krypteringen utan att användarna ska påverkas. Lösenordet krypteras alltid för en användare med den specifikation som användaren har lagrad, om den lagrade versionen inte är den senaste kommer en lyckad inloggning följas av automatisk omkryptering av lösenordet så att det sedan använder den senaste versionen. På så vis försäkras att största delen av användarna har stark kryptering på sitt lösenord. Som standard krypteras lösenordet med SHA-256 och PBKDF2 (en strategi som repeterar krypteringen ett antal gånger)[30] med 2000 iterationer. Lösenordet krypteras också med ett slumpvärde (ett så kallat SALT[31]) som genereras av SecureRandom (ger oförutsägbart slumpmässiga värden)[32]. Slumpvärdet är inställt att vara 16 byte långt som standard. Alla grundinställningar kan ändras i projektets ejb-jar fil. Efter en ändring krävs omstart av applikationen vilket följs av att alla användare automatiskt uppdateras nästa gång de loggar in. Figur 11: PasswordService – Klass som sköter lösenordskrypteringen i applikationen. Dokumentation i bilaga A. Kod i bilaga B. 20 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 4.2.6 2015-06-16 Utveckling och testning Projektet har endast en klass som är specifik för utveckling och som bör avlägsnas före publicering av applikationen. Klassen är en singelton (en instans som bara skapas en gång)[33] som körs när programmet startas. Dess enda syfte är att lägga in användare i databasen som kan användas för att testa applikationen. Projektet har definierat fyra olika roller för testning. De är STUDENT, TEACHER, SCHOOL_ADMIN och GROUP_MANAGER. En användare av varje typ skapas för att kunna testa dem, deras namn och lösenord motsvarar deras roll med små bokstäver. De olika användarna ser sidan ur de olika rollernas perspektiv och har därför använts för att kontrollera att allt fungerar efter förväntan. Det är den enda testning som utförts under projektets utveckling, metoden innebär rekursivt och tidskrävande arbete. Arbetssättet har valts för att testning av Java EE innebär problem som är ett projekt i sig att lösa. Eftersom Java EE applikationer måste köras i en container så kan det inte testas med vanliga ramverk. 21 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 5 Resultat 5.1 Lösenordskryptering 2015-06-16 Detta är resultatet av tester som körts för att undersöka olika hashalgoritmers exekveringstid, värdena kan ses i tabell 1. Tabell 1: Tid per körning - Djup anger antalet tecken i följd. Rep anger antalet gånger algoritmen körts för att ge medelvärdet. Anledningen till att så många körningar utförts på de lägsta djupet är att Java maskinen utför optimering som påverkar resultaten. För att minimera den effekt optimeringen har på värdena har därför samtliga test körts tillräckligt länge för att ett stabilt läge ska nås. Djup MD5 (s) SHA-1 (s) SHA-256 (s) SHA-512 (s) Rep. 1 0,0009 0,0010 0,0032 0,0040 5000 2 0,025 0,028 0.087 0,107 1000 3 0.66 0.75 2.3 2.8 5 4 16,6 19,4 58,4 73,4 5 5 447.9 503.64 1520.15 1889,9 5 Tabellen (1) visar att skillnaden i hastighet mellan SHA-256 och SHA-512 inte är stor, båda tillhör SHA-2 familjen så det resultatet är inte särskilt förvånande. Genom att dela körtiden på antalet hashningar som görs så kan arbetstiden för algoritmen uppskattas. Ett resultat av detta kan ses i tabell 2. Tabell 2: Krypteringstid baserat på körningstids tabellen. Djup MD5 (ms) SHA-1 (ms) SHA-256 (ms) SHA-512 (ms) 1 34,61 38,46 123,07 153,85 2 35,61 39,89 123,93 152,42 3 36,11 41,03 125,83 154,44 4 34,93 40,82 122,88 153,19 5 36,25 40,71 123,02 152,95 Genomsnitt 35,5 40,2 123,7 152,8 Tabellen visar att MD5 är nästan fem gånger så snabb som SHA-512, SHA-1 däremot är bara knappt långsammare än MD5. 22 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 I testprogrammet har 26 tecken använts (små engelska bokstäver). Uträkningen för SHA-512 visas i formel 2. Genom att sätta databas storleken till åtta teckens lösenord så skulle det ta närmare 385 dagar att utföra hashningarna. Samma uträkning för MD5 ger 91 dagar. Normalt bör närmare 100 tecken användas då det är antalet tecken som kan skrivas från tangentbordet. Resultatet av ovanstående beräkning blir då ungefär 49000 år respektive 11800 år. N Time=0,0001528∗∑ 26n (2) n=1 Att använda SHA-512 kan inte anses vara någon form av begränsning för serverns prestanda trots att det är den långsammaste algoritm som testats. Enligt ovanstående resultat skulle 6500 användare kunna logga in varje sekund, algoritmen är snarare mycket för snabb än ett prestandaproblem. Detta talar för att algoritmerna inte borde användas. 23 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 5.2 Java EE – Inloggning 5.2.1 Genomgång säkerhetsverktyg Eftersom arbetet ändrat karaktär från ren implementation till stora delar teori presenteras vad som uppnåtts som substitut för resultatet av kod konstruktion. Java EE tillhandahåller verktyg för att arbeta med säkerhet i en webbapplikation. Eftersom detta projekt är inriktat på autentisering så är det de verktygen som är relaterat till detta och auktorisering som granskas. För att auktoriserings verktygen ska fungera så måste JAAS användas som underliggande system för autentisering. För autentisering finns metoder för inloggning och utloggning, ett sessions kontext skapas vid inloggning och består en vis tid eller till utloggning (sessionen förstörs). Verktygen för auktorisering som erbjuds kan delas in i tre kategorier: • Notiser (en. Annotations) • Programmatisk • Konfiguration De tre kategorierna används för det mesta för olika saker. Notiser används för att undvika behovet av specifik kod. Programmatisk säkerhet används när notiser är för grovkornigt. Konfiguration är ännu grovkornigare än notiser (det mesta som kan göras med notiser kan även göras i konfigurationsfiler) och erbjuder bl.a. ett sätt att välja vilka adresser på webbplatsen som en roll ska ha tillgång till. Det är endast till det som detta projekt använder konfigurations relaterad säkerhet. Det finns ett antal säkerhetsrelaterade notiser [34] men den viktigaste är @RolesAllowed och tar som argumentnamnet på den roll som tillåts anropa metoden, eller samtliga metoder i en klass, som notisen fästs vid. För att notisen ska fungera krävs det att det i modulen där den används finns deklarerat vilka roller som ska testas. Detta kan göras antingen med @DeclareRoles-notisen eller kan det definieras i en konfigurationsfil. Detta projekt definierar detta i konfigurationsfilen som är kopplad till modulen. Programmatisk säkerhet uppnås genom att helt enkelt utföra kontrollerna manuellt i koden. Detta ger möjlighet till mycket finkornig säkerhet men med extra kodning i utbyte. I projektet har en fasad skapats som tillåter enhetlig användning av de vanligaste operationerna, och som kan användas på samma sätt både i anknytning till domänlogiken och i presentationslagret. 24 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 5.2.2 2015-06-16 Kravspecifikation Användare ska kunna registrera Avklarat sig. Användare läggs helt enkelt till i databasen. Användare ska kunna avregistrera sig (detta innebär att inloggningen inte längre går att använda. Inte att allt användaren gjort tas bort.) Avklarat En användare kan inaktiverar sitt konto. Om denne sedan ska tas bort eller om en aktiveringsfunktion ska finnas är upp till det användande systemet, eller i detta fall framtiden, att avgöra. Användaren ska kunna logga in/ut. Avklarat Servletens inbyggda funktioner används för att logga in och ut med JAAS. Ett hjälpverktyg har skapats för att kunna utföra detta direkt i JSF koden. Innehåll ska kunna specialiseras Avklarat beroende på användarroll. Funktionaliteten finns inbyggt i Java EE. Ett hjälpverktyg har skapats för att enklare utföra detta. Resurser ska gå att begränsa till Avklarat roller. Funktionaliteten finns inbyggt i Java EE. Olika roller ska gå att definiera. Avklarat Funktionaliteten finns inbyggt i Java EE. Privilegierade användare ska kun- Bekräftat na höja icke privilegierade använ- Systemet kan konfigureras så detta går att dares till en annan roll. göra efter behov. Ett exempel har implementerats. 25 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 5.3 2015-06-16 Brute force attack Behovet av någon form av skydd mot BFA är verkligt för de flesta sidor, men hur detta skydd ska implementeras är något som varje applikation måste utvärdera. Det finns vissa verktyg att använda i Java EE som hjälper till att motverka BFA, t.ex. har Primeface ett färdigt robotfilter som enkelt kan inkluderas i sidan, men de mesta tycks vara upp till utvecklarna själva att implementera. Här följer en lista som är resultatet av en studie av problemet, med olika fall av hur BFA kan yttra sig och motarbetas: Fall 1. Beskrivning: När en attack kommer från en enda adress och är riktad mot en användare. Detta är den enklaste formen av BFA. Problem: Problemet är att om den attackerande parten tillåts utföra en attack obehindrat så kommer denne förr eller senare få tillgång till offrets inloggning. Lösning: Problemet kan enkelt avvärjas genom att blockera en ipadress efter upprepade inloggningsförsök som misslyckats. Konsekvens: Om attacken kommer genom en proxy (server som agerar mellanhand för internet frågor) [35] så kommer samtliga användare som ansluter genom den proxyn blockeras. Vissa attacker utnyttjar detta för att utföra en DoS (en. Denial of service)[36] attack. Fall 2. Beskrivning: När en attack kommer från flera adresser och är riktad mot en användare. Problem: Problemet är det samma som i fall 1. Lösning: Eftersom flera adresser används så kan inte detta förebyggas på samma sätt som i fall 1. Istället kan användaren blockeras, antingen för en viss tid, eller tills någon ytterligare form av identitets bekräftelse utförs. Konsekvens: Konsekvensen av detta är att användaren som är målet för attacken får svårare att få tillgång till tjänsten. Därav kan även detta användas för att utföra en DoS attack. 26 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Fall 3. Beskrivning: När en attack kommer från flera adresser och är riktad mot flera användare. Problem: Denna attackform är svårare att motarbeta än tidigarenämnda, men inte särskilt svår att utföra. Om någon av ovanstående lösningar används för att motverka denna attack så kan det leda till att hela sidan snabbt stängs ned. Lösning: Det finns flera metoder att motarbeta attacker av denna form, men ingen verklig lösning. 1. Applikationen kan ställa ytterligare frågor till användaren, t.ex. Vad var färgen på din första bil. Som användaren har besvarat tidigare. 2. Robotfilter (en. CAPTCHA, en fråga som en robot ska ska svara fel på och en människa svara rätt nära 100% av försöken)[37] kan användas för att för att öka sannolikheten för att det är en mänsklig användare. 3. Applikationen kan lagra data om tidigare säkra enheter, detta kan göras via IP eller med kakor eller någon annan form av identifiering. Konsekvens: Varje lösning har medföljande konsekvenser och svagheter, här följer de som är kopplade till lösnings listan. 1. Ofta ogillas denna form av extrafrågor då den kan anses samla personlig information. Det är också så att om attacken är riktad (Fall 1 & 2) kan ofta information hittas som går att använda för att besvara frågan. 2. Robotfilter är olagliga i vissa länder och filtrens frågor kan lösas av en dator, det är bara lite svårare, men de är likväl en lösning som bör övervägas. Robotfilter har blivit en väl använd metod för att det är enkelt att implementera och inte medför allt för drastiska konsekvenser, tyvärr är en konsekvens av att filtren blivit vanliga att användare kan få betalt för att lösa filtrens frågor, vilket då kan användas av hackningsprogram för att kringgå hindret. 3. Att lagra data med betrodda användare är en god lösning men som alla andra medför den problem. Om en betrodd användare ansluter genom en proxy så blir alla användare som ansluter genom proxyn betrodd, ip är därför ingen god identifierare av betrodda enheter. Att skapa en kaka hos klienten är bättre, men en kaka kan förfalskas och en publik enhet är för applikationen lika säker som en privat. 27 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 6 Diskussion 6.1 Lösenordskryptering 2015-06-16 Inledande i arbetet så fastslogs det att MD5 är en för snabb algoritm, från resultaten i tabell 1 bör det vara säkert att säga att även SHA-1 därför är föråldrad då den bara knappt är långsammare, resonemanget stärks av Google online security Error: Reference source not found som valt att avveckla användandet av SHA-1 i certifikat till 2016 , även om motivationen är att kollisioner sker oftare än väntat. I certifikat är givetvis omständigheterna annorlunda kontra lösenord. Problemet för lösenord är för det mesta inte kollisioner utan att indata är relativt liten. Resultaten verkar rätt lovande även för MD5 som anses vara en snabb algoritm, problemet har tyvärr flera rötter. För det första så är detta test kört utan någon optimering och på en enkel persondator. Idag finns redan tabeller som innehåller mer än åtta tecken [38]. Detta test förutsätter att en ren Brute force sökning utförs, människor använder ofta ord och det finns inte så många ord att välja på. Enligt Oxford Dictionaries[39] finns drygt 170 000 engelska ord (detta utan böjningar mm. Totalt uppskattas det till minst 250 000 ord) , det motsvarar drygt en sjättedel av de uträkningar som krävs för att testa alla kombinationer till och med tre tecken långa ord och 100 möjliga tecken. Matematiskt skulle sökningen kunna göras på ca 26 sekunder under samma förutsättningar som de resterande testerna i detta projekt och med SHA-512 som algoritm. Det finns även tabeller[40] som innehåller många miljoner olika böjningar och kombinationer av ord som gör det mycket svårt att hitta lösenord som inte redan dekrypterats. Resultatet tyder på att algoritmerna som normalt används för lösenordskryptering inte lämpar sig som sådana. Även SHA-512 som är den tyngsta algoritmen som har inbyggt stöd i Glassfish 4.0 är alldeles för snabb för att användas explicit som skydd. En ointelligent attack klarar algoritmen så länge värdet som resulterar i ett hash är någorlunda långt, men intelligentare attacker finner värdet utan större problem. Om lösenordet inte har någon form av underliggande struktur så blir de intelligentare attackerna verkningslösa, problemet är att användare sällan skapar lösenord utan struktur då de blir mycket svårare att memorera. En lösning på problemet är att använda vad som kallas för SALT. Det innebär att man skapar ett hash av lösenordet tillsammans med oförutsägbart slumpade tecken för att öka dess längd och förhindra att lika lösenord får samma hashvärde. SALT gör att befintliga tabeller inte går att använda för att finna värdet på ett hash utan det måste sökas. Om grundlösenordet är dåligt och SALT-värdet är känt så kan lösenordet fortfarande hittas på en rimlig tid. Ett annat system som finns tillgängligt är ett som på engelska kallas för key stretching. Tekniken eftersträvar att öka kravet på resurser som krävs för att framställa hash värdet och på så sätt begränsa möjligheten för BFA. En variant för att uppnå 28 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 detta är att krypteringsalgoritmen körs upprepade gånger, det är en teknik som används av PBKDF2 standarden. 6.2 Java EE – Inloggning Resultatet av arbetet uppfyller kravspecifikationen, arbetet tog dock en liten annan vändning än vad som var väntat när kravspecifikationen skrevs. Redan när specifikationen skapades var det tydligt att Java EE hade inbyggt stöd för säkerhet, men inte hur mycket eller på vilken nivå. Av den anledningen är kravspecifikationen formad för att täcka in nyskapande av säkerhetsfunktionerna om så skulle krävas. Detta blev dock inte resultatet då allt som behövdes fanns tillgängligt och endast hjälpklasser skapats utöver arbetet med att sätta sig in i det befintliga säkerhetssystemet. Java EE i allmänhet har varit en utmaning att lära sig. Mycket nytänk introduceras och vävs samman till ett bra system, men som kräver att man förstår stora delar av det för att det ska kunna användas effektivt. Under detta projekt har CDI varit en stor bromskloss, vid flera tillfällen har det visat sig att små missförstånd allvarligt påverkat utformningen av produkten. T.ex. finns det inget enkelt sätt att skapa en factory method(en metod som skapar en instans)[41] som returnerar en instans hanterad av containern. Jag är fortfarande osäker på hur detta kan göras och var tvungen att avsluta arbetet med detta för att projektet skulle avancera. Ett annat problem relaterat till CDI som möts i projektet är att arv och mer exakt val av implementation vid arv är klurigt att lösa, speciellt när arvet sträcker sig mellan olika moduler. Det lättaste sättet är att helt enkelt se till att endast en typ av implementation finns tillgänglig till varje gränssnitt. Det finns även andra metoder att lösa problemet, och jag är säker på att de fungerar utmärkt när man väl lärt sig dem. Men för mig fanns inte tid för att fördjupa mig i problemet för mycket och när inte något av mina test fungerade så lämnades det. Problemen som stöttes på har påverkat den slutliga produkten, t.ex. var tanken att authJSF skulle ärva securityBean och användas i JSF relaterad kod. Eftersom arvet här skapade problem för containern att välja implementation, och för att problemet inte gick lösa genom att definiera ytterligare notiser för att göra detta val, så separerades arvet och objekten får arbeta var för sig. En annan konsekvens i projektet som kommer sig av CDI är att userWrapper var tänkt att produceras av en factory method i en typ av gateway, detta skulle ge en lite renare design då wrappern helt enkelt hanterade säkerhet relaterat till entiteten och gatewayen fick sköta synkroniseringen med databasen. Även detta fick avbry29 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 tas för att tiden inte tillät tillräckligt djup efterforskning i hur man kan be containern att nyskapa en instans under körning. För närvarande fungerar systemet jag implementerat men jag ser ett behov av att tillåta användaren skapa frågor till databasen och att hämta kollektioner med användare. Detta stöds inte för närvarande, en lösning vore att skapa en version av Wrap som tillåter iterering, och på så vis tillåta användaren att indirekt kunna hantera en lista med användare. Problemet har undvikits p.g.a. att en bättre lösning nog går att nå med fördjupad kunskap i CDI. Angående lösenordskrypteringen som görs i applikationen så bör en gräns införas för hur länge en användare får vara inaktiv innan en lösenordsförnyelse måste genomföras för att kunna logga in. Detta för att säkerställa att inga svaga lösenord hänger kvar i programmet p.g.a. inaktiva användare. En annan sak som utelämnas i arbetet är lösenordskryptering innan den kommer till databasen. I nuvarande implementation så skickas uppgifterna som text och kan därför avlyssnas. En lösning är att bara kryptera lösenordet innan det skickas, men det har säkerhetsbrister. Bättre är det att använda SSL(en. Secure Sockets Layer)[42] för att säkra hela anslutningen. Dock är även detta bara säkert om det används på rätt sätt och det är ett ganska stort ämne och har därför inte tagits upp i denna rapport. SQL injektion(SQL kod skickas till databasen istället för text)[43] är en annan säkerhetsfråga som är relevant för projektet. Den säkerhetsbristen är däremot allmänt känd och genom att använda de metoder som erbjuds av många databas APIn så undviks problemet genom att inte skapa färdiga frågor med variablerna i frågan, utan att skapa frågor som definierar vart en variabel ska sättas in i frågan och sedan skicka med variabeln var för sig. En validering och om nödvändigt en omkodning sker då på variablerna som försäkrar databasens skydd. 6.3 Brute force attack Teoristudien rörande BFA resulterade i en lista med problem och förslag på lösningar, helt i enlighet med kravspecifikationen. Resultatet var väntat i det avseendet att det inte finns någon generell lösning på problemen kopplade till BFA. Dock hade jag förväntat mig att robotfilter skulle vara det närmaste en ultimat lösning som skulle gå att nå. Detta visade sig inte vara sant då det till och med har klassats som ett antimönster (tillsammans med hemliga frågor) av OWASP[44]. Det som borde motarbetas är Fall 3 i resultatet, om detta kan förhindras så fungerar lösningen även för fall 1 & 2. Eftersom detta projekt är tänkt att användas i skolväsendet så är inte en lösning som öppnar dörrar för DoS acceptabel. Att använda en hemlig fråga är ganska vanligt, men det skiljer sig inte mycket från att ha ytterligare ett lösenord med ett tips om vad det kan vara. Därför skulle det 30 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 gå att använda en Brute force attack för att lösa även den frågan, om man inte begränsar antalet försök. Vad händer när antalet försök är slut? Ytterligare en hemlig fråga? Även om iterationsdjupet ökar, vilket i sig motverkar attacken så känns det inte som ett särskilt robust system. Robotfilter är en god kandidat för detta projekt, även om den har svagheter så skulle stora resurser krävas för att kringgå filtret. Problemet med detta är att projektet är tänkt att vara användbart av unga individer. Innan användaren har blivit läskunnig så krävs givetvis hjälp för att logga in mm. Men slutprodukten är tänkt att vara anpassad så att så unga som möjligt ska kunna använda den. Att kräva att de som just lärt sig läsa ska kunna läsa en förvrängd, och möjligtvis engelsk, text är inte möjligt. Vidare är anledningen till att robotfilter förbjudits i vissa länder att det har visat sig vara svårt för vissa funktionshindrade att utföra dem, vilket gör det till en otänkbar lösning för projektet. Den lösning som utarbetats för projektet (men ännu ej implementerats) är en variant av tredje lösningen i fall 3. Genom att spara en kaka (en. Cookie, data lagrad hos klienten)[45] hos användaren som säger att den tidigare har lyckats logga in, och sedan lagra vilken inloggning det var som lyckades logga in med kakans id i databasen, kan samtliga konton hållas låsta om de inte ansluter från en enhet de framgångsrik har bekräftat sig på. Första gången användaren loggar in kan kan ett e-post (eller annat fristående meddelandesystem) användas för att skicka ett enhetslösenord som används för att registrera inloggningen från enheten. Lösningen har ett tydligt problem, en kaka kan förfalskas. En attack med förfalskad kaka kan se ut: 1. Den attackerande parten måste gissa kakans id, eller har en befintlig kaka kopierats. 2. Anfallaren måste antingen söka användare, eller vet den attackerande redan vilka användare som är kopplade till kakan. 3. En BFA startas mot användarna kopplade till kakan. Fördelen här är att en kraftig reduktion av möjliga mål skapats och därför begränsas antalet användare som blir lidande av åtgärder som görs. T.ex. är det möjligt att förkasta kakan om fler än fem inloggningsförsök misslyckas, och de användare som var kopplade till kakan måste åter bekräfta sig med en ny nyckel. När de väl identifierat sig så får de en session som inte är beroende av kakan och kan därför tillfullo använda systemet även om kakan raderas som konsekvens av en samtidig attack. Eftersom kakans id är en viktig del i att förhindra att kakorna enkelt kan förfalskas så bör identiteten vara både lång och oförutsägbar, möjligtvis en hash av en sekventiell id, kopplade användare och ett SALT. Systemet har även en god konsekvens i det att om en icke registrerad kaka används, så betyder det med stor sannolikhet att en attack har börjat. 31 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Arbetet kan anses ha lett projektet bort från robotfilter och till det förslag som presenterats, förslaget som lagts fram har förmodligen negativa aspekter som jag ännu inte har uppdagat. Förhoppningsvis finns inga brister som äventyrar den underliggande säkerheten och på så vis försämrar systemet. Eftersom förslaget blir ytterligare ett lager, inte ett substitut, bör det inte kunna påverka säkerheten negativt. 32 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 Källförteckning [1] J.R Suler, ”The psychology of cypterspace” http://users.rider.edu/~suler/psycyber/identitymanage.html sektion 4. Hämtad – 2015-05-02 [2] MeasuringU, ”Do users read licens agreements”, http://www.measuringu.com/blog/eula.php Hämtad 2015-05-02. [3] R. Cooks, The Wizardry Compiled, 1990 [4] Klein, Daniel V. "Foiling the cracker: A survey of, and improvements to, password security." Proceedings of the 2nd USENIX Security Workshop. 1990. Bishop, Matt, and Daniel V. Klein. "Improving system security via proactive password checking." Computers & Security 14.3 (1995): 233-249. [5] [6] R. Rivest, ”The MD5 Message-Digest Algorithm” https://www.ietf.org/rfc/rfc1321.txt Hämtad – 2015-06-10 [7] Common Vulnerbilities and Exposures (CVE), ”CVE-2012-3287 (MD5crypt)” http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-3287 Hämtad – 2015-05-17 [8] FIPS PUB, ”Secure hash standard” http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf [9] GoogleOnlineSecurity, ”Gradually sunsetting SHA-1” http://googleonlinesecurity.blogspot.se/2014/09/gradually-sunsetting-sha1.html Hämtad – 2015-05-16 [10] OWASP, ”Guide to Authentication – minimum hash strength ” https://www.owasp.org/index.php/Guide_to_Authentication Hämtad – 2015-05-20 [11] Gauravaram, Praveen. "Security Analysis of salt|| password Hashes." Advanced Computer Science Applications and Technologies (ACSAT), 2012 International Conference on. IEEE, 2012. 33 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 [12] Wikipedia, ”MD5”, http://sv.wikipedia.org/wiki/MD5 Hämtad – 2015-05-08 [13] Wikipedia, ”Rainbow table”, http://en.wikipedia.org/wiki/Rainbow_table Hämtad – 2015-05-08 [14] Computer Hope, ”Brute-force attack”, http://www.computerhope.com/jargon/b/brutforc.htm Hämtad – 2015-05-08 [15] Wikipedia, ”List of hash functions, Cryptographic hash functions”, http://en.wikipedia.org/wiki/List_of_hash_functions Hämtad – 2015-05-20 [16] Oracle, ”JAAS Reference guide”, http://docs.oracle.com/javase/7/docs/technotes/guides/security/jaas/JAAS RefGuide.html Hämtad – 2015-05-15 [17] Oracle, ”Java EE Tutorial, Security mechanism”, http://docs.oracle.com/javase/7/docs/technotes/guides/security/jaas/JAAS RefGuide.html Hämtad – 2015-05-15 [18] Oracle, ”MessageDigest dokumentation”, http://docs.oracle.com/javase/7/docs/api/java/security/MessageDigest.htm l Hämtad – 2015-05-16 [19] Oracle, ”Java EE, JavaServer Faces Technology”, http://www.oracle.com/technetwork/java/javaee/javaserverfaces139869.html Hämtad – 2015-05-21 [20] PrimeFaces, ”Ultimate JSF framework”, http://www.primefaces.org/ Hämtad – 2015-05-10 [21] Oracle, ”Unified expression language ”, http://docs.oracle.com/cd/E19226-01/820-7627/gjddd/ Hämtad – 2015-05-21 [22] Oracle, ”Java persistence API ”, http://www.oracle.com/technetwork/java/javaee/tech/persistence-jsp140049.html Hämtad – 2015-05-16 34 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 [23] Martin Fowler, ”Active Record”, http://www.martinfowler.com/eaaCatalog/activeRecord.html Hämtad – 2015-05-22 [24] Wikipedia, ”JavaBeans”, http://en.wikipedia.org/wiki/JavaBeans Hämtad – 2015-05-22 [25] Oracle, ”Overview of CDI”, https://docs.oracle.com/javaee/6/tutorial/doc/giwhl.html Hämtad – 2015-05-22 [26] Martin Fowler, ”Gateway”, http://martinfowler.com/eaaCatalog/gateway.html Hämtad – 2015-05-22 [27] Oracle, ”FacesContext dokumentation”, http://docs.oracle.com/javaee/6/api/javax/faces/context/FacesContext.htm l Hämtad – 2015-05-16 [28] Oracle, ”FacesMessage dokumentation”, http://docs.oracle.com/cd/E17802_01/j2ee/j2ee/javaserverfaces/1.1_01/d ocs/api/javax/faces/application/FacesMessage.html Hämtad – 2015-05-16 [29] Wikipedia, ”Java Naming and Dicrectory Interface”, http://en.wikipedia.org/wiki/Java_Naming_and_Directory_Interface Hämtad – 2015-05-20 [30] Wikipedia, ”PBKDF2”, http://en.wikipedia.org/wiki/PBKDF2 Hämtad – 2015-05-22 [31] Wikipedia, ”Salt”, http://en.wikipedia.org/wiki/Salt_%28cryptography%29 Hämtad – 2015-05-22 [32] Oracle, ”SecureRandom dokumentation”, https://docs.oracle.com/javase/7/docs/api/java/security/SecureRandom.ht ml Hämtad – 2015-05-16 [33] Oracle, ”Singelton session bean”, http://docs.oracle.com/javaee/6/tutorial/doc/gipvi.html Hämtad – 2015-05-16 35 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg 2015-06-16 [34] Oracle, ”Security Annotations and Authorization”, http://www.oracle.com/technetwork/articles/javaee/security-annotation142276.html Hämtad – 2015-05-22 [35] Wikipedia, ”Proxy”, http://sv.wikipedia.org/wiki/Proxy Hämtad – 2015-05-22 [36] OWASP, ”Denial of service” https://www.owasp.org/index.php/Denial_of_Service Hämtad – 2015-05-20 [37] Wikipedia, ”CAPTCHA”, http://en.wikipedia.org/wiki/CAPTCHA Hämtad – 2015-05-22 [38] RainbowCrack, ”List of rainbow tables” http://project-rainbowcrack.com/table.htm Hämtad – 2015-05-22 [39] Oxford Dictionaries, ”How many words are there in the English language” http://www.oxforddictionaries.com/words/how-many-words-are-there-inthe-english-language Hämtad – 2015-05-22 [40] MD5 My-Addr, ”Database Decrypt” http://md5.my-addr.com/md5_decryptmd5_cracker_online/md5_decoder_tool.php Hämtad – 2015-05-22 [41] OODesign, ”Factory method pattern”, http://www.oodesign.com/factory-method-pattern.html Hämtad – 2015-05-22 [42] Oracle, ”Secure connection usion SSL”, https://docs.oracle.com/javaee/6/tutorial/doc/bnbxw.html Hämtad – 2015-05-22 [43] OWASP, ”SQL Injection” https://www.owasp.org/index.php/SQL_Injection Hämtad – 2015-05-22 [44] OWASP, ”Guide to authentication - AntiPatterns” https://www.owasp.org/index.php/Guide_to_Authentication Hämtad – 2015-05-22 36 Inloggning – Lösenordskryptering och Brute force attack Emil Strandberg [45] Wikipedia, ”HTTP cookie”, http://en.wikipedia.org/wiki/HTTP_cookie Hämtad – 2015-05-22 37 2015-06-16 Bilaga A: Dokumentation av Java EE källkod Project Documentation 5/24/15 9:16 PM Package Summary Page se.mathplatform.bean 1 se.security.bean 9 se.security.encrypt 14 se.security.model 18 se.web.security.bean 43 DocFlex/Doclet -- 5/24/15 Page 1 of 46 Package se.mathplatform.bean Package se.mathplatform.bean Class Summary Page Account this class is a bean assosiated with a users account Its supporting /faces/pages/authenticated/account.xhtml 2 RecruitTeacher This class is used to recruit a teacher, it a simple test to ensure that groupmanagers can affect groups of other users. 5 Registrate This class is used to registered a new user Its supporting /faces/pages/signin.xhtml 7 DocFlex/Doclet -- 5/24/15 Page 2 of 46 Class Account Class Account se.mathplatform.bean java.lang.Object se.mathplatform.bean.Account @Model public class Account extends Object this class is a bean assosiated with a users account Its supporting /faces/pages/authenticated/account.xhtml Constructor Summary Page Account() 3 Method Summary Page voiddeActivateAccount() Deactivate the account, remove user form groups, and logout 4 StringgetOldPassword() 4 StringgetPassword1() 4 StringgetPassword2() 4 UsergetUser() 4 voidrenewPass() renews the users password the method creates global facesMessages if something userrelated is wrong voidsetOldPassword(String oldPassword) 3 4 voidsetPassword1(String password1) 4 voidsetPassword2(String password2) 4 Constructor Detail Account public Account() Method Detail renewPass public void renewPass() renews the users password the method creates global facesMessages if something userrelated is wrong DocFlex/Doclet -- 5/24/15 Page 3 of 46 Class Account deActivateAccount public void deActivateAccount() Deactivate the account, remove user form groups, and logout getUser public User getUser() getOldPassword public String getOldPassword() setOldPassword public void setOldPassword(String oldPassword) getPassword1 public String getPassword1() setPassword1 public void setPassword1(String password1) getPassword2 public String getPassword2() setPassword2 public void setPassword2(String password2) DocFlex/Doclet -- 5/24/15 Page 4 of 46 Class RecruitTeacher Class RecruitTeacher se.mathplatform.bean java.lang.Object se.mathplatform.bean.RecruitTeacher @Model public class RecruitTeacher extends Object This class is used to recruit a teacher, it a simple test to ensure that groupmanagers can affect groups of other users. Its supporting /faces/pages/authenticated/groupManager/recruitTeacher.xhtml Constructor Summary Page RecruitTeacher() 5 Method Summary Page voidexecute() this will attempt to add the defined user to the teacher role StringgetUsername() voidsetUsername(String 5 5 username) 6 Constructor Detail RecruitTeacher public RecruitTeacher() Method Detail execute public void execute() this will attempt to add the defined user to the teacher role creates global facesMessages to inform the user about problems they can solve getUsername public String getUsername() DocFlex/Doclet -- 5/24/15 Page 5 of 46 Class RecruitTeacher setUsername public void setUsername(String username) DocFlex/Doclet -- 5/24/15 Page 6 of 46 Class Registrate Class Registrate se.mathplatform.bean java.lang.Object se.mathplatform.bean.Registrate All Implemented Interfaces: Serializable @Model public class Registrate extends Object implements Serializable This class is used to registered a new user Its supporting /faces/pages/signin.xhtml Constructor Summary Page Registrate() 7 Method Summary Page StringgetPassword1() 8 StringgetPassword2() 8 StringgetUsername() 8 Stringregistrate() Tries to registrate a new user with the supplied values. 7 voidsetPassword1(String password1) 8 voidsetPassword2(String password2) 8 voidsetUsername(String username) 8 Constructor Detail Registrate public Registrate() Method Detail registrate public String registrate() Tries to registrate a new user with the supplied values. informs the user by creating global facesMessages DocFlex/Doclet -- 5/24/15 Page 7 of 46 Class Registrate Returns: empty string, left for navigation purposes getPassword1 public String getPassword1() getPassword2 public String getPassword2() getUsername public String getUsername() setPassword1 public void setPassword1(String password1) setPassword2 public void setPassword2(String password2) setUsername public void setUsername(String username) DocFlex/Doclet -- 5/24/15 Page 8 of 46 Package se.security.bean Package se.security.bean Interface Summary Security This interface defines methods to manage some common security related features in an application. Class Summary SecurityBean Page SecurityBean implements security its used to perform some common security related functions, this implementation can be used in the business layer as well as in the presentation. DocFlex/Doclet -- 5/24/15 9 Page 12 Page 9 of 46 Interface Security Interface Security se.security.bean All Known Implementing Classes: SecurityBean public interface Security This interface defines methods to manage some common security related features in an application. Method Summary Page StringgetAuthenticatedUserName() 11 used to get the name of a user booleanisAuthenticated() 11 Package se.security.bean Package se.security.bean Interface Summary Security Page This interface defines methods to manage some common security related features in an application. Class Summary SecurityBean 9 Page SecurityBean implements security its used to perform some common security related functions, this implementation can be used in the business layer as well as in the presentation. 12 This method is used to check if the user is authenticated, bow. booleanisAuthorized(String singleRoleOrCommaSeperatedRoleList) The method is used to check if a user is in a role. DocFlex/Doclet -- 5/24/15 11 Page 10 of 46 Interface Security Method Detail isAuthorized boolean isAuthorized(String singleRoleOrCommaSeperatedRoleList) The method is used to check if a user is in a role. Parameters: singleRoleOrCommaSeperatedRoleList - A comma separated list of roles to check, if a single role, then don't use a trailing comma Returns: True if authenticated user is in one of the supplied roles, else false isAuthenticated boolean isAuthenticated() This method is used to check if the user is authenticated, bow. if the user has a none anonymous session context Returns: True if user is authenticated, else false getAuthenticatedUserName String getAuthenticatedUserName() used to get the name of a user Returns: username if authenticated, else null DocFlex/Doclet -- 5/24/15 Page 11 of 46 Class SecurityBean Class SecurityBean se.security.bean java.lang.Object se.security.bean.SecurityBean All Implemented Interfaces: Security, Serializable @Named @Dependent public class SecurityBean extends Object implements Serializable, Security SecurityBean implements security its used to perform some common security related functions, this implementation can be used in the business layer as well as in the presentation. Overrided methods is documented by there supertype, aslong as they fulfill the contracts stated there. Constructor Summary Page SecurityBean() 12 Method Summary Page StringgetAuthenticatedUserName() used to get the name of a user booleanisAuthenticated() This method is used to check if the user is authenticated, bow. booleanisAuthorized(String singleRoleOrCommaSeperatedRoleList) The method is used to check if a user is in a role. 12 13 13 Constructor Detail SecurityBean public SecurityBean() Method Detail getAuthenticatedUserName public String getAuthenticatedUserName() Description copied from interface: Security used to get the name of a user DocFlex/Doclet -- 5/24/15 Page 12 of 46 Class SecurityBean Specified by: getAuthenticatedUserName in interface Security Returns: username if authenticated, else null isAuthenticated public boolean isAuthenticated() Description copied from interface: Security This method is used to check if the user is authenticated, bow. if the user has a none anonymous session context Specified by: isAuthenticated in interface Security Returns: True if user is authenticated, else false isAuthorized public boolean isAuthorized(String singleRoleOrCommaSeperatedRoleList) Description copied from interface: Security The method is used to check if a user is in a role. Specified by: isAuthorized in interface Security Parameters: singleRoleOrCommaSeperatedRoleList - A comma separated list of roles to check, if a single role, then don't use a trailing comma Returns: True if authenticated user is in one of the supplied roles, else false DocFlex/Doclet -- 5/24/15 Page 13 of 46 Package se.security.encrypt Package se.security.encrypt Class Summary PasswordServic this class can be used to manage password hashing. e DocFlex/Doclet -- 5/24/15 Page 14 Page 14 of 46 Class PasswordService Class PasswordService se.security.encrypt java.lang.Object se.security.encrypt.PasswordService @Named public class PasswordService extends Object this class can be used to manage password hashing. Its properties can be set through the associated modules deployment descriptor. Base64 encoding is used. The properties that can be set: Name Type Default Description The algorithm used to hash the password, SecretKeyFactory_algorit PBKDF2WithHmacS String supported types @see hm HA256 SecretKeyFactory.getInstance(String) Length of the key (0 for ficed length) @see KeySpec_length int 256 PBEKeySpec.getKeyLength() Iterations to perform @see KeySpec_iterations int 2000 PBEKeySpec.getIterationCount() Salt_length int 16 Length of the generated salt the algorithm to produce a secure random Salt_algorithm String SHA1PRNG salt @see SecureRandom.getAlgorithm() the provider of the salt algorithm @see Salt_provider String SUN SecureRandom.getProvider() TODO: Create a interface Constructor Summary Page PasswordService() 15 Method Summary StringencryptPassword(String Page password, String salt, PasswordSpecification ps) this method encrypts the password according to the supplied PasswordSpecification. StringgenerateSalt() This method generate a salt string, it uses SecureRandom to do this. PasswordSpegetPasswordSpecs() cification This method is used to acquire the current PasswordSpecification to use when encrypting/hashing booleanisCurrent(PasswordSpecification ps) checks if the supplied PasswordSpecification is of the latest version 16 16 16 16 Constructor Detail PasswordService public PasswordService() DocFlex/Doclet -- 5/24/15 Page 15 of 46 Class PasswordService Method Detail encryptPassword public String encryptPassword(String password, String salt, PasswordSpecification ps) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException this method encrypts the password according to the supplied PasswordSpecification. If its a new encryption the current specification can be acquired by calling getPasswordSpecs() Parameters: password - the unencrypted password. salt - the salt to include in the encryption procedure. ps - the PasswordSpecification to encrypt by. Returns: the encrypted password. Throws: NoSuchAlgorithmException - if configured incorrectly InvalidKeySpecException - if configured incorrectly * NoSuchProviderException - if configured incorrectly getPasswordSpecs public PasswordSpecification getPasswordSpecs() This method is used to acquire the current PasswordSpecification to use when encrypting/hashing Returns: the current version of PasswordSpecification isCurrent public boolean isCurrent(PasswordSpecification ps) checks if the supplied PasswordSpecification is of the latest version Parameters: ps - the PasswordSpecification to check Returns: true if the supplied PasswordSpecification is the latest, else false generateSalt public String generateSalt() throws NoSuchAlgorithmException, NoSuchProviderException This method generate a salt string, it uses SecureRandom to do this. DocFlex/Doclet -- 5/24/15 Page 16 of 46 Class PasswordService Returns: a random string produced by defined properties Throws: NoSuchAlgorithmException - if configured incorrectly NoSuchProviderException - if configured incorrectly DocFlex/Doclet -- 5/24/15 Page 17 of 46 Package se.security.model Package se.security.model Interface Summary Page User an interface defining a user. 24 UserWrap simply to make CDI behave as expected 34 Wrap this is an interface defining how to handle a wrapping object 41 Class Summary Page initDevDatabaseThis class is only for development. 18 This class works ass a structure holding properties associated with a encrypted/hashed PasswordSpecif password, its used mainly in association with PasswordService and then stored ication embedded in the UserEntity 20 PasswordSpecif ication_ 22 UserEntity 28 this is the entity class representing a user. 32 UserEntity_ UserWrapper This is a class that wraps the user entity in this project, this class is mainly used to enforce security constraints to the entity's properties. IMPORTANT: This is container managed object so don't instantiate it manually 34 Documentation is only written when the superclass documentation doesn't match the implementation. DocFlex/Doclet -- 5/24/15 Page 18 of 46 Class initDevDatabase Class initDevDatabase se.security.model java.lang.Object se.security.model.initDevDatabase public class initDevDatabase extends Object This class is only for development. it must be removed before publishing this application The purpose of the class is to add test users to the system. users added are: Name Password Group student student STUDENT teacher teacher TEACHER school_admin school_admin SCHOOL_ADMIN group_manager group_manager GROUP_MANAGER Constructor Summary initDevDatabase() Page 19 Constructor Detail initDevDatabase public initDevDatabase() DocFlex/Doclet -- 5/24/15 Page 19 of 46 Class PasswordSpecification Class PasswordSpecification se.security.model java.lang.Object se.security.model.PasswordSpecification @Embeddable public class PasswordSpecification extends Object This class works ass a structure holding properties associated with a encrypted/hashed password, its used mainly in association with PasswordService and then stored embedded in the UserEntity Field Summary Stringalgorithm Page 20 intiterations 20 intkeyLength 20 StringsaltAlgorithm 21 intsaltLength 21 StringsaltProvider 21 Constructor Summary Page PasswordSpecification() 21 PasswordSpecification(String algorithm, int iterations, int keyLength, String saltAlgorithm, String saltProvider, int saltLength) 21 creates a PasswordSpecification with the supplied arguments. Field Detail algorithm public final String algorithm iterations public final int iterations keyLength public final int keyLength DocFlex/Doclet -- 5/24/15 Page 20 of 46 Class PasswordSpecification saltAlgorithm public final String saltAlgorithm saltProvider public final String saltProvider saltLength public final int saltLength Constructor Detail PasswordSpecification public PasswordSpecification() PasswordSpecification public PasswordSpecification(String algorithm, int iterations, int keyLength, String saltAlgorithm, String saltProvider, int saltLength) creates a PasswordSpecification with the supplied arguments. The salt properties are strictly not necessary to repeat the encryption, but its used to decide if the password should be reencrypted after a salt related property changes. Parameters: algorithm - the password algorithm used in the encryption procedure iterations - the number of iterations done in the encryption procedure keyLength - the length of the produced key saltAlgorithm - the algorithm used to produce a secureRandom salt value saltProvider - the provider of the saltAlgorithm saltLength - the length of the produced salt. DocFlex/Doclet -- 5/24/15 Page 21 of 46 Class PasswordSpecification_ Class PasswordSpecification_ se.security.model java.lang.Object se.security.model.PasswordSpecification_ @Generated(value="Dali", date="2015-05-21T04:23:23.755+0200") public class PasswordSpecification_ extends Object Field Summary Page staticalgorithm SingularAtt ribute<Pass wordSpecifi cation,Stri ng> 22 staticiterations SingularAtt ribute<Pass wordSpecifi cation,Inte ger> 23 statickeyLength SingularAtt ribute<Pass wordSpecifi cation,Inte ger> 23 staticsaltAlgorithm SingularAtt ribute<Pass wordSpecifi cation,Stri ng> 23 staticsaltLength SingularAtt ribute<Pass wordSpecifi cation,Inte ger> 23 staticsaltProvider SingularAtt ribute<Pass wordSpecifi cation,Stri ng> 23 Constructor Summary Page PasswordSpecification_() 23 Field Detail algorithm public static volatile SingularAttribute<PasswordSpecification,String> algorithm DocFlex/Doclet -- 5/24/15 Page 22 of 46 Class PasswordSpecification_ iterations public static volatile SingularAttribute<PasswordSpecification,Integer> iterations keyLength public static volatile SingularAttribute<PasswordSpecification,Integer> keyLength saltAlgorithm public static volatile SingularAttribute<PasswordSpecification,String> saltAlgorithm saltProvider public static volatile SingularAttribute<PasswordSpecification,String> saltProvider saltLength public static volatile SingularAttribute<PasswordSpecification,Integer> saltLength Constructor Detail PasswordSpecification_ public PasswordSpecification_() DocFlex/Doclet -- 5/24/15 Page 23 of 46 Interface User Interface User se.security.model All Known Subinterfaces: UserWrap All Known Implementing Classes: UserEntity, UserWrapper public interface User an interface defining a user. Method Summary Page voidaddToGroup(String g) 26 adds a user to the group List<StringgetGroups() > 26 StringgetPassword() 24 PasswordSpegetPasswordSpecification() cification 25 StringgetSalt() 26 StringgetUsername() 26 booleanisActive() 26 checks if the users account is active. booleanremoveFromGroup(String g) 26 removes the user from a group voidsetActive(boolean active) 27 set the active status of the user voidsetPassword(String password) 25 sets the users password booleansetPasswordSpecification(PasswordSpecification ps) sets the users PasswordSpecification this can only be done if updatePassword(String, String) or setPassword(String) has been called before this method is called booleansetSalt(String 25 Salt) sets the users salt this can only be done if updatePassword(String, String) or setPassword(String) has been called before this method is called booleanupdatePassword(String oldPassword, String newPassword) update the users password 25 25 Method Detail getPassword String getPassword() DocFlex/Doclet -- 5/24/15 Page 24 of 46 Interface User Returns: returns the users password updatePassword boolean updatePassword(String oldPassword, String newPassword) update the users password Parameters: oldPassword - the password currently in use newPassword - the password to set instead Returns: true if update is successful, else false setPassword void setPassword(String password) sets the users password Parameters: password - the password to set for the user setPasswordSpecification boolean setPasswordSpecification(PasswordSpecification ps) sets the users PasswordSpecification this can only be done if updatePassword(String, String) or setPassword(String) has been called before this method is called Parameters: ps - the passwordspecification used to encrupt the users password Returns: true if success, else false getPasswordSpecification PasswordSpecification getPasswordSpecification() Returns: users PasswordSpecification setSalt boolean setSalt(String Salt) sets the users salt this can only be done if updatePassword(String, String) or setPassword(String) has been called before this method is called DocFlex/Doclet -- 5/24/15 Page 25 of 46 Interface User Parameters: Salt - the salt used when encrypting the users password Returns: true if success, else false getSalt String getSalt() Returns: users salt getGroups List<String> getGroups() Returns: an unmodifiable list of the groups the user is currently in addToGroup void addToGroup(String g) adds a user to the group Parameters: g - name of the group removeFromGroup boolean removeFromGroup(String g) removes the user from a group Parameters: g - the name of the group to remove the user from Returns: true if successfuly removed getUsername String getUsername() Returns: the users username witch acts as a primary key isActive boolean isActive() DocFlex/Doclet -- 5/24/15 Page 26 of 46 Interface User checks if the users account is active. Returns: true if active, else false setActive void setActive(boolean active) set the active status of the user Parameters: active - set the user active (true) or inactive (false) DocFlex/Doclet -- 5/24/15 Page 27 of 46 Class UserEntity Class UserEntity se.security.model java.lang.Object se.security.model.UserEntity All Implemented Interfaces: Serializable, User @Entity(name="S_USERS") public class UserEntity extends Object implements User, Serializable this is the entity class representing a user. its not intended to be used by the system, instead use UserWrapper Method Summary Page voidaddToGroup(String g) 30 adds a user to the group List<StringgetGroups() > 30 StringgetPassword() 29 PasswordSpegetPasswordSpecification() cification 29 StringgetSalt() 30 StringgetUsername() 31 booleanisActive() 31 checks if the users account is active. booleanremoveFromGroup(String g) 30 removes the user from a group voidsetActive(boolean active) 31 set the active status of the user voidsetPassword(String password) 29 sets the users password booleansetPasswordSpecification(PasswordSpecification ps) sets the users PasswordSpecification this can only be done if User.updatePassword(String, String) or User.setPassword(String) has been called before this method is called booleansetSalt(String salt) sets the users salt this can only be done if User.updatePassword(String, String) or User.setPassword(String) has been called before this method is called booleanupdatePassword(String oldPassword, String newPassword) update the users password DocFlex/Doclet -- 5/24/15 29 29 31 Page 28 of 46 Class UserEntity Method Detail getPassword public String getPassword() Specified by: getPassword in interface User Returns: returns the users password setPassword public void setPassword(String password) Description copied from interface: User sets the users password Specified by: setPassword in interface User Parameters: password - the password to set for the user getPasswordSpecification public PasswordSpecification getPasswordSpecification() Specified by: getPasswordSpecification in interface User Returns: users PasswordSpecification setPasswordSpecification public boolean setPasswordSpecification(PasswordSpecification ps) Description copied from interface: User sets the users PasswordSpecification this can only be done if User.updatePassword(String, String) or User.setPassword(String) has been called before this method is called Specified by: setPasswordSpecification in interface User Parameters: ps - the passwordspecification used to encrupt the users password Returns: true if success, else false setSalt public boolean setSalt(String salt) DocFlex/Doclet -- 5/24/15 Page 29 of 46 Class UserEntity Description copied from interface: User sets the users salt this can only be done if User.updatePassword(String, String) or User.setPassword(String) has been called before this method is called Specified by: setSalt in interface User Returns: true if success, else false getSalt public String getSalt() Specified by: getSalt in interface User Returns: users salt getGroups public List<String> getGroups() Specified by: getGroups in interface User Returns: an unmodifiable list of the groups the user is currently in addToGroup public void addToGroup(String g) Description copied from interface: User adds a user to the group Specified by: addToGroup in interface User Parameters: g - name of the group removeFromGroup public boolean removeFromGroup(String g) Description copied from interface: User removes the user from a group Specified by: removeFromGroup in interface User Parameters: g - the name of the group to remove the user from Returns: true if successfuly removed DocFlex/Doclet -- 5/24/15 Page 30 of 46 Class UserEntity getUsername public String getUsername() Specified by: getUsername in interface User Returns: the users username witch acts as a primary key isActive public boolean isActive() Description copied from interface: User checks if the users account is active. Specified by: isActive in interface User Returns: true if active, else false setActive public void setActive(boolean active) Description copied from interface: User set the active status of the user Specified by: setActive in interface User Parameters: active - set the user active (true) or inactive (false) updatePassword public boolean updatePassword(String oldPassword, String newPassword) Description copied from interface: User update the users password Specified by: updatePassword in interface User Parameters: oldPassword - the password currently in use newPassword - the password to set instead Returns: true if update is successful, else false DocFlex/Doclet -- 5/24/15 Page 31 of 46 Class UserEntity_ Class UserEntity_ se.security.model java.lang.Object se.security.model.UserEntity_ @Generated(value="Dali", date="2015-05-24T00:05:59.773+0200") public class UserEntity_ extends Object Field Summary Page staticactive SingularAtt ribute<User Entity,Bool ean> 33 staticgroups SetAttribut e<UserEntit y,String> 33 staticpassword SingularAtt ribute<User Entity,Stri ng> 33 staticpasswordSpecification SingularAtt ribute<User Entity,Pass wordSpecifi cation> 33 staticsalt SingularAtt ribute<User Entity,Stri ng> 33 staticusername SingularAtt ribute<User Entity,Stri ng> 32 staticversion SingularAtt ribute<User Entity,Long > 33 Constructor Summary UserEntity_() Page 33 Field Detail username public static volatile SingularAttribute<UserEntity,String> username DocFlex/Doclet -- 5/24/15 Page 32 of 46 Class UserEntity_ password public static volatile SingularAttribute<UserEntity,String> password active public static volatile SingularAttribute<UserEntity,Boolean> active version public static volatile SingularAttribute<UserEntity,Long> version groups public static volatile SetAttribute<UserEntity,String> groups passwordSpecification public static volatile SingularAttribute<UserEntity,PasswordSpecification> passwordSpecification salt public static volatile SingularAttribute<UserEntity,String> salt Constructor Detail UserEntity_ public UserEntity_() DocFlex/Doclet -- 5/24/15 Page 33 of 46 Interface UserWrap Interface UserWrap se.security.model All Superinterfaces: User, Wrap All Known Implementing Classes: UserWrapper public interface UserWrap extends Wrap, User simply to make CDI behave as expected Methods inherited from interface se.security.model.Wrap cleanWrap, isWrapping, mergeWrap, wrapByPK, wrapNew Methods inherited from interface se.security.model.User addToGroup, getGroups, getPassword, getPasswordSpecification, getSalt, getUsername, isActive, removeFromGroup, setActive, setPassword, setPasswordSpecification, setSalt, updatePassword DocFlex/Doclet -- 5/24/15 Page 34 of 46 Class UserWrapper Class UserWrapper se.security.model java.lang.Object se.security.model.UserWrapper All Implemented Interfaces: User, UserWrap, Wrap @Named @Dependent public class UserWrapper extends Object implements UserWrap This is a class that wraps the user entity in this project, this class is mainly used to enforce security constraints to the entity's properties. IMPORTANT: This is container managed object so don't instantiate it manually Documentation is only written when the superclass documentation doesn't match the implementation. Method Summary voidaddToGroup(String Page g) 38 adds a user to the group voidcleanWrap() 37 removes the contained object from the wrap List<StringgetGroups() > 38 StringgetPassword() 37 PasswordSpegetPasswordSpecification() cification 38 StringgetSalt() 38 StringgetUsername() 39 booleanisActive() 39 checks if the users account is active. booleanisWrapping() 37 checks if the wrap is currently wrapping an object voidmergeWrap() 36 Merges the wraps entity with the database. booleanremoveFromGroup(String g) 38 removes the user from a group voidsetActive(boolean active) 39 set the active status of the user voidsetPassword(String password) 40 sets the users password booleansetPasswordSpecification(PasswordSpecification ps) sets the users PasswordSpecification this can only be done if User.updatePassword(String, String) or User.setPassword(String) has been called before this method is called DocFlex/Doclet -- 5/24/15 39 Page 35 of 46 Class UserWrapper booleansetSalt(String Salt) sets the users salt this can only be done if User.updatePassword(String, String) or User.setPassword(String) has been called before this method is called booleanupdatePassword(String oldPassword, String newPassword) 37 update the users password booleanwrapByPK(String name) 36 wraps an object by its primarykey booleanwrapNew(String 40 name, String password) 36 Creates an entity and wraps it. Method Detail wrapByPK public boolean wrapByPK(String name) Description copied from interface: Wrap wraps an object by its primarykey Specified by: wrapByPK in interface Wrap Returns: if entity was successfully wrapped, true, else false wrapNew public boolean wrapNew(String name, String password) Description copied from interface: Wrap Creates an entity and wraps it. Take a look at EntityManager.persist(Object) for hidden exceptions Specified by: wrapNew in interface Wrap Returns: if successful wrap, true, else false TODO: this method should be generalized Throws: RuntimeException - if system configurations related to password encryptions is wrong mergeWrap public void mergeWrap() Description copied from interface: Wrap Merges the wraps entity with the database. Take a look at EntityManager.merge(Object) for hidden exceptions Also remember that entity's might throw concurrency exceptions DocFlex/Doclet -- 5/24/15 Page 36 of 46 Class UserWrapper Specified by: mergeWrap in interface Wrap cleanWrap public void cleanWrap() Description copied from interface: Wrap removes the contained object from the wrap Specified by: cleanWrap in interface Wrap isWrapping public boolean isWrapping() Description copied from interface: Wrap checks if the wrap is currently wrapping an object Specified by: isWrapping in interface Wrap Returns: true if wrapping an entity, else false getPassword public String getPassword() Specified by: getPassword in interface User Returns: returns the users password updatePassword public boolean updatePassword(String oldPassword, String newPassword) Description copied from interface: User update the users password Specified by: updatePassword in interface User Parameters: oldPassword - the password currently in use newPassword - the password to set instead Returns: true if update is successful, else false Throws: RuntimeException - if system configurations related to password encryptions is wrong DocFlex/Doclet -- 5/24/15 Page 37 of 46 Class UserWrapper getPasswordSpecification public PasswordSpecification getPasswordSpecification() Specified by: getPasswordSpecification in interface User Returns: users PasswordSpecification getSalt public String getSalt() Specified by: getSalt in interface User Returns: users salt getGroups public List<String> getGroups() Specified by: getGroups in interface User Returns: an unmodifiable list of the groups the user is currently in addToGroup @RolesAllowed(value="GROUP_MANAGER") public void addToGroup(String g) Description copied from interface: User adds a user to the group Specified by: addToGroup in interface User Parameters: g - name of the group removeFromGroup @RolesAllowed(value={ "GROUP_MANAGER", "STUDENT", "TEACHER", "SCHOOL_ADMIN" }) public boolean removeFromGroup(String g) Description copied from interface: User removes the user from a group Specified by: removeFromGroup in interface User DocFlex/Doclet -- 5/24/15 Page 38 of 46 Class UserWrapper Parameters: g - the name of the group to remove the user from Returns: true if successfuly removed getUsername public String getUsername() Specified by: getUsername in interface User Returns: the users username witch acts as a primary key isActive public boolean isActive() Description copied from interface: User checks if the users account is active. Specified by: isActive in interface User Returns: true if active, else false setActive public void setActive(boolean active) Description copied from interface: User set the active status of the user Specified by: setActive in interface User Parameters: active - set the user active (true) or inactive (false) setPasswordSpecification @DenyAll public boolean setPasswordSpecification(PasswordSpecification ps) Description copied from interface: User sets the users PasswordSpecification this can only be done if User.updatePassword(String, String) or User.setPassword(String) has been called before this method is called Specified by: setPasswordSpecification in interface User Parameters: ps - the passwordspecification used to encrupt the users password Returns: true if success, else false DocFlex/Doclet -- 5/24/15 Page 39 of 46 Class UserWrapper setSalt @DenyAll public boolean setSalt(String Salt) Description copied from interface: User sets the users salt this can only be done if User.updatePassword(String, String) or User.setPassword(String) has been called before this method is called Specified by: setSalt in interface User Parameters: Salt - the salt used when encrypting the users password Returns: true if success, else false setPassword @DenyAll public void setPassword(String password) Description copied from interface: User sets the users password Specified by: setPassword in interface User Parameters: password - the password to set for the user DocFlex/Doclet -- 5/24/15 Page 40 of 46 Interface Wrap Interface Wrap se.security.model All Known Subinterfaces: UserWrap All Known Implementing Classes: UserWrapper public interface Wrap this is an interface defining how to handle a wrapping object Method Summary Page voidcleanWrap() removes the contained object from the wrap booleanisWrapping() checks if the wrap is currently wrapping an object voidmergeWrap() Merges the wraps entity with the database. booleanwrapByPK(String pk) wraps an object by its primarykey booleanwrapNew(String pk, String password) Creates an entity and wraps it. 42 42 42 41 41 Method Detail wrapByPK boolean wrapByPK(String pk) wraps an object by its primarykey Parameters: pk - primarykey of the entity to wrap Returns: if entity was successfully wrapped, true, else false wrapNew boolean wrapNew(String pk, String password) Creates an entity and wraps it. Take a look at EntityManager.persist(Object) for hidden exceptions DocFlex/Doclet -- 5/24/15 Page 41 of 46 Interface Wrap Returns: if successful wrap, true, else false TODO: this method should be generalized mergeWrap void mergeWrap() Merges the wraps entity with the database. Take a look at EntityManager.merge(Object) for hidden exceptions Also remember that entity's might throw concurrency exceptions cleanWrap void cleanWrap() removes the contained object from the wrap isWrapping boolean isWrapping() checks if the wrap is currently wrapping an object Returns: true if wrapping an entity, else false DocFlex/Doclet -- 5/24/15 Page 42 of 46 Package se.web.security.bean Package se.web.security.bean Interface Summary Authentication Page This interface is used to define methods to manage user session authentication 43 Class Summary AuthJSF Page this is a helper class to be used from JSF EL, its used to manage user authentication DocFlex/Doclet -- 5/24/15 45 Page 43 of 46 Interface Authentication Interface Authentication se.web.security.bean All Known Implementing Classes: AuthJSF public interface Authentication This interface is used to define methods to manage user session authentication Method Summary voidlogin(String Page username, String password) this method is used to login to the application. 44 voidloginForm() This method extracts name and password from form fields named j_username and j_password and then calls login(String, String) voidlogout() this method logs the user out from the application. 44 44 Method Detail loginForm void loginForm() This method extracts name and password from form fields named j_username and j_password and then calls login(String, String) login void login(String username, String password) this method is used to login to the application. Parameters: username - the username of the user trying to authenticate password - the unencrypted password used to authenticate logout void logout() this method logs the user out from the application. DocFlex/Doclet -- 5/24/15 Page 44 of 46 Class AuthJSF Class AuthJSF se.web.security.bean java.lang.Object se.web.security.bean.AuthJSF All Implemented Interfaces: Authentication @Model public class AuthJSF extends Object implements Authentication this is a helper class to be used from JSF EL, its used to manage user authentication Constructor Summary AuthJSF() Page 45 Method Summary voidlogin(String Page username, String password) Creates global facesMessages with user associated errors and information voidloginForm() Creates global facesMessages with user associated errors and information voidlogout() Creates global facesMessages with user associated errors and information 46 45 46 Constructor Detail AuthJSF public AuthJSF() Method Detail loginForm public void loginForm() Creates global facesMessages with user associated errors and information Specified by: loginForm in interface Authentication DocFlex/Doclet -- 5/24/15 Page 45 of 46 Class AuthJSF login public void login(String username, String password) Creates global facesMessages with user associated errors and information Specified by: login in interface Authentication Parameters: username - the username of the user trying to authenticate password - the unencrypted password used to authenticate logout public void logout() Creates global facesMessages with user associated errors and information Specified by: logout in interface Authentication Java API documentation generated with DocFlex/Doclet v1.6.1 DocFlex/Doclet is both a multi-format Javadoc doclet and a free edition of DocFlex/Javadoc. If you need to customize your Javadoc without writing a full-blown doclet from scratch, DocFlex/Javadoc may be the only tool able to help you! Find out more at www.docflex.com DocFlex/Doclet -- 5/24/15 Page 46 of 46 Bilaga B: Källkod Java EE Konfigurations filer Project – Deployment Descriptors Table of Contents Project – Deployment Descriptors........................................................................................................1 Presentation web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>MathplatformWeb</display-name> <welcome-file-list> <welcome-file>faces/home.xhtml</welcome-file> </welcome-file-list> <login-config> <auth-method>FORM</auth-method> <realm-name>MathplatformSecurityRealm</realm-name> <form-login-config> <form-login-page>/faces/pages/signin.xhtml</form-login-page> <form-error-page>/faces/pages/signin.xhtml</form-error-page> </form-login-config> </login-config> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping> <security-constraint> <display-name></display-name> <web-resource-collection> <web-resource-name></web-resource-name> <url-pattern>/faces/pages/authenticated/groupManager/*</urlpattern> </web-resource-collection> <auth-constraint> <role-name>GROUP_MANAGER</role-name> </auth-constraint> </security-constraint> </web-app> Security project ejb-jar.xml <?xml version="1.0" encoding="UTF-8"?> <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" metadatacomplete="false"> <enterprise-beans> <session> <!-- test configuration --> <ejb-name>PasswordService</ejb-name> <env-entry> <env-entry-name>SecretKeyFactory_algorithm</env-entryname> <env-entry-type>java.lang.String</env-entry-type> <env-entry-value>PBKDF2WithHmacSHA256</env-entry-value> </env-entry> <env-entry> <env-entry-name>KeySpec_iterations</env-entry-name> <env-entry-type>java.lang.Integer</env-entry-type> <env-entry-value>3000</env-entry-value> </env-entry> </session> </enterprise-beans> <assembly-descriptor> <security-role> <role-name>STUDENT</role-name> </security-role> <security-role> <role-name>SCHOOL_ADMIN</role-name> </security-role> <security-role> <role-name>TEACHER</role-name> </security-role> <security-role> <role-name>GROUP_MANAGER</role-name> </security-role> </assembly-descriptor> </ejb-jar> Presentation project – HTML pages Empty pages not included. Table of Contents Presentation project – HTML pages.....................................................................................................1 Faces/tempaltes................................................................................................................................1 baseTemplate.xhtml....................................................................................................................1 faces/defaultCompositions...............................................................................................................2 content.xhtml...............................................................................................................................2 navMenu.xhtml...........................................................................................................................2 userMenu.xhtml..........................................................................................................................3 faces/pages.......................................................................................................................................4 signin.xhtml.................................................................................................................................4 faces/pages/authenticated.................................................................................................................6 account.xhtml..............................................................................................................................6 faces/authenticated/groupManager/.................................................................................................8 recruitTeacher.xhtml....................................................................................................................8 Faces/tempaltes baseTemplate.xhtml <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <ui:insert name="head"> </ui:insert> <title>Matteplattformen - <ui:insert name="title"> </ui:insert></title> </h:head> <h:body> <h:outputStylesheet name="base-style.css" library="css" /> <div id="userMenu" class="userMenu"> <ui:insert name="userMenu"> <ui:include src="/faces/defaultCompositions/userMenu.xhtml" /> </ui:insert> </div> <div id="navMenu" class="navMenu"> <ui:insert name="navMenu"> <ui:include src="/faces/defaultCompositions/navMenu.xhtml" /> </ui:insert> </div> <div id="content" class="content"> <ui:insert name="content"> <ui:include src="/faces/defaultCompositions/content.xhtml" /> </ui:insert> </div> </h:body> </html> faces/defaultCompositions content.xhtml <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:f="http://java.sun.com/jsf/core"> <div>default content.</div> </ui:composition> navMenu.xhtml <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"> <div> <h:form> <p:growl id="messages" showDetail="false" /> <p:menu toggleable="true"> <p:menuitem value="Hem" url="/faces/home.xhtml" /> <p:menuitem value="Om sidan" url="/faces/pages/about.xhtml" /> <p:submenu label="Documentation"> <p:menuitem value="Allmänt" url="/faces/pages/doc/general.xhtml" /> <p:menuitem value="Lärare" url="/faces/pages/doc/teachers.xhtml" /> </p:submenu> <p:submenu label="Spel"> <p:menuitem value="Tärning" url="/faces/pages/games/dices.xhtml" /> </p:submenu> <p:submenu label="Kurser" expanded="false"> <p:menuitem value="f-3" url="/faces/pages/courses/f-3.xhtml" /> </p:submenu> </p:menu> </h:form> </div> </ui:composition> userMenu.xhtml <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui" xmlns:fn="http://java.sun.com/jsp/jstl/functions"> <!-- byta mot toolbar? --> <div> <h:form> <p:menubar> <p:menuitem> <div style="padding-left: 20px; padding-right: 20px;"> logo here</div> </p:menuitem> <p:menuitem style="border-right: 1px dotted gray;" value="Konto" url="/faces/pages/authenticated/account.xhtml" rendered = "#{securityBean.isAuthenticated()}" /> <p:menuitem style="border-right: 1px dotted gray;" value="Meddelanden" url="/faces/pages/authenticated//messages.xhtml" rendered = "#{securityBean.isAuthenticated()}"/> <p:submenu label="verktyg" rendered = "#{securityBean.isAuthenticated()}"> <p:submenu label="Elev" rendered= "#{ securityBean.isAuthorized('STUDENT')}"> <p:menuitem value="Registrera på kurs" url="#" /> <p:menuitem value="Mina resultat" url="#" /> <p:menuitem value="Mina kurser" url="#" /> </p:submenu> <p:submenu label="Lärare" rendered="#{securityBean.isAuthorized('TEACHER')}"> <p:menuitem value="Mina elever" url="#" /> <p:menuitem value="Mina kurser" url="#" /> </p:submenu> <p:submenu label="Skolansvarig" rendered="#{securityBean.isAuthorized('SCHOOL_ADMIN')}"> <p:menuitem value="Hantera elever" url="#"/> <p:menuitem value="Köp platser" url="#" /> </p:submenu> <p:submenu label="Grupp ansvarig" rendered = "#{securityBean.isAuthorized('GROUP_MANAGER')}"> <p:menuitem value="Anställ lärare" url= "/faces/pages/authenticated/groupManager/recruitTeacher.xhtml" /> </p:submenu> </p:submenu> <f:facet name="options"> <p:commandButton value="Logga ut" rendered="#{securityBean.isAuthenticated()}" action="#{authJSF.logout()}" /> <p:button type="button" value="Logga in" rendered="#{securityBean.isAuthenticated() != true}" href="/faces/pages/signin.xhtml" /> </f:facet> </p:menubar> </h:form> </div> </ui:composition> faces/pages signin.xhtml <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"> <ui:composition template="/faces/templates/baseTemplate.xhtml"> <ui:define name="title">Logga in</ui:define> <ui:define name="content"> <p:messages id="messages" autoUpdate="true" redisplay="false" /> <p:accordionPanel rendered="#{securityBean.isAuthenticated() != true}"> <p:tab title="Logga in"> <ui:fragment> <h:form> <h:panelGrid border="0" columns="2"> <h:outputText value ="Användarnamn:"> </h:outputText> <input class="ui-inputfield uiinputtext ui-widget ui-statedefault ui-corner-all" type="text" name="j_username" /> <h:outputText value="Lösenord:"> </h:outputText> <input class="ui-inputfield uiinputtext ui-widget ui-statedefault ui-corner-all" type="password" name="j_password" /> <h:outputText value=""></h:outputText> <p:commandButton value="Logga in" action="#{authJSF.loginForm()}" /> </h:panelGrid> </h:form> </ui:fragment> </p:tab> <p:tab title="Registrera"> <ui:fragment> <h:form> <fieldset> <legend>Registrera</legend> <h:panelGrid border="0" columns="2"> <h:outputText value="Användarnamn:" > </h:outputText> <p:inputText value= "#{registrate.username}" required="true" requiredMessage="Du måste ange ett användarnamn!" /> <h:outputText value="Lösenord:"> </h:outputText> <p:password id="pwd1" value = "#{registrate.password1}" match="pwd2" required="true" label="Lösenord:" requiredMessage="Du måste ange ett lösenord." validatorMessage= "Lösenorden matchar inte." /> <h:outputText value="Lösenord igen:"></h:outputText> <p:password id="pwd2" value= "#{registrate.password2}" required="true" requiredMessage="Du måste ange lösenordet två gånger." /> <h:outputText value=" "> </h:outputText> <p:commandButton type="submit" value="Registrera" action= "#{registrate.registrate()}" id="registrate_button" /> </h:panelGrid> </fieldset> </h:form> </ui:fragment> </p:tab> </p:accordionPanel> <ui:fragment rendered="#{SecurityBean.isAuthenticated() }"> <h:outputText value="Du är redan inloggad!" /> </ui:fragment> </ui:define> </ui:composition> </html> faces/pages/authenticated account.xhtml <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"> <ui:composition template="/faces/templates/baseTemplate.xhtml"> <ui:define name="title">Konto</ui:define> <ui:define name="content"> <ui:fragment rendered="#{securityBean.isAuthenticated()}"> <p:accordionPanel> <p:tab title="Konto uppgifter"> <ui:fragment> <h:panelGrid columns="2" cellpadding="10"> <h:panelGrid border="0" columns="2"> <h:outputText value ="Användarnamn: " /> <h:outputText value ="#{account.user.username}" /> <h:outputText value="Groups:" /> <ui:repeat var="group" value = "#{account.user.groups}" rendered = "#{not empty account.user.groups}"> <h:outputText value=" #{group}," /> </ui:repeat> </h:panelGrid> </h:panelGrid> </ui:fragment> </p:tab> <p:tab title="Förnya lösenord"> <ui:fragment> <h:form> <p:messages id="messages" autoUpdate="true" /> <h:panelGrid border="0" columns="2"> <h:outputText value="Gammalt lösenord:"> </h:outputText> <p:password id="pwd" value = "#{account.oldPassword}" required="true" requiredMessage="Du måste ange ditt gamla lösenord!" /> <h:outputText value="Nytt lösenord:"></h:outputText> <p:password id="pwd1" value = "#{account.password1}" match="pwd2" required="true" label="Nytt lösenord:" requiredMessage="Du måste ange ett lösenord!" validatorMessage = "Lösenorden matchar inte!" /> <h:outputText value="Nytt lösenord igen:"> </h:outputText> <p:password id="pwd2" value = "#{account.password2}" required="true" requiredMessage="Du måste ange lösenordet två gånger!" /> <h:outputText value=""> </h:outputText> <p:commandButton type="submit" value="Förnya lösenord" action= "#{account.renewPass()}"/> </h:panelGrid> </h:form> </ui:fragment> </p:tab> <p:tab title="Avregistrera konto"> <ui:fragment> <h:form> <p:commandButton value="Avregistrera" actionListener = "#{account.deActivateAccount()}" > <p:confirm header="Bekräftelse" message="Om du avregistrerar dig kommer dina rättigheter tas bort från kontot och det går inte längre att använda!" icon="ui-icon-alert" /> </p:commandButton> <p:confirmDialog global="true" showEffect="fade" hideEffect="fade"> <p:commandButton value="Okej" type="button" styleClass="uiconfirmdialog-yes" icon="ui-icon-check" /> <p:commandButton value="Avbryt" type="button" styleClass="uiconfirmdialog-no" icon="ui-icon-close" /> </p:confirmDialog> </h:form> </ui:fragment> </p:tab> </p:accordionPanel> </ui:fragment> </ui:define> </ui:composition> </html> faces/authenticated/groupManager/ recruitTeacher.xhtml <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"> <ui:composition template="/faces/templates/baseTemplate.xhtml"> <ui:define name="title">Anställ lärare</ui:define> <ui:define name="content"> <ui:fragment rendered = "#{securityBean.isAuthorized ('GROUP_MANAGER')}"> <h:form> <p:messages id="messages" autoUpdate="true" /> <p:watermark for="username_to_recruit" value="Användare att anställa" id="watermark" /> <p:inputText id = "username_to_recruit" value="#{recruitTeacher.username}" /> <p:spacer width="5"/> <p:commandButton action="#{recruitTeacher.execute()}" value="Anställ lärare" /> </h:form> </ui:fragment> </ui:define> </ui:composition> </html> Presentation project – sourcecode Table of Contents Presentation project – sourcecode........................................................................................................1 se.mathplatform.bean.......................................................................................................................1 Account.java...............................................................................................................................1 RecruitTeacher.java.....................................................................................................................3 Registrate.java.............................................................................................................................4 se.web.security.bean........................................................................................................................5 Authentication.java.....................................................................................................................5 AuthJSF.java...............................................................................................................................6 se.mathplatform.bean Account.java /**@author Emil Strandberg*/ package se.mathplatform.bean; import java.util.List; import import import import import javax.annotation.PostConstruct; javax.enterprise.inject.Model; javax.faces.application.FacesMessage; javax.faces.context.FacesContext; javax.inject.Inject; import import import import import se.security.bean.Security; se.security.encrypt.PasswordService; se.security.model.User; se.security.model.UserWrap; se.web.security.bean.Authentication; /** * this class is a bean assosiated with a users account <br> * * Its supporting <a href="http://localhost:8080/MathplatformWeb/faces/pages/authenticated/account.xhtml">/fac es/pages/authenticated/account.xhtml</a> * **/ @Model public class Account { String oldPassword; String password1; String password2; @Inject Security security; @Inject Authentication securityJSF; @Inject PasswordService passwordService; @Inject UserWrap uw; /** if the user is logged in, fetch the user from the database */ @PostConstruct private void init() { if (security.isAuthenticated()) { uw.wrapByPK(security.getAuthenticatedUserName()); } } /** * renews the users password <br> * the method creates global facesMessages if something userrelated is wrong */ public void renewPass() { if (uw.isWrapping()) { try { if (uw.updatePassword(oldPassword, password1)) { uw.mergeWrap(); FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Lösenordet har uppdaterats!")); } else { FacesContext.getCurrentInstance().addMessage( null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Lösenordet du angav var fel!", "")); } } catch (SecurityException e) { e.printStackTrace(); FacesContext.getCurrentInstance().addMessage( null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Ett oväntat fel!", "")); return; } } } /** Deactivate the account, remove user form groups, and logout */ public void deActivateAccount() { uw.setActive(false); List<String> groups = uw.getGroups(); for (String g : groups) { uw.removeFromGroup(g); } uw.mergeWrap(); securityJSF.logout(); } public User getUser() { return uw; } public String getOldPassword() { return oldPassword; } public void setOldPassword(String oldPassword) { this.oldPassword = oldPassword; } public String getPassword1() { return password1; } public void setPassword1(String password1) { this.password1 = password1; } public String getPassword2() { return password2; } public void setPassword2(String password2) { this.password2 = password2; } } RecruitTeacher.java /**@author Emil Strandberg*/ package se.mathplatform.bean; import java.util.List; import import import import javax.enterprise.inject.Model; javax.faces.application.FacesMessage; javax.faces.context.FacesContext; javax.inject.Inject; import se.security.model.UserWrap; /**This class is used to recruit a teacher, it a simple test to ensure that groupmanagers * can affect groups of other users. * Its supporting <a href="http://localhost:8080/MathplatformWeb/faces/pages/authenticated/groupManager/recrui tTeacher.xhtml">/faces/pages/authenticated/groupManager/recruitTeacher.xhtml</a> * */ @Model public class RecruitTeacher { private String username; @Inject UserWrap uw; /**this will attempt to add the defined user to the teacher role * <p> * creates global facesMessages to inform the user about problems they can solve*/ public void execute() { if(uw.wrapByPK(username)) { try { uw.addToGroup("TEACHER"); uw.mergeWrap(); List<String> groups = uw.getGroups(); for(String s : groups) { System.out.println(s); } } catch(Exception e) { FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,"Det gÃ¥r inte göra användaren till lärare",""); FacesContext.getCurrentInstance().addMessage(null, message); return; } FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,"Användaren är nu lärare",""); FacesContext.getCurrentInstance().addMessage(null, message); } else { FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,"Kan inte hitta användaren",""); FacesContext.getCurrentInstance().addMessage(null, message); } } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } } Registrate.java /**@author Emil Strandberg*/ package se.mathplatform.bean; import java.io.Serializable; import import import import javax.enterprise.inject.Model; javax.faces.application.FacesMessage; javax.faces.context.FacesContext; javax.inject.Inject; import se.security.model.UserWrap; import se.web.security.bean.Authentication; /**This class is used to registered a new user <br> * * Its supporting <a href="http://localhost:8080/MathplatformWeb/faces/pages/signin.xhtml">/faces/pages/signin .xhtml</a> * */ @Model public class Registrate implements Serializable { private static final long serialVersionUID = 2442499769323428138L; @Inject private UserWrap uw; @Inject Authentication authJSF; private String password1 = ""; private String password2 = ""; private String username = ""; public Registrate() { } /**Tries to registrate a new user with the supplied values. informs the user by creating global facesMessages * @return empty string, left for navigation purposes */ public String registrate() { try { if (uw.wrapNew(username, password1)) { authJSF.login(username, password1); } else { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Användarnamnet finns redan!")); return ""; } } catch (Exception e) { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Oidentifierat fel!")); e.printStackTrace(); } return ""; } public String getPassword1() { return password1; } public String getPassword2() { return password2; } public String getUsername() { return username; } public void setPassword1(String password1) { this.password1 = password1; } public void setPassword2(String password2) { this.password2 = password2; } public void setUsername(String username) { this.username = username; } } se.web.security.bean Authentication.java /**@author Emil Strandberg*/ package se.web.security.bean; /**This interface is used to define methods to manage user session authentication * <br> * */ public interface Authentication { /**This method extracts name and password from form fields named j_username and j_password and then calls {@link Authentication#login(String, String)}*/ public void loginForm(); /**this method is used to login to the application. <p> * * @param username the username of the user trying to authenticate * @param password the unencrypted password used to authenticate * */ public void login(String username, String password); /**this method logs the user out from the application. */ public void logout(); } AuthJSF.java /**@author Emil Strandberg*/ package se.web.security.bean; import import import import import java.io.IOException; java.security.NoSuchAlgorithmException; java.security.NoSuchProviderException; java.security.spec.InvalidKeySpecException; java.util.Map; import import import import import import import javax.enterprise.inject.Model; javax.faces.application.FacesMessage; javax.faces.context.ExternalContext; javax.faces.context.FacesContext; javax.inject.Inject; javax.servlet.ServletException; javax.servlet.http.HttpServletRequest; import se.security.bean.Security; import se.security.encrypt.PasswordService; import se.security.model.UserWrap; /**this is a helper class to be used from JSF EL, its used to manage user authentication*/ @Model public class AuthJSF implements Authentication { @Inject Security s; @Inject UserWrap uw; @Inject PasswordService passwordService; /** Creates global facesMessages with user associated errors and information * */ @Override public void loginForm() { ExternalContext ec = FacesContext.getCurrentInstance() .getExternalContext(); Map<String, String> params = ec.getRequestParameterMap(); login(params.get("j_username"), params.get("j_password")); // TODO Security risk - non validated input } /** Creates global facesMessages with user associated errors and information * */ @Override public void login(String username, String password) { ExternalContext ec = FacesContext.getCurrentInstance() .getExternalContext(); HttpServletRequest request = (HttpServletRequest) ec.getRequest(); if (uw.wrapByPK(username)) { if (uw.isActive()) { try { String encPass = passwordService.encryptPassword(password, uw.getSalt(), uw.getPasswordSpecification()); request.login(username, encPass); if (!passwordService.isCurrent(uw .getPasswordSpecification())) { uw.updatePassword(password, password); uw.mergeWrap(); } try { ec.redirect(ec.getRequestContextPath() + "/"); } catch (IOException e) { FacesContext .getCurrentInstance() .addMessage( null, new FacesMessage( FacesMessage.SEVERITY_FATAL, "NÃ¥got gick fel", "Det gick inte omdirigera din webbläsare. Vänligen uppdatera sidan.")); e.printStackTrace(); return; } } catch (ServletException e) { FacesContext.getCurrentInstance().addMessage( null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Inloggningsuppgifterna är felaktiga", "")); e.printStackTrace(); return; } catch (NoSuchProviderException | InvalidKeySpecException | NoSuchAlgorithmException e) { FacesContext.getCurrentInstance().addMessage( null, new FacesMessage(FacesMessage.SEVERITY_FATAL, "NÃ¥got gick fel", "")); e.printStackTrace(); return; } } else { FacesContext.getCurrentInstance().addMessage( null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Detta kontot är deaktiverat!", "")); return; } } else { FacesContext.getCurrentInstance().addMessage( null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Inloggningsuppgifterna är felaktiga", "")); return; } } /** Creates global facesMessages with user associated errors and information **/ @Override public void logout() { ExternalContext ec = FacesContext.getCurrentInstance() .getExternalContext(); ec.invalidateSession(); try { ec.redirect(ec.getRequestContextPath() + "/"); } catch (IOException e) { e.printStackTrace(); FacesContext .getCurrentInstance() .addMessage( null, new FacesMessage(FacesMessage.SEVERITY_FATAL, "NÃ¥got gick fel", "Det gick inte omdirigera din webbläsare. Vänligen uppdatera fönstret.")); } } } Security project – sourcecode Table of Contents Security project – source code..............................................................................................................1 se.security.bean................................................................................................................................1 Security.java................................................................................................................................1 SecurityBean.java.......................................................................................................................2 se.security.encrypt............................................................................................................................4 PasswordService.java..................................................................................................................4 se.security.model..............................................................................................................................7 InitDevDatabase.java..................................................................................................................7 PasswordSpecification.java.........................................................................................................9 User.java....................................................................................................................................10 UserEntity.java..........................................................................................................................11 UserWrap.java...........................................................................................................................14 package se.security.model;........................................................................................................14 UserWrapper.java......................................................................................................................14 Wrap.java..................................................................................................................................18 se.security.bean Security.java /**@author Emil Strandberg * */ package se.security.bean; /** * This interface defines methods to manage some common * security related features in an application. * */ public interface Security { /** * The method is used to check if a user is in a role. * @param singleRoleOrCommaSeperatedRoleList A comma separated list of roles to check, if a single role, then don't use a trailing comma * @return True if authenticated user is in one of the supplied roles, else false*/ boolean isAuthorized(String singleRoleOrCommaSeperatedRoleList); /** * This method is used to check if the user is authenticated, bow. if the user has a none anonymous session context * @return True if user is authenticated, else false * */ boolean isAuthenticated(); /**used to get the name of a user * @return username if authenticated, else null*/ String getAuthenticatedUserName(); } SecurityBean.java /**@author Emil Strandberg * */ package se.security.bean; import java.io.Serializable; import import import import import javax.annotation.Resource; javax.ejb.SessionContext; javax.ejb.Stateless; javax.enterprise.context.Dependent; javax.inject.Named; /** * SecurityBean implements security * its used to perform some common security related functions, * this implementation can be used in the business layer as well as in the * presentation. * * Overrided methods is documented by there supertype, aslong as they fulfill the contracts stated there. */ @Named @Stateless @Dependent public class SecurityBean implements Serializable, Security { private static final long serialVersionUID = 1L; @Resource protected SessionContext ctx; public SecurityBean() { } @Override public String getAuthenticatedUserName() { if (isAuthenticated()) { return ctx.getCallerPrincipal().getName(); } return null; } @Override public boolean isAuthenticated() { if (!ctx.getCallerPrincipal().getName().equals("ANONYMOUS")) { return true; } return false; } @Override public boolean isAuthorized(String singleRoleOrCommaSeperatedRoleList) { String[] roles = singleRoleOrCommaSeperatedRoleList.split(","); for (String r : roles) { if (isAuthorizedTo(r)) { return true; } } return false; } /**a helper method to check i a user is authorized to a single role * @return true if user is in role, else false*/ private boolean isAuthorizedTo(String singleRole) { singleRole = singleRole.trim().toUpperCase(); if (ctx.isCallerInRole(singleRole)) { return true; } return false; } } se.security.encrypt PasswordService.java /** @author Emil Strandberg * */ package se.security.encrypt; import import import import import java.security.NoSuchAlgorithmException; java.security.NoSuchProviderException; java.security.SecureRandom; java.security.spec.InvalidKeySpecException; java.security.spec.KeySpec; import import import import import import javax.annotation.Resource; javax.crypto.SecretKeyFactory; javax.crypto.spec.PBEKeySpec; javax.ejb.Stateless; javax.inject.Named; javax.xml.bind.DatatypeConverter; import se.security.model.PasswordSpecification; /** * * this class can be used to manage password hashing. Its properties can be set * through the associated modules deployment descriptor. * * Base64 encoding is used. * * The properties that can be set: * <table summary="properties set by configuration file" > * <tr> * <td>Name</td> * <td>Type</td> * <td>Default</td> * <td>Description</td> * </tr> * <tr> * <td>SecretKeyFactory_algorithm</td> * <td>String</td> * <td>PBKDF2WithHmacSHA256</td> * <td>The algorithm used to hash the password, supported types @see * {@link javax.crypto.SecretKeyFactory#getInstance(String)}</td> * </tr> * <tr> * <td>KeySpec_length</td> * <td>int</td> * <td>256</td> * <td>Length of the key (0 for ficed length) @see * {@link javax.crypto.spec.PBEKeySpec#getKeyLength()}</td> * </tr> * <tr> * <td>KeySpec_iterations</td> * <td>int</td> * <td>2000</td> * <td>Iterations to perform @see * {@link javax.crypto.spec.PBEKeySpec#getIterationCount()}</td> * </tr> * <tr> * <td>Salt_length</td> * <td>int</td> * <td>16</td> * <td>Length of the generated salt</td> * </tr> * <tr> * <td>Salt_algorithm</td> * <td>String</td> * <td>SHA1PRNG</td> * <td>the algorithm to produce a secure random salt @see * {@link java.security.SecureRandom#getAlgorithm()}</td> * </tr> * <tr> * <td>Salt_provider</td> * <td>String</td> * <td>SUN</td> * <td>the provider of the salt algorithm @see * {@link java.security.SecureRandom#getProvider()}</td> * </tr> * </table> * * TODO: Create a interface * */ @Named @Stateless public class PasswordService { @Resource(name = "SecretKeyFactory_algorithm") private String algorithm = "PBKDF2WithHmacSHA256"; @Resource(name = "KeySpec_length") private int keyLength = 256; @Resource(name = "KeySpec_iterations") private int iterations = 2000; @Resource(name = "Salt_length") private int saltLength = 16; @Resource(name = "Salt_algorithm") private String saltAlgorithm = "SHA1PRNG"; @Resource(name = "Salt_provider") private String saltProvider = "SUN"; /** * this method encrypts the password according to the supplied * PasswordSpecification. If its a new encryption the current specification * can be acquired by calling {@link PasswordService#getPasswordSpecs()} * * @param password * the unencrypted password. * @param salt * the salt to include in the encryption procedure. * @param ps * the {@link PasswordSpecification} to encrypt by. * @return the encrypted password. * * @throws NoSuchAlgorithmException * if configured incorrectly * @throws NoSuchProviderException * if configured incorrectly * @throws InvalidKeySpecException * if configured incorrectly * */ public String encryptPassword(String password, String salt, PasswordSpecification ps) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException { KeySpec ks; if (keyLength != 0) { ks = new PBEKeySpec(password.toCharArray(), DatatypeConverter.parseBase64Binary(salt), ps.iterations, ps.keyLength); } else { ks = new PBEKeySpec(password.toCharArray(), DatatypeConverter.parseBase64Binary(salt), ps.iterations); } SecretKeyFactory skf = SecretKeyFactory.getInstance(ps.algorithm); return DatatypeConverter.printBase64Binary(skf.generateSecret(ks) .getEncoded()); } /** * This method is used to acquire the current PasswordSpecification to use * when encrypting/hashing * * @return the current version of {@link PasswordSpecification} */ public PasswordSpecification getPasswordSpecs() { return new PasswordSpecification(algorithm, iterations, keyLength, saltAlgorithm, saltProvider, saltLength); } /** * checks if the supplied {@link PasswordSpecification} is of the latest * version * * @param ps * the {@link PasswordSpecification} to check * @return true if the supplied {@link PasswordSpecification} is the latest, * else false */ public boolean isCurrent(PasswordSpecification ps) { if (!(ps.algorithm.equals(algorithm) && ps.keyLength == keyLength && ps.iterations == iterations && ps.saltLength == saltLength && ps.saltAlgorithm.equals(saltAlgorithm) && ps.saltProvider .equals(saltProvider))) { return false; } return true; } /** * This method generate a salt string, it uses {@link SecureRandom} to do * this. * * @return a random string produced by defined properties * @throws NoSuchAlgorithmException * if configured incorrectly * @throws NoSuchProviderException * if configured incorrectly */ public String generateSalt() throws NoSuchAlgorithmException, NoSuchProviderException { SecureRandom random = SecureRandom.getInstance(saltAlgorithm, saltProvider); byte[] salt = new byte[saltLength]; random.nextBytes(salt); return DatatypeConverter.printBase64Binary(salt); } } se.security.model InitDevDatabase.java /**@author Emil Strandberg*/ package se.security.model; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.spec.InvalidKeySpecException; import javax.annotation.PostConstruct; import import import import import javax.ejb.Singleton; javax.ejb.Startup; javax.inject.Inject; javax.persistence.EntityManager; javax.persistence.PersistenceContext; import se.security.encrypt.PasswordService; import se.security.model.User; import se.security.model.UserEntity; /**This class is only for development. it must be removed before publishing this application * * The purpose of the class is to add test users to the system. * users added are: * <table summary="users added for development"> * <tr><td>Name</td><td>Password</td><td>Group</td></tr> * <tr><td>student</td><td>student</td><td>STUDENT</td></tr> * <tr><td>teacher</td><td>teacher</td><td>TEACHER</td></tr> * <tr><td>school_admin</td><td>school_admin</td><td>SCHOOL_ADMIN</td></tr> * <tr><td>group_manager</td><td>group_manager</td><td>GROUP_MANAGER</td></tr> * </table> * */ @Singleton @Startup public class initDevDatabase { @PersistenceContext(name = "SecurityDB") EntityManager em; @Inject PasswordService passwordService; @PostConstruct private void init() { System.out .println("init------------------------------------------------"); String strudent = "student"; String teacher = "teacher"; String school_admin = "school_admin"; String group_manager = "GROUP_MANAGER"; try { String salt = passwordService.generateSalt(); PasswordSpecification psp = passwordService.getPasswordSpecs(); User sa = new UserEntity("school_admin", passwordService.encryptPassword("school_admin", salt, psp), salt, psp); sa.addToGroup(school_admin); em.persist(sa); salt = passwordService.generateSalt(); psp = passwordService.getPasswordSpecs(); User t = new UserEntity("teacher", passwordService.encryptPassword("teacher", salt, psp), salt, psp); t.addToGroup(teacher); em.persist(t); salt = passwordService.generateSalt(); psp = passwordService.getPasswordSpecs(); User s = new UserEntity("student", passwordService.encryptPassword("student", salt, psp), salt, psp); s.addToGroup(strudent); em.persist(s); salt = passwordService.generateSalt(); psp = passwordService.getPasswordSpecs(); User s2 = new UserEntity( "group_manager", passwordService.encryptPassword("group_manager", salt, psp), salt, psp); s2.addToGroup(group_manager); em.persist(s2); } catch (NoSuchAlgorithmException | NoSuchProviderException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidKeySpecException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } PasswordSpecification.java /**@author Emil Strandberg*/ package se.security.model; import javax.persistence.Embeddable; /** * This class works ass a structure holding properties associated with a * encrypted/hashed password, its used mainly in association with * {@link se.security.encrypt.PasswordService} and then stored embedded in the * {@link se.security.model.UserEntity} */ @Embeddable public class PasswordSpecification { public public public public public public final final final final final final String algorithm; int iterations; int keyLength; String saltAlgorithm; String saltProvider; int saltLength; public PasswordSpecification() { this.algorithm = null; this.iterations = -1; this.keyLength = -1; this.saltAlgorithm = null; this.saltProvider = null; this.saltLength = -1; } /** * creates a PasswordSpecification with the supplied arguments. The salt * properties are strictly not necessary to repeat the encryption, but its * used to decide if the password should be reencrypted after a salt related * property changes. * * @param algorithm * the password algorithm used in the encryption procedure * @param iterations * the number of iterations done in the encryption procedure * @param keyLength * the length of the produced key * @param saltAlgorithm * the algorithm used to produce a secureRandom salt value * @param saltProvider * the provider of the saltAlgorithm * @param saltLength * the length of the produced salt. */ public PasswordSpecification(String algorithm, int iterations, int keyLength, String saltAlgorithm, String saltProvider, int saltLength) { this.algorithm = algorithm; this.iterations = iterations; this.keyLength = keyLength; this.saltAlgorithm = saltAlgorithm; this.saltProvider = saltProvider; this.saltLength = saltLength; } } User.java /**@author Emil Strandberg*/ package se.security.model; import java.util.List; /**an interface defining a user. */ public interface User { /**@return returns the users password*/ public String getPassword(); /**update the users password * @param oldPassword the password currently in use * @param newPassword the password to set instead * @return true if update is successful, else false*/ public boolean updatePassword(String oldPassword, String newPassword); /**sets the users password * @param password the password to set for the user*/ public void setPassword(String password); /**sets the users {@link se.security.model.PasswordSpecification} * this can only be done if {@link User#updatePassword(String, String)} or {@link User#setPassword(String)} has been called before this method is called * @param ps the passwordspecification used to encrupt the users password * @return true if success, else false*/ public boolean setPasswordSpecification(PasswordSpecification ps); /**@return users {@link se.security.model.PasswordSpecification}*/ public PasswordSpecification getPasswordSpecification(); /**sets the users salt * this can only be done if {@link User#updatePassword(String, String)} or {@link User#setPassword(String)} has been called before this method is called * @param Salt the salt used when encrypting the users password * @return true if success, else false*/ public boolean setSalt(String Salt); /**@return users salt*/ public String getSalt(); /**@return an unmodifiable list of the groups the user is currently in */ public List<String> getGroups(); /**adds a user to the group * @param g name of the group*/ public void addToGroup(String g); /**removes the user from a group * @param g the name of the group to remove the user from * @return true if successfuly removed*/ public boolean removeFromGroup(String g); /**@return the users username witch acts as a primary key*/ public String getUsername(); /**checks if the users account is active. * @return true if active, else false*/ public boolean isActive(); /**set the active status of the user * @param active set the user active (true) or inactive (false)*/ public void setActive(boolean active); } UserEntity.java /**@author Emil Strandberg*/ package se.security.model; import import import import import java.io.Serializable; java.util.ArrayList; java.util.HashSet; java.util.List; java.util.Set; import import import import import import import javax.persistence.ElementCollection; javax.persistence.Entity; javax.persistence.Id; javax.persistence.Transient; javax.persistence.Version; javax.validation.constraints.NotNull; javax.validation.constraints.Size; /**this is the entity class representing a user. its not intended to be used by the system, instead use {@link se.security.model.UserWrapper} */ @Entity(name = "S_USERS") public class UserEntity implements User, Serializable { @Transient private static final long serialVersionUID = -677828261187442009L; @Transient private boolean saltChange = false; @Transient private boolean passwordSpecificationChange = false; @Id @Size(min = 1, max = 80) private String username; @NotNull @Size(min = 6, max = 80) private String password; private boolean active = true; @Version private Long version; @ElementCollection private Set<String> groups = new HashSet<>(); private PasswordSpecification passwordSpecification; private String salt; protected UserEntity() { } /**this constructor is protected since this class is not intended to be used directly by the system. Instead use {@link se.security.model.UserWrapper} * * @param username is the name of the user and also the PK in the database * @param pass is the password of the user * @param salt is the salt used when encrypting the password * @param psp is the {@link se.security.model.PasswordSpecification} used when encrypting the password. */ protected UserEntity(String username, String pass, String salt, PasswordSpecification psp) { this.username = username; this.password = pass; this.salt = salt; this.passwordSpecification = psp; } @Override public String getPassword() { return password; } @Override public void setPassword(String password) { this.password = password; this.passwordSpecificationChange = true; this.saltChange = true; } @Override public PasswordSpecification getPasswordSpecification() { return passwordSpecification; } @Override public boolean setPasswordSpecification(PasswordSpecification ps) { if (this.passwordSpecificationChange == true) { this.passwordSpecificationChange = false; this.passwordSpecification = ps; return true; } return false; } @Override public boolean setSalt(String salt) { if (this.saltChange == true) { this.salt = salt; this.saltChange = false; return true; } return false; } @Override public String getSalt() { return salt; } @Override public List<String> getGroups() { // TODO: find a better solution! return new ArrayList<String>(groups); } @Override public void addToGroup(String g) { groups.add(g.trim().toUpperCase()); } @Override public boolean removeFromGroup(String g) { return groups.remove(g.trim().toUpperCase()); } @Override public String getUsername() { return username; } @Override public boolean isActive() { return active; } @Override public void setActive(boolean active) { this.active = active; } @Override public boolean updatePassword(String oldPassword, String newPassword) { if (oldPassword.equals(password)) { setPassword(newPassword); return true; } else { return false; } } } UserWrap.java /**@author Emil Strandberg*/ package se.security.model; /**simply to make CDI behave as expected*/ public interface UserWrap extends Wrap, User{ } UserWrapper.java /**@author Emil Strandberg*/ package se.security.model; import import import import java.security.NoSuchAlgorithmException; java.security.NoSuchProviderException; java.security.spec.InvalidKeySpecException; java.util.List; import import import import import import import import javax.annotation.security.DenyAll; javax.annotation.security.RolesAllowed; javax.ejb.Stateful; javax.enterprise.context.Dependent; javax.inject.Inject; javax.inject.Named; javax.persistence.EntityManager; javax.persistence.PersistenceContext; import se.security.bean.Security; import se.security.encrypt.PasswordService; /** * This is a class that wraps the user entity in this project, this class is * mainly used to enforce security constraints to the entity's properties.<br> * IMPORTANT: This is container managed object so don't instantiate it manually * <br><br> * Documentation is only written when the superclass documentation doesn't match the implementation. */ @Named @Stateful @Dependent public class UserWrapper implements UserWrap { UserEntity user = null; @Inject Security securityImp; @Inject PasswordService passwordService; @PersistenceContext(name = "SecurityDB") EntityManager em; protected UserWrapper() { } @Override public boolean wrapByPK(String name) { UserEntity u = em.find(UserEntity.class, name); if (u != null) { user = u; return true; } else { return false; } } /** * @throws RuntimeException * if system configurations related to password encryptions is * wrong */ @Override public boolean wrapNew(String name, String password) { if (em.find(UserEntity.class, name) == null) { UserEntity u; try { String salt = passwordService.generateSalt(); PasswordSpecification psp = passwordService.getPasswordSpecs(); u = new UserEntity(name, passwordService.encryptPassword(password, salt, psp), salt, psp); } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) { throw new RuntimeException( "Password encryption configuration error: ", e); } em.persist(u); user = u; return true; } return false; } @Override public void mergeWrap() { if (user != null) { em.merge(user); } } @Override public void cleanWrap() { user = null; } @Override public boolean isWrapping() { if (user != null) { return true; } return false; } @Override public String getPassword() { if (user != null) { if (securityImp.getAuthenticatedUserName().equals( this.getUsername())) { return user.getPassword(); } else { return null; } } else { return null; } } /** * @throws RuntimeException * if system configurations related to password encryptions is * wrong */ @Override public boolean updatePassword(String oldPassword, String newPassword) { if (user != null) { if (securityImp.getAuthenticatedUserName().equals( this.getUsername())) { try { String salt = passwordService.generateSalt(); PasswordSpecification psp = passwordService .getPasswordSpecs(); System.out.println(passwordService.encryptPassword( "student", user.getSalt(), user.getPasswordSpecification())); if (user.updatePassword(passwordService.encryptPassword( oldPassword, user.getSalt(), user.getPasswordSpecification()), passwordService .encryptPassword(newPassword, salt, psp))) { user.setSalt(salt); user.setPasswordSpecification(psp); return true; } else { return false; } } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) { throw new RuntimeException( "Password encryption configuration error: ", e); } } } return true; } @Override public PasswordSpecification getPasswordSpecification() { if (user != null) { return user.getPasswordSpecification(); } return null; } @Override public String getSalt() { if (user != null) { return user.getSalt(); } return null; } @Override public List<String> getGroups() { if (user != null) { return user.getGroups(); } else { return null; } } @Override @RolesAllowed({ "GROUP_MANAGER" }) public void addToGroup(String g) { if (user != null) { user.addToGroup(g); } } @Override @RolesAllowed({ "GROUP_MANAGER", "STUDENT", "TEACHER", "SCHOOL_ADMIN" }) public boolean removeFromGroup(String g) { if (user != null) { if (securityImp.getAuthenticatedUserName().equals( this.getUsername()) || securityImp.isAuthorized("GROUP_MANAGER")) { return user.removeFromGroup(g); } } return false; } @Override public String getUsername() { if (user != null) { return user.getUsername(); } else { return null; } } @Override public boolean isActive() { if (user != null) { return user.isActive(); } else { return false; } } @Override public void setActive(boolean active) { if (user != null) { if (securityImp.getAuthenticatedUserName().equals( this.getUsername())) { user.setActive(active); } } } @DenyAll @Override public boolean setPasswordSpecification(PasswordSpecification ps) { return false; } @DenyAll @Override public boolean setSalt(String Salt) { return false; } @DenyAll @Override public void setPassword(String password) { } } Wrap.java /**@author Emil Strandberg*/ package se.security.model; /**this is an interface defining how to handle a wrapping object*/ public interface Wrap { /**wraps an object by its primarykey * @param pk primarykey of the entity to wrap * @return if entity was successfully wrapped, true, else false*/ public boolean wrapByPK(String pk); /** * Creates an entity and wraps it. * <br > * Take a look at {@link javax.persistence.EntityManager#persist(Object)} for hidden exceptions * * @param pk, the primarykey of the object to wrap * @param password, the password of the object. * @return if successful wrap, true, else false * * <br > * TODO: this method should be generalized * */ public boolean wrapNew(String pk, String password); /**Merges the wraps entity with the database. <br> * Take a look at {@link javax.persistence.EntityManager#merge(Object)} for hidden exceptions <br> * Also remember that entity's might throw concurrency exceptions * */ public void mergeWrap(); /**removes the contained object from the wrap*/ public void cleanWrap(); /**checks if the wrap is currently wrapping an object * @return true if wrapping an entity, else false*/ boolean isWrapping(); } Bilaga C Källkod Lösenordskryptering Password-hashing test program /**@author Emil Strandberg*/ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import javax.xml.bind.DatatypeConverter; public class Main { final String[] passwordAlgorithms = { "SHA-512" }; final char[] charsToHash = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v','w', 'x', 'y', 'z' }; final int deeptToHash = 0; final int repeatTests = 1; final boolean outputToFile = true; final File file = new File("/home/emil/Desktop/hashTable.txt"); FileOutputStream fos = null; String currentAlgorithm = ""; public static void main(String[] args) throws IOException { Main program = new Main(); program.start(); } public void start() throws IOException { long[] time = new long[passwordAlgorithms.length]; for (int i = 0; i < passwordAlgorithms.length && i > -1; i++) { currentAlgorithm = passwordAlgorithms[i]; if (outputToFile) { fos = new FileOutputStream(file); } for (int n = 0; n < repeatTests; n++) { long startTime = System.nanoTime(); runHashing(0, ""); long stopTime = System.nanoTime(); time[i] += stopTime - startTime; } time[i] /= repeatTests; System.out.println(currentAlgorithm + " Hashing took: " + ((time[i]) / 1000000000.0) + "s"); } } public void runHashing(int depth, String base) throws IOException { if (depth > deeptToHash) { return; } for (char mChar : charsToHash) { String pass = new StringBuilder().append(base).append(mChar) .toString(); } byte[] passHash = hashPassword(pass); if (outputToFile) { fos.write((DatatypeConverter.printHexBinary(passHash) + " for: " + pass + " \n").getBytes()); } runHashing(depth + 1, pass); } byte[] hashPassword(String password) { byte[] passwordDigest = null; MessageDigest md; try { md = MessageDigest.getInstance(currentAlgorithm); md.update(password.getBytes("UTF-8")); passwordDigest = md.digest(); } } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return passwordDigest;
© Copyright 2026