Hashování hesla, generování náhodného tokenu, částečný převod chyb na uživatelsky přijatelné hlášky.
authorFrantišek Kučera <franta-hg@frantovo.cz>
Thu Mar 04 14:09:21 2010 +0100 (2010-03-04)
changeset 524c0408690ebf
parent 51 d01685a7e07d
child 53 d76be0124c40
Hashování hesla, generování náhodného tokenu, částečný převod chyb na uživatelsky přijatelné hlášky.
java/nekurak.net-ejb/src/java/cz/frantovo/nekurak/ejb/UzivatelEJB.java
java/nekurak.net-lib/src/cz/frantovo/nekurak/ejb/UzivatelRemote.java
java/nekurak.net-lib/src/cz/frantovo/nekurak/util/Hash.java
java/nekurak.net-lib/src/cz/frantovo/nekurak/vyjimky/NecekanaVyjimka.java
java/nekurak.net-lib/src/cz/frantovo/nekurak/vyjimky/NekurakVyjimka.java
java/nekurak.net-web/src/java/cz/frantovo/nekurak/preklady_cs.properties
java/nekurak.net-web/src/java/cz/frantovo/nekurak/web/RegistraceUzivatele.java
java/nekurak.net-web/src/java/cz/frantovo/nekurak/web/UzivatelPredRegistraci.java
java/nekurak.net-web/web/WEB-INF/casti/registrovatUzivatele.jsp
     1.1 --- a/java/nekurak.net-ejb/src/java/cz/frantovo/nekurak/ejb/UzivatelEJB.java	Thu Mar 04 12:02:41 2010 +0100
     1.2 +++ b/java/nekurak.net-ejb/src/java/cz/frantovo/nekurak/ejb/UzivatelEJB.java	Thu Mar 04 14:09:21 2010 +0100
     1.3 @@ -2,6 +2,11 @@
     1.4  
     1.5  import cz.frantovo.nekurak.dao.UzivatelDAO;
     1.6  import cz.frantovo.nekurak.dto.Uzivatel;
     1.7 +import cz.frantovo.nekurak.util.Hash;
     1.8 +import cz.frantovo.nekurak.vyjimky.NecekanaVyjimka;
     1.9 +import cz.frantovo.nekurak.vyjimky.NekurakVyjimka;
    1.10 +import java.io.UnsupportedEncodingException;
    1.11 +import java.security.NoSuchAlgorithmException;
    1.12  import javax.ejb.EJB;
    1.13  import javax.ejb.Stateless;
    1.14  
    1.15 @@ -16,7 +21,17 @@
    1.16      private UzivatelDAO uzivatelDao;
    1.17  
    1.18      /** Uživatele může zakládat kdokoli – uživatel se registruje sám. */
    1.19 -    public void zalozUzivatele(Uzivatel u) {
    1.20 -	uzivatelDao.uloz(u);
    1.21 +    public void zalozUzivatele(Uzivatel u) throws NekurakVyjimka {
    1.22 +	try {
    1.23 +	    /** Heslo musíme před uložení zahashovat, aby se uživatel mohl přihlásit. */
    1.24 +	    u.setHeslo(Hash.hashuj(u.getHeslo()));
    1.25 +	    uzivatelDao.uloz(u);
    1.26 +	} catch (NoSuchAlgorithmException e) {
    1.27 +	    /** Nemělo by nastat */
    1.28 +	    throw new NecekanaVyjimka("Neexistující hashovací algoritmus.", e);
    1.29 +	} catch (UnsupportedEncodingException e) {
    1.30 +	    /** Nemělo by nastat */
    1.31 +	    throw new NecekanaVyjimka("Nepodporované kódování znaků.", e);
    1.32 +	}
    1.33      }
    1.34  }
     2.1 --- a/java/nekurak.net-lib/src/cz/frantovo/nekurak/ejb/UzivatelRemote.java	Thu Mar 04 12:02:41 2010 +0100
     2.2 +++ b/java/nekurak.net-lib/src/cz/frantovo/nekurak/ejb/UzivatelRemote.java	Thu Mar 04 14:09:21 2010 +0100
     2.3 @@ -1,6 +1,7 @@
     2.4  package cz.frantovo.nekurak.ejb;
     2.5  
     2.6  import cz.frantovo.nekurak.dto.Uzivatel;
     2.7 +import cz.frantovo.nekurak.vyjimky.NekurakVyjimka;
     2.8  import javax.ejb.Remote;
     2.9  
    2.10  /**
    2.11 @@ -10,6 +11,5 @@
    2.12  @Remote
    2.13  public interface UzivatelRemote {
    2.14  
    2.15 -    public void zalozUzivatele(Uzivatel u);
    2.16 -
    2.17 +    public void zalozUzivatele(Uzivatel u) throws NekurakVyjimka;
    2.18  }
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/java/nekurak.net-lib/src/cz/frantovo/nekurak/util/Hash.java	Thu Mar 04 14:09:21 2010 +0100
     3.3 @@ -0,0 +1,47 @@
     3.4 +package cz.frantovo.nekurak.util;
     3.5 +
     3.6 +import java.io.UnsupportedEncodingException;
     3.7 +import java.security.MessageDigest;
     3.8 +import java.security.NoSuchAlgorithmException;
     3.9 +
    3.10 +/**
    3.11 + * Pomocná třída pro počítání hashů.
    3.12 + * @author fiki
    3.13 + */
    3.14 +public class Hash {
    3.15 +
    3.16 +    private static String algoritmus = "SHA-1";
    3.17 +    private static String kodovani = "UTF-8";
    3.18 +
    3.19 +    private static String prevedNaHex(byte[] data) {
    3.20 +	StringBuffer vysledek = new StringBuffer();
    3.21 +	for (int i = 0; i < data.length; i++) {
    3.22 +	    int pulBajt = (data[i] >>> 4) & 0x0F;
    3.23 +	    int dvePulky = 0;
    3.24 +	    do {
    3.25 +		if ((0 <= pulBajt) && (pulBajt <= 9)) {
    3.26 +		    vysledek.append((char) ('0' + pulBajt));
    3.27 +		} else {
    3.28 +		    vysledek.append((char) ('a' + (pulBajt - 10)));
    3.29 +		}
    3.30 +		pulBajt = data[i] & 0x0F;
    3.31 +	    } while (dvePulky++ < 1);
    3.32 +	}
    3.33 +	return vysledek.toString();
    3.34 +    }
    3.35 +
    3.36 +    /**
    3.37 +     * @param text vstupní text
    3.38 +     * @return hashovaný text v HEX tvaru
    3.39 +     * @throws NoSuchAlgorithmException neexistující hashovací algoritmus
    3.40 +     * @throws UnsupportedEncodingException nepodporované kódování znaků
    3.41 +     */
    3.42 +    public static String hashuj(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    3.43 +	MessageDigest md;
    3.44 +	md = MessageDigest.getInstance(algoritmus);
    3.45 +	byte[] hash = new byte[40];
    3.46 +	md.update(text.getBytes(kodovani), 0, text.length());
    3.47 +	hash = md.digest();
    3.48 +	return prevedNaHex(hash);
    3.49 +    }
    3.50 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/java/nekurak.net-lib/src/cz/frantovo/nekurak/vyjimky/NecekanaVyjimka.java	Thu Mar 04 14:09:21 2010 +0100
     4.3 @@ -0,0 +1,12 @@
     4.4 +package cz.frantovo.nekurak.vyjimky;
     4.5 +
     4.6 +/**
     4.7 + *
     4.8 + * @author fiki
     4.9 + */
    4.10 +public class NecekanaVyjimka extends NekurakVyjimka {
    4.11 +
    4.12 +    public NecekanaVyjimka(String chyba, Exception e) {
    4.13 +	super(chyba, e);
    4.14 +    }
    4.15 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/java/nekurak.net-lib/src/cz/frantovo/nekurak/vyjimky/NekurakVyjimka.java	Thu Mar 04 14:09:21 2010 +0100
     5.3 @@ -0,0 +1,12 @@
     5.4 +package cz.frantovo.nekurak.vyjimky;
     5.5 +
     5.6 +/**
     5.7 + *
     5.8 + * @author fiki
     5.9 + */
    5.10 +public class NekurakVyjimka extends Exception {
    5.11 +
    5.12 +    public NekurakVyjimka(String chyba, Exception e) {
    5.13 +	super(chyba, e);
    5.14 +    }
    5.15 +}
     6.1 --- a/java/nekurak.net-web/src/java/cz/frantovo/nekurak/preklady_cs.properties	Thu Mar 04 12:02:41 2010 +0100
     6.2 +++ b/java/nekurak.net-web/src/java/cz/frantovo/nekurak/preklady_cs.properties	Thu Mar 04 14:09:21 2010 +0100
     6.3 @@ -56,7 +56,9 @@
     6.4  registrace.hotovo.prihlasit=p\u0159ihl\u00E1sit
     6.5  registrace.tlacitko=Registrovat se
     6.6  registrace.potvrdit=Potvrdit registraci
     6.7 -registrace.chybnyToken=Relace vypr\u0161ela, registraci nelze dokon\u010Dit. Vypl\u0148te pros\u00EDm formul\u00E1\u0159 znovu.
     6.8 +registrace.vyjimka=Nepoda\u0159ilo se zalo\u017Eit u\u017Eivatele. Po\u017Eadovan\u00E1 p\u0159ezd\u00EDvka je pravd\u011Bpodobn\u011B obsazena.
     6.9 +registrace.vyjimka.necekana=Omlouv\u00E1me se, b\u011Bhem registrace do\u0161lo k nezn\u00E1m\u00E9 chyb\u011B.
    6.10 +registrace.vyjimka.token=Relace vypr\u0161ela, registraci nelze dokon\u010Dit. Vypl\u0148te pros\u00EDm formul\u00E1\u0159 znovu.
    6.11  
    6.12  dto.uzivatel.prezdivka=P\u0159ezd\u00EDvka
    6.13  dto.uzivatel.prezdivka.tip=U\u017Eivatelsk\u00E9 jm\u00E9no
     7.1 --- a/java/nekurak.net-web/src/java/cz/frantovo/nekurak/web/RegistraceUzivatele.java	Thu Mar 04 12:02:41 2010 +0100
     7.2 +++ b/java/nekurak.net-web/src/java/cz/frantovo/nekurak/web/RegistraceUzivatele.java	Thu Mar 04 14:09:21 2010 +0100
     7.3 @@ -1,8 +1,11 @@
     7.4  package cz.frantovo.nekurak.web;
     7.5  
     7.6 +import cz.frantovo.nekurak.vyjimky.NekurakVyjimka;
     7.7  import java.util.Collections;
     7.8  import java.util.HashMap;
     7.9  import java.util.Map;
    7.10 +import java.util.logging.Level;
    7.11 +import java.util.logging.Logger;
    7.12  
    7.13  /**
    7.14   *
    7.15 @@ -11,6 +14,7 @@
    7.16  public class RegistraceUzivatele {
    7.17  
    7.18      private HledacSluzby hledac = new HledacSluzby();
    7.19 +    private static final Logger log = Logger.getLogger(RegistraceUzivatele.class.getSimpleName());
    7.20      private Map<String, UzivatelPredRegistraci> uzivatele = Collections.synchronizedMap(new HashMap<String, UzivatelPredRegistraci>());
    7.21      private String token;
    7.22  
    7.23 @@ -22,16 +26,25 @@
    7.24  	this.token = token;
    7.25      }
    7.26  
    7.27 -    public boolean getDokonciRegistraci() {
    7.28 +    /**
    7.29 +     * @return true, pokud registrace proběhla, jinak vyhazuje výjimku.
    7.30 +     * @throws NekurakVyjimka špatný token nebo chyba při zakládání uživatele
    7.31 +     */
    7.32 +    public String getDokonciRegistraci() {
    7.33  
    7.34  	UzivatelPredRegistraci u = uzivatele.get(token);
    7.35  
    7.36  	if (u == null) {
    7.37  	    /** Chybný token – uživatel se snaží dokončit neexistující registraci */
    7.38 -	    return false;
    7.39 +	    return "registrace.vyjimka.token";
    7.40  	} else {
    7.41 -	    hledac.getUzivatelEJB().zalozUzivatele(u.getUzivatel());
    7.42 -	    return true;
    7.43 +	    try {
    7.44 +		hledac.getUzivatelEJB().zalozUzivatele(u.getUzivatel());
    7.45 +	    } catch (Exception e) {
    7.46 +		log.log(Level.WARNING, "Chyba při registraci uživatele.", e);
    7.47 +		return "registrace.vyjimka";
    7.48 +	    }
    7.49 +	    return null;
    7.50  	}
    7.51      }
    7.52  }
     8.1 --- a/java/nekurak.net-web/src/java/cz/frantovo/nekurak/web/UzivatelPredRegistraci.java	Thu Mar 04 12:02:41 2010 +0100
     8.2 +++ b/java/nekurak.net-web/src/java/cz/frantovo/nekurak/web/UzivatelPredRegistraci.java	Thu Mar 04 14:09:21 2010 +0100
     8.3 @@ -1,6 +1,9 @@
     8.4  package cz.frantovo.nekurak.web;
     8.5  
     8.6  import cz.frantovo.nekurak.dto.Uzivatel;
     8.7 +import cz.frantovo.nekurak.util.Hash;
     8.8 +import java.util.logging.Level;
     8.9 +import java.util.logging.Logger;
    8.10  
    8.11  /**
    8.12   * Pomocná třída obalujícího uživatele a token (kvůli CSRF)
    8.13 @@ -8,6 +11,7 @@
    8.14   */
    8.15  public class UzivatelPredRegistraci {
    8.16  
    8.17 +    private static final Logger log = Logger.getLogger(UzivatelPredRegistraci.class.getSimpleName());
    8.18      private Uzivatel uzivatel;
    8.19      private final String token = generujToken();
    8.20  
    8.21 @@ -23,9 +27,16 @@
    8.22  	return token;
    8.23      }
    8.24  
    8.25 +    /**
    8.26 +     * @return náhodný token
    8.27 +     */
    8.28      private static String generujToken() {
    8.29 -	/** TODO: generovat náhodný. */
    8.30 -	return "XXX_TODO_generovat_nahodny_token";
    8.31 +	try {
    8.32 +	    return Hash.hashuj(String.valueOf(Math.random()));
    8.33 +	} catch (Exception e) {
    8.34 +	    log.log(Level.SEVERE, "Chyba při generování háhodného tokenu", e);
    8.35 +	    /** Nemělo by nikdy nastat :-) */
    8.36 +	    return "nbusr123";
    8.37 +	}
    8.38      }
    8.39 -
    8.40  }
     9.1 --- a/java/nekurak.net-web/web/WEB-INF/casti/registrovatUzivatele.jsp	Thu Mar 04 12:02:41 2010 +0100
     9.2 +++ b/java/nekurak.net-web/web/WEB-INF/casti/registrovatUzivatele.jsp	Thu Mar 04 14:09:21 2010 +0100
     9.3 @@ -11,8 +11,16 @@
     9.4  
     9.5      <h1><fmt:message key="registrace.nadpis"/></h1>
     9.6  
     9.7 +    <!--
     9.8 +    Registrace probíhá ve třech krocích:
     9.9 +	1) uživatel vyplňí formulář
    9.10 +	2) zobrazíme mu vyplněné údaje a on si je zkontroluje
    9.11 +        3) potvrdí registraci
    9.12 +    -->
    9.13 +
    9.14      <c:choose>
    9.15  	<c:when test="${param.akceRegistrace == 'kontrola'}">
    9.16 +	    <!-- Vypíšeme uživateli údaje, které zadal do formuláře, aby si je mohl zkontrolovat. -->
    9.17  	    <jsp:setProperty name="uzivatel" property="*"/>
    9.18  	    <jsp:setProperty name="uzivatelPredRegistraci" property="uzivatel" value="${uzivatel}"/>
    9.19  	    <jsp:setProperty name="registraceUzivatele" property="uzivatel" value="${uzivatelPredRegistraci}"/>
    9.20 @@ -34,11 +42,14 @@
    9.21  
    9.22  	</c:when>
    9.23  	<c:when test="${param.akceRegistrace == 'dokonceni'}">
    9.24 -
    9.25 +	    <!-- Uživatel si zkontroloval údaje a chce dokončit svoji registraci. -->
    9.26  	    <jsp:setProperty name="registraceUzivatele" property="token" value="${param.token}"/>
    9.27  
    9.28 +	    <c:set var="chybaRegistrace" value="${registraceUzivatele.dokonciRegistraci}"/>
    9.29 +
    9.30  	    <c:choose>
    9.31 -		<c:when test="${registraceUzivatele.dokonciRegistraci}">
    9.32 +		<c:when test="${chybaRegistrace == null}">
    9.33 +		    <!-- Registrace proběhla úspěšně. -->
    9.34  		    <p>
    9.35  			<fmt:message key="registrace.hotovo"/>&amp;#160;
    9.36  			<a href="?akce=prihlaseni">
    9.37 @@ -47,17 +58,13 @@
    9.38  		    </p>
    9.39  		</c:when>
    9.40  		<c:otherwise>
    9.41 -		    <!--
    9.42 -		    Zaznamenali jsme pokus o CSRF nebo vypršela relace
    9.43 -		    a uživatel se pokouší dokončit registraci po dlouhé době.
    9.44 -		    -->
    9.45 -		    <p><fmt:message key="registrace.chybnyToken"/></p>
    9.46 +		    <!-- Během pokusu o registraci uživatele došlo k chybě. -->
    9.47 +		    <p class="chybovaHlaska"><fmt:message key="${chybaRegistrace}"/></p>
    9.48  		</c:otherwise>
    9.49  	    </c:choose>
    9.50 -
    9.51 -
    9.52  	</c:when>
    9.53  	<c:otherwise>
    9.54 +	    <!-- Zobrazíme uživateli registrační formulář. -->
    9.55  	    <form method="post" action="?akce=registrovatUzivatele&amp;amp;akceRegistrace=kontrola">
    9.56  		<fieldset>
    9.57  		    <fmt:message key="dto.uzivatel.prezdivka.tip" var="prezdivkaTip"/>
    9.58 @@ -74,7 +81,4 @@
    9.59  	</c:otherwise>
    9.60      </c:choose>
    9.61  
    9.62 -
    9.63 -
    9.64 -
    9.65  </jsp:root>