1.1 --- a/java/sql-java-prihlasovani/src/cz/frantovo/jaas/sql/SQLRealm.java Tue Feb 07 00:27:39 2012 +0100
1.2 +++ b/java/sql-java-prihlasovani/src/cz/frantovo/jaas/sql/SQLRealm.java Tue Feb 07 18:03:31 2012 +0100
1.3 @@ -1,8 +1,6 @@
1.4 package cz.frantovo.jaas.sql;
1.5
1.6 -import com.sun.appserv.security.AppservRealm;
1.7 import com.sun.enterprise.security.auth.realm.BadRealmException;
1.8 -import com.sun.enterprise.security.auth.realm.NoSuchRealmException;
1.9 import com.sun.enterprise.security.auth.realm.NoSuchUserException;
1.10 import java.sql.Connection;
1.11 import java.sql.PreparedStatement;
1.12 @@ -13,7 +11,6 @@
1.13 import java.util.Collection;
1.14 import java.util.Collections;
1.15 import java.util.Enumeration;
1.16 -import java.util.Properties;
1.17 import java.util.logging.Level;
1.18 import javax.naming.InitialContext;
1.19 import javax.naming.NamingException;
1.20 @@ -25,52 +22,113 @@
1.21 *
1.22 * @author fiki
1.23 */
1.24 -public class SQLRealm extends AppservRealm {
1.25 +public class SQLRealm extends ParametrizovanýRealm {
1.26
1.27 private static final String AUTH_TYPE = "Ověřuje uživatele proti SQL databázi.";
1.28 - private static final String PARAM_JNDI = "jndi";
1.29 - private static final String PARAM_SQL_HESLO = "sql_heslo";
1.30 - private static final String PARAM_SQL_SKUPINY_UŽIVATELE = "sql_skupiny_uzivatele";
1.31 - private static final String PARAM_SQL_SKUPINY_VŠECHNY = "sql_skupiny_vsechny";
1.32 - private DataSource datovýZdroj;
1.33 + /**
1.34 + * <p>JNDI jméno datového zdroje – odkazuje na instanci {@linkplain javax.sql.DataSource}</p>
1.35 + *
1.36 + * <p>Příklady:</p>
1.37 + *
1.38 + * <ul>
1.39 + * <li><code>jdbc/mojeAplikace</code></li>
1.40 + * </ul>
1.41 + */
1.42 + public static final String PARAM_JNDI = "jndi";
1.43 + /** Pokud je nastaveno na "true", nebude se při inicializaci testovat spojení s databází */
1.44 + public static final String PARAM_NETESTOVAT_SPOJENÍ = "netestovat_spojeni";
1.45 + /**
1.46 + * <p>SQL dotaz pro kontrolu hesla.</p>
1.47 + *
1.48 + * <p>Má dva parametry:</p>
1.49 + * <ol>
1.50 + * <li>uživatelské jméno</li>
1.51 + * <li>heslo</li>
1.52 + * </ol>
1.53 + *
1.54 + * <p>Vrací:</p>
1.55 + * <ul>
1.56 + * <li>Při úspěšném ověření jednu hodnotu: uživatelské jméno</li>
1.57 + * <li>Při neexistujícím uživateli nebo špatném hesle: prázdný výsledek (nula řádků)</li>
1.58 + * <li>Při jiné chybě: vyhazuje výjimku</li>
1.59 + * </ul>
1.60 + *
1.61 + * <p>Příklady:</p>
1.62 + *
1.63 + * <ul>
1.64 + * <li><code>SELECT jmeno FROM uzivatel WHERE jmeno = ? AND heslo = ?</code></li>
1.65 + * <li><code>SELECT jmeno FROM uzivatel WHERE jmeno = ? AND heslo = sha1(?)</code></li>
1.66 + * <li><code>SELECT zkontroluj_heslo(?, ?)</code></li>
1.67 + * </ul>
1.68 + *
1.69 + * <p>(hashovací a jiné funkce musí být samozřejmě podporované databází)</p>
1.70 + */
1.71 + public static final String PARAM_SQL_HESLO = "sql_heslo";
1.72 + /**
1.73 + * <p>SQL dotaz pro zjištění skupin daného uživatele.</p>
1.74 + *
1.75 + * <p>Má jeden parametr: jméno uživatele</p>
1.76 + *
1.77 + * <p>Příklady:</p>
1.78 + *
1.79 + * <ul>
1.80 + * <li><code>SELECT nazev FROM skupina WHERE uzivatel = ?</code></li>
1.81 + * </ul>
1.82 + */
1.83 + public static final String PARAM_SQL_SKUPINY_UŽIVATELE = "sql_skupiny_uzivatele";
1.84 + /**
1.85 + * <p>SQL dotaz pro zjištění všech skupin v dané bezpečnostní doméně.</p>
1.86 + *
1.87 + * <p>Příklady:</p>
1.88 + *
1.89 + * <ul>
1.90 + * <li><code>SELECT nazev FROM skupina</code></li>
1.91 + * </ul>
1.92 + */
1.93 + public static final String PARAM_SQL_SKUPINY_VŠECHNY = "sql_skupiny_vsechny";
1.94 + private String jndiDatovéhoZdroje;
1.95 private String sqlHeslo;
1.96 private String sqlSkupinyUživatele;
1.97 private String sqlSkupinyVšechny;
1.98
1.99 - /**
1.100 - * Načteme a zkontrolujeme parametry
1.101 - *
1.102 - * @param parametry
1.103 - * @throws BadRealmException pokud je v parametrech chyba
1.104 - * @throws NoSuchRealmException
1.105 - */
1.106 @Override
1.107 - public void init(Properties parametry) throws BadRealmException, NoSuchRealmException {
1.108 - super.init(parametry);
1.109 -
1.110 - String jaasContext = parametry.getProperty(JAAS_CONTEXT_PARAM, SQLLoginModul.VÝCHOZÍ_JAAS_KONTEXT);
1.111 - setProperty(JAAS_CONTEXT_PARAM, jaasContext);
1.112 + protected void parametrizuj() throws BadRealmException {
1.113 + String jaasContext = getProperties().getProperty(JAAS_CONTEXT_PARAM, SQLLoginModul.VÝCHOZÍ_JAAS_KONTEXT);
1.114 + getProperties().setProperty(JAAS_CONTEXT_PARAM, jaasContext);
1.115
1.116 /** Databázové spojení */
1.117 - {
1.118 - String jndi = najdiParametr(parametry, PARAM_JNDI, "název datového zdroje");
1.119 + jndiDatovéhoZdroje = najdiParametr(PARAM_JNDI, "název datového zdroje");
1.120 + testSpojení();
1.121 +
1.122 + /** SQL dotazy */
1.123 + sqlHeslo = najdiParametr(PARAM_SQL_HESLO, "SQL dotaz pro ověření jména a hesla");
1.124 + sqlSkupinyUživatele = najdiParametr(PARAM_SQL_SKUPINY_UŽIVATELE, "SQL dotaz pro zjištění skupin uživatele");
1.125 + sqlSkupinyVšechny = najdiParametr(PARAM_SQL_SKUPINY_VŠECHNY, "SQL dotaz pro zjištění všech skupin");
1.126 +
1.127 + _logger.log(Level.INFO, "SQLRealm úspěšně parametrizován. JaasContext: {0}, počet parametrů: {1}", new Object[]{getJAASContext(), getProperties().size()});
1.128 + }
1.129 +
1.130 + private void testSpojení() throws BadRealmException {
1.131 + if (Boolean.valueOf(getProperty(PARAM_NETESTOVAT_SPOJENÍ))) {
1.132 + _logger.log(Level.WARNING, "Netestujeme databázové spojení při inicializaci.");
1.133 + } else {
1.134 try {
1.135 - InitialContext k = new InitialContext();
1.136 - jndi = parametry.getProperty(PARAM_JNDI);
1.137 - datovýZdroj = (DataSource) k.lookup(jndi);
1.138 + Connection s = getSpojení();
1.139 + s.close();
1.140 } catch (NamingException e) {
1.141 - throw new BadRealmException("Datový zdroj s tímto názvem nebyl nalezen: " + jndi, e);
1.142 + throw new BadRealmException("Datový zdroj s tímto názvem nebyl nalezen: " + jndiDatovéhoZdroje, e);
1.143 + } catch (SQLException e) {
1.144 + throw new BadRealmException("Nepodařilo se navázat spojení s DB datového zdroje: " + jndiDatovéhoZdroje, e);
1.145 }
1.146 }
1.147 + }
1.148
1.149 - /** SQL dotazy */
1.150 - sqlHeslo = najdiParametr(parametry, PARAM_SQL_HESLO, "SQL dotaz pro ověření jména a hesla");
1.151 - sqlSkupinyUživatele = najdiParametr(parametry, PARAM_SQL_SKUPINY_UŽIVATELE, "SQL dotaz pro zjištění skupin uživatele");
1.152 - sqlSkupinyVšechny = najdiParametr(parametry, PARAM_SQL_SKUPINY_VŠECHNY, "SQL dotaz pro zjištění všech skupin");
1.153 + private Connection getSpojení() throws NamingException, SQLException {
1.154 + InitialContext k = new InitialContext();
1.155 + DataSource datovýZdroj = (DataSource) k.lookup(jndiDatovéhoZdroje);
1.156 + return datovýZdroj.getConnection();
1.157 + }
1.158
1.159 - _logger.log(Level.INFO, "SQLRealm úspěšně vytvořen. JaasContext: {0}", jaasContext);
1.160 - }
1.161 -
1.162 @Override
1.163 public String getAuthType() {
1.164 return AUTH_TYPE;
1.165 @@ -83,15 +141,41 @@
1.166 */
1.167 @Override
1.168 public Enumeration<String> getGroupNames(String uživatel) throws NoSuchUserException {
1.169 + try {
1.170 + return getSkupiny(sqlSkupinyUživatele, uživatel);
1.171 + } catch (NamingException | SQLException e) {
1.172 + String hláška = "Chyba při zjišťování skupin uživatele: " + uživatel + ".";
1.173 + _logger.log(Level.WARNING, hláška, e);
1.174 + throw new NoSuchUserException(hláška);
1.175 + }
1.176 + }
1.177 +
1.178 + /**
1.179 + * @return seznam všech skupin v této bezpečnostní doméně
1.180 + * @throws BadRealmException v případě SQL chyby
1.181 + */
1.182 + @Override
1.183 + public Enumeration getGroupNames() throws BadRealmException {
1.184 + try {
1.185 + return getSkupiny(sqlSkupinyVšechny, null);
1.186 + } catch (NamingException | SQLException e) {
1.187 + throw new BadRealmException("Chyba při zjišťování seznamu všech skupin.", e);
1.188 + }
1.189 + }
1.190 +
1.191 + public Enumeration<String> getSkupiny(String sql, String parametr) throws SQLException, NamingException {
1.192 Collection<String> skupiny = new ArrayList<>();
1.193
1.194 Connection s = null;
1.195 PreparedStatement ps = null;
1.196 ResultSet rs = null;
1.197 try {
1.198 - s = datovýZdroj.getConnection();
1.199 - ps = s.prepareStatement(sqlSkupinyUživatele);
1.200 - ps.setString(1, uživatel);
1.201 + s = getSpojení();
1.202 +
1.203 + ps = s.prepareStatement(sql);
1.204 + if (parametr != null) {
1.205 + ps.setString(1, parametr);
1.206 + }
1.207 rs = ps.executeQuery();
1.208
1.209 while (rs.next()) {
1.210 @@ -99,18 +183,13 @@
1.211 }
1.212
1.213 return Collections.enumeration(skupiny);
1.214 -
1.215 - } catch (Exception e) {
1.216 - String hláška = "Chyba při zjišťování skupin uživatele: " + uživatel + ".";
1.217 - _logger.log(Level.WARNING, hláška, e);
1.218 - throw new NoSuchUserException(hláška);
1.219 } finally {
1.220 zavri(s, ps, rs);
1.221 }
1.222 }
1.223
1.224 /**
1.225 - *
1.226 + *
1.227 * @param jméno uživatelské jméno
1.228 * @param heslo heslo
1.229 * @return true pokud je jméno a heslo v pořádku | false nikdy – vyhazuje výjimku
1.230 @@ -122,7 +201,7 @@
1.231 PreparedStatement ps = null;
1.232 ResultSet rs = null;
1.233 try {
1.234 - s = datovýZdroj.getConnection();
1.235 + s = getSpojení();
1.236 ps = s.prepareStatement(sqlHeslo);
1.237 ps.setString(1, jméno);
1.238 ps.setString(2, new String(heslo));
1.239 @@ -130,16 +209,16 @@
1.240
1.241 if (rs.next()) {
1.242 String dbJméno = rs.getString(1);
1.243 - if (dbJméno.equals(jméno)) {
1.244 + if (dbJméno != null && dbJméno.equals(jméno)) {
1.245 // OK – úspěšné ověření
1.246 return true;
1.247 } else {
1.248 - throw new LoginException("Nebyl nalezen správný uživatel: " + jméno + " != " + dbJméno);
1.249 + throw new LoginException("Špatné heslo nebo neexistující uživatel: " + jméno + " != " + dbJméno);
1.250 }
1.251 } else {
1.252 - throw new LoginException("Uživatel nebyl nalezen: " + jméno);
1.253 + throw new LoginException("Špatné heslo nebo neexistující uživatel: " + jméno);
1.254 }
1.255 - } catch (SQLException e) {
1.256 + } catch (NamingException | SQLException e) {
1.257 String hláška = "SQL chyba při ověřování hesla uživatele: " + jméno + ".";
1.258 _logger.log(Level.WARNING, hláška, e);
1.259 throw new LoginException(hláška);
1.260 @@ -148,16 +227,6 @@
1.261 }
1.262 }
1.263
1.264 - private String najdiParametr(Properties parametry, String názevParametru, String popis) throws BadRealmException {
1.265 - String hodnotaParametru = parametry.getProperty(názevParametru);
1.266 -
1.267 - if (hodnotaParametru == null || hodnotaParametru.length() < 1) {
1.268 - throw new BadRealmException("Chybí " + popis + " – parametr: " + názevParametru);
1.269 - } else {
1.270 - return hodnotaParametru;
1.271 - }
1.272 - }
1.273 -
1.274 /**
1.275 * Zavře všechno
1.276 *
1.277 @@ -170,18 +239,21 @@
1.278 try {
1.279 vysledek.close();
1.280 } catch (Exception e) {
1.281 + _logger.log(Level.FINE, "Při zavírání SQL výsledku došlo k chybě.", e);
1.282 }
1.283 }
1.284 if (prikaz != null) {
1.285 try {
1.286 prikaz.close();
1.287 } catch (Exception e) {
1.288 + _logger.log(Level.FINE, "Při zavírání SQL příkazu došlo k chybě.", e);
1.289 }
1.290 }
1.291 if (spojeni != null) {
1.292 try {
1.293 spojeni.close();
1.294 } catch (Exception e) {
1.295 + _logger.log(Level.FINE, "Při zavírání SQL spojení došlo k chybě.", e);
1.296 }
1.297 }
1.298 }