franta-hg@2
|
1 |
package cz.frantovo.jaas.sql;
|
franta-hg@2
|
2 |
|
franta-hg@4
|
3 |
import com.sun.enterprise.security.auth.realm.BadRealmException;
|
franta-hg@2
|
4 |
import com.sun.enterprise.security.auth.realm.NoSuchUserException;
|
franta-hg@6
|
5 |
import java.sql.Connection;
|
franta-hg@6
|
6 |
import java.sql.PreparedStatement;
|
franta-hg@6
|
7 |
import java.sql.ResultSet;
|
franta-hg@6
|
8 |
import java.sql.SQLException;
|
franta-hg@6
|
9 |
import java.sql.Statement;
|
franta-hg@6
|
10 |
import java.util.ArrayList;
|
franta-hg@6
|
11 |
import java.util.Collection;
|
franta-hg@6
|
12 |
import java.util.Collections;
|
franta-hg@2
|
13 |
import java.util.Enumeration;
|
franta-hg@4
|
14 |
import java.util.logging.Level;
|
franta-hg@6
|
15 |
import javax.naming.InitialContext;
|
franta-hg@6
|
16 |
import javax.naming.NamingException;
|
franta-hg@4
|
17 |
import javax.security.auth.login.LoginException;
|
franta-hg@6
|
18 |
import javax.sql.DataSource;
|
franta-hg@2
|
19 |
|
franta-hg@2
|
20 |
/**
|
franta-hg@6
|
21 |
* Bezpečnostní doména. Uživatelé jsou uloženi v SQL databázi.
|
franta-hg@6
|
22 |
*
|
franta-hg@2
|
23 |
* @author fiki
|
franta-hg@2
|
24 |
*/
|
franta-hg@7
|
25 |
public class SQLRealm extends ParametrizovanýRealm {
|
franta-hg@2
|
26 |
|
franta-hg@4
|
27 |
private static final String AUTH_TYPE = "Ověřuje uživatele proti SQL databázi.";
|
franta-hg@7
|
28 |
/**
|
franta-hg@7
|
29 |
* <p>JNDI jméno datového zdroje – odkazuje na instanci {@linkplain javax.sql.DataSource}</p>
|
franta-hg@7
|
30 |
*
|
franta-hg@7
|
31 |
* <p>Příklady:</p>
|
franta-hg@7
|
32 |
*
|
franta-hg@7
|
33 |
* <ul>
|
franta-hg@7
|
34 |
* <li><code>jdbc/mojeAplikace</code></li>
|
franta-hg@7
|
35 |
* </ul>
|
franta-hg@7
|
36 |
*/
|
franta-hg@7
|
37 |
public static final String PARAM_JNDI = "jndi";
|
franta-hg@7
|
38 |
/** Pokud je nastaveno na "true", nebude se při inicializaci testovat spojení s databází */
|
franta-hg@7
|
39 |
public static final String PARAM_NETESTOVAT_SPOJENÍ = "netestovat_spojeni";
|
franta-hg@7
|
40 |
/**
|
franta-hg@7
|
41 |
* <p>SQL dotaz pro kontrolu hesla.</p>
|
franta-hg@7
|
42 |
*
|
franta-hg@7
|
43 |
* <p>Má dva parametry:</p>
|
franta-hg@7
|
44 |
* <ol>
|
franta-hg@7
|
45 |
* <li>uživatelské jméno</li>
|
franta-hg@7
|
46 |
* <li>heslo</li>
|
franta-hg@7
|
47 |
* </ol>
|
franta-hg@7
|
48 |
*
|
franta-hg@7
|
49 |
* <p>Vrací:</p>
|
franta-hg@7
|
50 |
* <ul>
|
franta-hg@7
|
51 |
* <li>Při úspěšném ověření jednu hodnotu: uživatelské jméno</li>
|
franta-hg@7
|
52 |
* <li>Při neexistujícím uživateli nebo špatném hesle: prázdný výsledek (nula řádků)</li>
|
franta-hg@7
|
53 |
* <li>Při jiné chybě: vyhazuje výjimku</li>
|
franta-hg@7
|
54 |
* </ul>
|
franta-hg@7
|
55 |
*
|
franta-hg@7
|
56 |
* <p>Příklady:</p>
|
franta-hg@7
|
57 |
*
|
franta-hg@7
|
58 |
* <ul>
|
franta-hg@7
|
59 |
* <li><code>SELECT jmeno FROM uzivatel WHERE jmeno = ? AND heslo = ?</code></li>
|
franta-hg@7
|
60 |
* <li><code>SELECT jmeno FROM uzivatel WHERE jmeno = ? AND heslo = sha1(?)</code></li>
|
franta-hg@7
|
61 |
* <li><code>SELECT zkontroluj_heslo(?, ?)</code></li>
|
franta-hg@7
|
62 |
* </ul>
|
franta-hg@7
|
63 |
*
|
franta-hg@7
|
64 |
* <p>(hashovací a jiné funkce musí být samozřejmě podporované databází)</p>
|
franta-hg@7
|
65 |
*/
|
franta-hg@7
|
66 |
public static final String PARAM_SQL_HESLO = "sql_heslo";
|
franta-hg@7
|
67 |
/**
|
franta-hg@7
|
68 |
* <p>SQL dotaz pro zjištění skupin daného uživatele.</p>
|
franta-hg@7
|
69 |
*
|
franta-hg@7
|
70 |
* <p>Má jeden parametr: jméno uživatele</p>
|
franta-hg@7
|
71 |
*
|
franta-hg@7
|
72 |
* <p>Příklady:</p>
|
franta-hg@7
|
73 |
*
|
franta-hg@7
|
74 |
* <ul>
|
franta-hg@7
|
75 |
* <li><code>SELECT nazev FROM skupina WHERE uzivatel = ?</code></li>
|
franta-hg@7
|
76 |
* </ul>
|
franta-hg@7
|
77 |
*/
|
franta-hg@7
|
78 |
public static final String PARAM_SQL_SKUPINY_UŽIVATELE = "sql_skupiny_uzivatele";
|
franta-hg@7
|
79 |
/**
|
franta-hg@7
|
80 |
* <p>SQL dotaz pro zjištění všech skupin v dané bezpečnostní doméně.</p>
|
franta-hg@7
|
81 |
*
|
franta-hg@7
|
82 |
* <p>Příklady:</p>
|
franta-hg@7
|
83 |
*
|
franta-hg@7
|
84 |
* <ul>
|
franta-hg@7
|
85 |
* <li><code>SELECT nazev FROM skupina</code></li>
|
franta-hg@7
|
86 |
* </ul>
|
franta-hg@7
|
87 |
*/
|
franta-hg@7
|
88 |
public static final String PARAM_SQL_SKUPINY_VŠECHNY = "sql_skupiny_vsechny";
|
franta-hg@7
|
89 |
private String jndiDatovéhoZdroje;
|
franta-hg@6
|
90 |
private String sqlHeslo;
|
franta-hg@6
|
91 |
private String sqlSkupinyUživatele;
|
franta-hg@6
|
92 |
private String sqlSkupinyVšechny;
|
franta-hg@4
|
93 |
|
franta-hg@2
|
94 |
@Override
|
franta-hg@7
|
95 |
protected void parametrizuj() throws BadRealmException {
|
franta-hg@7
|
96 |
String jaasContext = getProperties().getProperty(JAAS_CONTEXT_PARAM, SQLLoginModul.VÝCHOZÍ_JAAS_KONTEXT);
|
franta-hg@7
|
97 |
getProperties().setProperty(JAAS_CONTEXT_PARAM, jaasContext);
|
franta-hg@4
|
98 |
|
franta-hg@6
|
99 |
/** Databázové spojení */
|
franta-hg@7
|
100 |
jndiDatovéhoZdroje = najdiParametr(PARAM_JNDI, "název datového zdroje");
|
franta-hg@7
|
101 |
testSpojení();
|
franta-hg@7
|
102 |
|
franta-hg@7
|
103 |
/** SQL dotazy */
|
franta-hg@7
|
104 |
sqlHeslo = najdiParametr(PARAM_SQL_HESLO, "SQL dotaz pro ověření jména a hesla");
|
franta-hg@7
|
105 |
sqlSkupinyUživatele = najdiParametr(PARAM_SQL_SKUPINY_UŽIVATELE, "SQL dotaz pro zjištění skupin uživatele");
|
franta-hg@7
|
106 |
sqlSkupinyVšechny = najdiParametr(PARAM_SQL_SKUPINY_VŠECHNY, "SQL dotaz pro zjištění všech skupin");
|
franta-hg@7
|
107 |
|
franta-hg@7
|
108 |
_logger.log(Level.INFO, "SQLRealm úspěšně parametrizován. JaasContext: {0}, počet parametrů: {1}", new Object[]{getJAASContext(), getProperties().size()});
|
franta-hg@7
|
109 |
}
|
franta-hg@7
|
110 |
|
franta-hg@7
|
111 |
private void testSpojení() throws BadRealmException {
|
franta-hg@7
|
112 |
if (Boolean.valueOf(getProperty(PARAM_NETESTOVAT_SPOJENÍ))) {
|
franta-hg@7
|
113 |
_logger.log(Level.WARNING, "Netestujeme databázové spojení při inicializaci.");
|
franta-hg@7
|
114 |
} else {
|
franta-hg@6
|
115 |
try {
|
franta-hg@7
|
116 |
Connection s = getSpojení();
|
franta-hg@7
|
117 |
s.close();
|
franta-hg@6
|
118 |
} catch (NamingException e) {
|
franta-hg@7
|
119 |
throw new BadRealmException("Datový zdroj s tímto názvem nebyl nalezen: " + jndiDatovéhoZdroje, e);
|
franta-hg@7
|
120 |
} catch (SQLException e) {
|
franta-hg@7
|
121 |
throw new BadRealmException("Nepodařilo se navázat spojení s DB datového zdroje: " + jndiDatovéhoZdroje, e);
|
franta-hg@6
|
122 |
}
|
franta-hg@6
|
123 |
}
|
franta-hg@7
|
124 |
}
|
franta-hg@6
|
125 |
|
franta-hg@7
|
126 |
private Connection getSpojení() throws NamingException, SQLException {
|
franta-hg@7
|
127 |
InitialContext k = new InitialContext();
|
franta-hg@7
|
128 |
DataSource datovýZdroj = (DataSource) k.lookup(jndiDatovéhoZdroje);
|
franta-hg@7
|
129 |
return datovýZdroj.getConnection();
|
franta-hg@7
|
130 |
}
|
franta-hg@6
|
131 |
|
franta-hg@2
|
132 |
@Override
|
franta-hg@4
|
133 |
public String getAuthType() {
|
franta-hg@4
|
134 |
return AUTH_TYPE;
|
franta-hg@4
|
135 |
}
|
franta-hg@4
|
136 |
|
franta-hg@4
|
137 |
/**
|
franta-hg@4
|
138 |
* @param uživatel přihlašovací jméno uživatele
|
franta-hg@4
|
139 |
* @return seznam skupin, ve kterých se daný uživatel nachází
|
franta-hg@4
|
140 |
* @throws NoSuchUserException když uživatel s tímto jménem neexistuje.
|
franta-hg@4
|
141 |
*/
|
franta-hg@4
|
142 |
@Override
|
franta-hg@6
|
143 |
public Enumeration<String> getGroupNames(String uživatel) throws NoSuchUserException {
|
franta-hg@7
|
144 |
try {
|
franta-hg@7
|
145 |
return getSkupiny(sqlSkupinyUživatele, uživatel);
|
franta-hg@7
|
146 |
} catch (NamingException | SQLException e) {
|
franta-hg@7
|
147 |
String hláška = "Chyba při zjišťování skupin uživatele: " + uživatel + ".";
|
franta-hg@7
|
148 |
_logger.log(Level.WARNING, hláška, e);
|
franta-hg@7
|
149 |
throw new NoSuchUserException(hláška);
|
franta-hg@7
|
150 |
}
|
franta-hg@7
|
151 |
}
|
franta-hg@7
|
152 |
|
franta-hg@7
|
153 |
/**
|
franta-hg@7
|
154 |
* @return seznam všech skupin v této bezpečnostní doméně
|
franta-hg@7
|
155 |
* @throws BadRealmException v případě SQL chyby
|
franta-hg@7
|
156 |
*/
|
franta-hg@7
|
157 |
@Override
|
franta-hg@7
|
158 |
public Enumeration getGroupNames() throws BadRealmException {
|
franta-hg@7
|
159 |
try {
|
franta-hg@7
|
160 |
return getSkupiny(sqlSkupinyVšechny, null);
|
franta-hg@7
|
161 |
} catch (NamingException | SQLException e) {
|
franta-hg@7
|
162 |
throw new BadRealmException("Chyba při zjišťování seznamu všech skupin.", e);
|
franta-hg@7
|
163 |
}
|
franta-hg@7
|
164 |
}
|
franta-hg@7
|
165 |
|
franta-hg@7
|
166 |
public Enumeration<String> getSkupiny(String sql, String parametr) throws SQLException, NamingException {
|
franta-hg@6
|
167 |
Collection<String> skupiny = new ArrayList<>();
|
franta-hg@6
|
168 |
|
franta-hg@6
|
169 |
Connection s = null;
|
franta-hg@6
|
170 |
PreparedStatement ps = null;
|
franta-hg@6
|
171 |
ResultSet rs = null;
|
franta-hg@6
|
172 |
try {
|
franta-hg@7
|
173 |
s = getSpojení();
|
franta-hg@7
|
174 |
|
franta-hg@7
|
175 |
ps = s.prepareStatement(sql);
|
franta-hg@7
|
176 |
if (parametr != null) {
|
franta-hg@7
|
177 |
ps.setString(1, parametr);
|
franta-hg@7
|
178 |
}
|
franta-hg@6
|
179 |
rs = ps.executeQuery();
|
franta-hg@6
|
180 |
|
franta-hg@6
|
181 |
while (rs.next()) {
|
franta-hg@6
|
182 |
skupiny.add(rs.getString(1));
|
franta-hg@6
|
183 |
}
|
franta-hg@6
|
184 |
|
franta-hg@6
|
185 |
return Collections.enumeration(skupiny);
|
franta-hg@6
|
186 |
} finally {
|
franta-hg@6
|
187 |
zavri(s, ps, rs);
|
franta-hg@6
|
188 |
}
|
franta-hg@4
|
189 |
}
|
franta-hg@4
|
190 |
|
franta-hg@4
|
191 |
/**
|
franta-hg@7
|
192 |
*
|
franta-hg@4
|
193 |
* @param jméno uživatelské jméno
|
franta-hg@4
|
194 |
* @param heslo heslo
|
franta-hg@6
|
195 |
* @return true pokud je jméno a heslo v pořádku | false nikdy – vyhazuje výjimku
|
franta-hg@6
|
196 |
* @throws LoginException pokud je jméno nebo heslo neplatné nebo došlo k jiné chybě
|
franta-hg@4
|
197 |
*/
|
franta-hg@6
|
198 |
public boolean ověřUživatele(String jméno, char[] heslo) throws LoginException {
|
franta-hg@4
|
199 |
|
franta-hg@6
|
200 |
Connection s = null;
|
franta-hg@6
|
201 |
PreparedStatement ps = null;
|
franta-hg@6
|
202 |
ResultSet rs = null;
|
franta-hg@6
|
203 |
try {
|
franta-hg@7
|
204 |
s = getSpojení();
|
franta-hg@6
|
205 |
ps = s.prepareStatement(sqlHeslo);
|
franta-hg@6
|
206 |
ps.setString(1, jméno);
|
franta-hg@6
|
207 |
ps.setString(2, new String(heslo));
|
franta-hg@6
|
208 |
rs = ps.executeQuery();
|
franta-hg@4
|
209 |
|
franta-hg@6
|
210 |
if (rs.next()) {
|
franta-hg@6
|
211 |
String dbJméno = rs.getString(1);
|
franta-hg@7
|
212 |
if (dbJméno != null && dbJméno.equals(jméno)) {
|
franta-hg@6
|
213 |
// OK – úspěšné ověření
|
franta-hg@6
|
214 |
return true;
|
franta-hg@6
|
215 |
} else {
|
franta-hg@7
|
216 |
throw new LoginException("Špatné heslo nebo neexistující uživatel: " + jméno + " != " + dbJméno);
|
franta-hg@6
|
217 |
}
|
franta-hg@6
|
218 |
} else {
|
franta-hg@7
|
219 |
throw new LoginException("Špatné heslo nebo neexistující uživatel: " + jméno);
|
franta-hg@6
|
220 |
}
|
franta-hg@7
|
221 |
} catch (NamingException | SQLException e) {
|
franta-hg@6
|
222 |
String hláška = "SQL chyba při ověřování hesla uživatele: " + jméno + ".";
|
franta-hg@6
|
223 |
_logger.log(Level.WARNING, hláška, e);
|
franta-hg@6
|
224 |
throw new LoginException(hláška);
|
franta-hg@6
|
225 |
} finally {
|
franta-hg@6
|
226 |
zavri(s, ps, rs);
|
franta-hg@6
|
227 |
}
|
franta-hg@6
|
228 |
}
|
franta-hg@6
|
229 |
|
franta-hg@6
|
230 |
/**
|
franta-hg@6
|
231 |
* Zavře všechno
|
franta-hg@6
|
232 |
*
|
franta-hg@6
|
233 |
* @param spojeni DB spojení
|
franta-hg@6
|
234 |
* @param prikaz DB dotaz
|
franta-hg@6
|
235 |
* @param vysledek DB výsledek
|
franta-hg@6
|
236 |
*/
|
franta-hg@6
|
237 |
private static void zavri(Connection spojeni, Statement prikaz, ResultSet vysledek) {
|
franta-hg@6
|
238 |
if (vysledek != null) {
|
franta-hg@6
|
239 |
try {
|
franta-hg@6
|
240 |
vysledek.close();
|
franta-hg@6
|
241 |
} catch (Exception e) {
|
franta-hg@7
|
242 |
_logger.log(Level.FINE, "Při zavírání SQL výsledku došlo k chybě.", e);
|
franta-hg@6
|
243 |
}
|
franta-hg@6
|
244 |
}
|
franta-hg@6
|
245 |
if (prikaz != null) {
|
franta-hg@6
|
246 |
try {
|
franta-hg@6
|
247 |
prikaz.close();
|
franta-hg@6
|
248 |
} catch (Exception e) {
|
franta-hg@7
|
249 |
_logger.log(Level.FINE, "Při zavírání SQL příkazu došlo k chybě.", e);
|
franta-hg@6
|
250 |
}
|
franta-hg@6
|
251 |
}
|
franta-hg@6
|
252 |
if (spojeni != null) {
|
franta-hg@6
|
253 |
try {
|
franta-hg@6
|
254 |
spojeni.close();
|
franta-hg@6
|
255 |
} catch (Exception e) {
|
franta-hg@7
|
256 |
_logger.log(Level.FINE, "Při zavírání SQL spojení došlo k chybě.", e);
|
franta-hg@6
|
257 |
}
|
franta-hg@4
|
258 |
}
|
franta-hg@2
|
259 |
}
|
franta-hg@2
|
260 |
}
|