Självständigt arbete på grundnivå

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;