1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.eclipse.jetty.plus.security;
21
22 import java.sql.Connection;
23 import java.sql.DatabaseMetaData;
24 import java.sql.PreparedStatement;
25 import java.sql.ResultSet;
26 import java.sql.SQLException;
27 import java.sql.Statement;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Locale;
31
32 import javax.naming.InitialContext;
33 import javax.naming.NameNotFoundException;
34 import javax.naming.NamingException;
35 import javax.servlet.ServletRequest;
36 import javax.sql.DataSource;
37
38 import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
39 import org.eclipse.jetty.security.IdentityService;
40 import org.eclipse.jetty.security.MappedLoginService;
41 import org.eclipse.jetty.server.Server;
42 import org.eclipse.jetty.server.UserIdentity;
43 import org.eclipse.jetty.util.log.Log;
44 import org.eclipse.jetty.util.log.Logger;
45 import org.eclipse.jetty.util.security.Credential;
46
47
48
49
50
51
52
53
54 public class DataSourceLoginService extends MappedLoginService
55 {
56 private static final Logger LOG = Log.getLogger(DataSourceLoginService.class);
57
58 private String _jndiName = "javax.sql.DataSource/default";
59 private DataSource _datasource;
60 private Server _server;
61 private String _userTableName = "users";
62 private String _userTableKey = "id";
63 private String _userTableUserField = "username";
64 private String _userTablePasswordField = "pwd";
65 private String _roleTableName = "roles";
66 private String _roleTableKey = "id";
67 private String _roleTableRoleField = "role";
68 private String _userRoleTableName = "user_roles";
69 private String _userRoleTableUserKey = "user_id";
70 private String _userRoleTableRoleKey = "role_id";
71 private int _cacheMs = 30000;
72 private long _lastPurge = 0;
73 private String _userSql;
74 private String _roleSql;
75 private boolean _createTables = false;
76
77
78
79
80
81 public class DBUser extends KnownUser
82 {
83 private int _key;
84
85 public DBUser(String name, Credential credential, int key)
86 {
87 super(name, credential);
88 _key = key;
89 }
90
91 public int getKey ()
92 {
93 return _key;
94 }
95
96 }
97
98
99 public DataSourceLoginService()
100 {
101 }
102
103
104 public DataSourceLoginService(String name)
105 {
106 setName(name);
107 }
108
109
110 public DataSourceLoginService(String name, IdentityService identityService)
111 {
112 setName(name);
113 setIdentityService(identityService);
114 }
115
116
117 public void setJndiName (String jndi)
118 {
119 _jndiName = jndi;
120 }
121
122
123 public String getJndiName ()
124 {
125 return _jndiName;
126 }
127
128
129 public void setServer (Server server)
130 {
131 _server=server;
132 }
133
134
135 public Server getServer()
136 {
137 return _server;
138 }
139
140
141 public void setCreateTables(boolean createTables)
142 {
143 _createTables = createTables;
144 }
145
146
147 public boolean getCreateTables()
148 {
149 return _createTables;
150 }
151
152
153 public void setUserTableName (String name)
154 {
155 _userTableName=name;
156 }
157
158
159 public String getUserTableName()
160 {
161 return _userTableName;
162 }
163
164
165 public String getUserTableKey()
166 {
167 return _userTableKey;
168 }
169
170
171
172 public void setUserTableKey(String tableKey)
173 {
174 _userTableKey = tableKey;
175 }
176
177
178
179 public String getUserTableUserField()
180 {
181 return _userTableUserField;
182 }
183
184
185
186 public void setUserTableUserField(String tableUserField)
187 {
188 _userTableUserField = tableUserField;
189 }
190
191
192
193 public String getUserTablePasswordField()
194 {
195 return _userTablePasswordField;
196 }
197
198
199
200 public void setUserTablePasswordField(String tablePasswordField)
201 {
202 _userTablePasswordField = tablePasswordField;
203 }
204
205
206
207 public String getRoleTableName()
208 {
209 return _roleTableName;
210 }
211
212
213
214 public void setRoleTableName(String tableName)
215 {
216 _roleTableName = tableName;
217 }
218
219
220
221 public String getRoleTableKey()
222 {
223 return _roleTableKey;
224 }
225
226
227
228 public void setRoleTableKey(String tableKey)
229 {
230 _roleTableKey = tableKey;
231 }
232
233
234
235 public String getRoleTableRoleField()
236 {
237 return _roleTableRoleField;
238 }
239
240
241
242 public void setRoleTableRoleField(String tableRoleField)
243 {
244 _roleTableRoleField = tableRoleField;
245 }
246
247
248
249 public String getUserRoleTableName()
250 {
251 return _userRoleTableName;
252 }
253
254
255
256 public void setUserRoleTableName(String roleTableName)
257 {
258 _userRoleTableName = roleTableName;
259 }
260
261
262
263 public String getUserRoleTableUserKey()
264 {
265 return _userRoleTableUserKey;
266 }
267
268
269
270 public void setUserRoleTableUserKey(String roleTableUserKey)
271 {
272 _userRoleTableUserKey = roleTableUserKey;
273 }
274
275
276
277 public String getUserRoleTableRoleKey()
278 {
279 return _userRoleTableRoleKey;
280 }
281
282
283
284 public void setUserRoleTableRoleKey(String roleTableRoleKey)
285 {
286 _userRoleTableRoleKey = roleTableRoleKey;
287 }
288
289
290 public void setCacheMs (int ms)
291 {
292 _cacheMs=ms;
293 }
294
295
296 public int getCacheMs ()
297 {
298 return _cacheMs;
299 }
300
301
302 @Override
303 protected void loadUsers()
304 {
305 }
306
307
308
309
310
311
312
313
314 @Deprecated
315 protected UserIdentity loadUser (String userName)
316 {
317 try
318 {
319 try (Connection connection = getConnection();
320 PreparedStatement statement1 = connection.prepareStatement(_userSql))
321 {
322 statement1.setObject(1, userName);
323 try (ResultSet rs1 = statement1.executeQuery())
324 {
325 if (rs1.next())
326 {
327 int key = rs1.getInt(_userTableKey);
328 String credentials = rs1.getString(_userTablePasswordField);
329
330 List<String> roles = new ArrayList<String>();
331 try (PreparedStatement statement2 = connection.prepareStatement(_roleSql))
332 {
333 statement2.setInt(1, key);
334 try (ResultSet rs2 = statement2.executeQuery())
335 {
336 while (rs2.next())
337 {
338 roles.add(rs2.getString(_roleTableRoleField));
339 }
340 }
341 }
342 return putUser(userName, Credential.getCredential(credentials), roles.toArray(new String[roles.size()]));
343 }
344 }
345 }
346 }
347 catch (NamingException e)
348 {
349 LOG.warn("No datasource for "+_jndiName, e);
350 }
351 catch (SQLException e)
352 {
353 LOG.warn("Problem loading user info for "+userName, e);
354 }
355 return null;
356 }
357
358
359
360
361
362 public KnownUser loadUserInfo (String username)
363 {
364 try
365 {
366 try (Connection connection = getConnection();
367 PreparedStatement statement1 = connection.prepareStatement(_userSql))
368 {
369 statement1.setObject(1, username);
370 try (ResultSet rs1 = statement1.executeQuery())
371 {
372 if (rs1.next())
373 {
374 int key = rs1.getInt(_userTableKey);
375 String credentials = rs1.getString(_userTablePasswordField);
376
377 return new DBUser(username, Credential.getCredential(credentials), key);
378 }
379 }
380 }
381 }
382 catch (NamingException e)
383 {
384 LOG.warn("No datasource for "+_jndiName, e);
385 }
386 catch (SQLException e)
387 {
388 LOG.warn("Problem loading user info for "+username, e);
389 }
390 return null;
391 }
392
393
394
395
396 public String[] loadRoleInfo (KnownUser user)
397 {
398 DBUser dbuser = (DBUser)user;
399
400 try
401 {
402 try (Connection connection = getConnection();
403 PreparedStatement statement2 = connection.prepareStatement(_roleSql))
404 {
405
406 List<String> roles = new ArrayList<String>();
407
408 statement2.setInt(1, dbuser.getKey());
409 try (ResultSet rs2 = statement2.executeQuery())
410 {
411 while (rs2.next())
412 {
413 roles.add(rs2.getString(_roleTableRoleField));
414 }
415
416 return roles.toArray(new String[roles.size()]);
417 }
418 }
419 }
420 catch (NamingException e)
421 {
422 LOG.warn("No datasource for "+_jndiName, e);
423 }
424 catch (SQLException e)
425 {
426 LOG.warn("Problem loading user info for "+user.getName(), e);
427 }
428 return null;
429 }
430
431
432 @Override
433 public UserIdentity login(String username, Object credentials, ServletRequest request)
434 {
435 long now = System.currentTimeMillis();
436 if (now - _lastPurge > _cacheMs || _cacheMs == 0)
437 {
438 _users.clear();
439 _lastPurge = now;
440 }
441
442 return super.login(username,credentials, request);
443 }
444
445
446
447
448
449
450
451
452
453
454 public void initDb() throws NamingException, SQLException
455 {
456 if (_datasource != null)
457 return;
458
459 @SuppressWarnings("unused")
460 InitialContext ic = new InitialContext();
461 assert ic!=null;
462
463
464
465
466 if (_server != null)
467 {
468 try
469 {
470 _datasource = (DataSource)NamingEntryUtil.lookup(_server, _jndiName);
471 }
472 catch (NameNotFoundException e)
473 {
474
475 }
476 }
477
478
479
480 if (_datasource==null)
481 {
482 _datasource = (DataSource)NamingEntryUtil.lookup(null, _jndiName);
483 }
484
485
486 _userSql = "select " + _userTableKey + "," + _userTablePasswordField
487 + " from " + _userTableName
488 + " where "+ _userTableUserField + " = ?";
489
490 _roleSql = "select r." + _roleTableRoleField
491 + " from " + _roleTableName + " r, " + _userRoleTableName
492 + " u where u."+ _userRoleTableUserKey + " = ?"
493 + " and r." + _roleTableKey + " = u." + _userRoleTableRoleKey;
494
495 prepareTables();
496 }
497
498 private void prepareTables()
499 throws NamingException, SQLException
500 {
501 if (_createTables)
502 {
503 boolean autocommit = true;
504 Connection connection = getConnection();
505 try (Statement stmt = connection.createStatement())
506 {
507 autocommit = connection.getAutoCommit();
508 connection.setAutoCommit(false);
509 DatabaseMetaData metaData = connection.getMetaData();
510
511
512 String tableName = (metaData.storesLowerCaseIdentifiers()? _userTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_userTableName.toUpperCase(Locale.ENGLISH): _userTableName));
513 try (ResultSet result = metaData.getTables(null, null, tableName, null))
514 {
515 if (!result.next())
516 {
517
518
519
520
521
522
523 stmt.executeUpdate("create table "+_userTableName+ "("+_userTableKey+" integer,"+
524 _userTableUserField+" varchar(100) not null unique,"+
525 _userTablePasswordField+" varchar(20) not null, primary key("+_userTableKey+"))");
526 if (LOG.isDebugEnabled()) LOG.debug("Created table "+_userTableName);
527 }
528 }
529
530 tableName = (metaData.storesLowerCaseIdentifiers()? _roleTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_roleTableName.toUpperCase(Locale.ENGLISH): _roleTableName));
531 try (ResultSet result = metaData.getTables(null, null, tableName, null))
532 {
533 if (!result.next())
534 {
535
536
537
538
539
540 String str = "create table "+_roleTableName+" ("+_roleTableKey+" integer, "+
541 _roleTableRoleField+" varchar(100) not null unique, primary key("+_roleTableKey+"))";
542 stmt.executeUpdate(str);
543 if (LOG.isDebugEnabled()) LOG.debug("Created table "+_roleTableName);
544 }
545 }
546
547 tableName = (metaData.storesLowerCaseIdentifiers()? _userRoleTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_userRoleTableName.toUpperCase(Locale.ENGLISH): _userRoleTableName));
548 try (ResultSet result = metaData.getTables(null, null, tableName, null))
549 {
550 if (!result.next())
551 {
552
553
554
555
556
557
558
559
560 stmt.executeUpdate("create table "+_userRoleTableName+" ("+_userRoleTableUserKey+" integer, "+
561 _userRoleTableRoleKey+" integer, "+
562 "primary key ("+_userRoleTableUserKey+", "+_userRoleTableRoleKey+"))");
563 stmt.executeUpdate("create index indx_user_role on "+_userRoleTableName+"("+_userRoleTableUserKey+")");
564 if (LOG.isDebugEnabled()) LOG.debug("Created table "+_userRoleTableName +" and index");
565 }
566 }
567 connection.commit();
568 }
569 finally
570 {
571 try
572 {
573 connection.setAutoCommit(autocommit);
574 }
575 catch (SQLException e)
576 {
577 if (LOG.isDebugEnabled()) LOG.debug("Prepare tables", e);
578 }
579 finally
580 {
581 try
582 {
583 connection.close();
584 }
585 catch (SQLException e)
586 {
587 if (LOG.isDebugEnabled()) LOG.debug("Prepare tables", e);
588 }
589 }
590 }
591 }
592 else if (LOG.isDebugEnabled())
593 {
594 LOG.debug("createTables false");
595 }
596 }
597
598 private Connection getConnection ()
599 throws NamingException, SQLException
600 {
601 initDb();
602 return _datasource.getConnection();
603 }
604 }