View Javadoc

1   // ========================================================================
2   // Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  
15  package org.eclipse.jetty.plus.security;
16  
17  import java.sql.Connection;
18  import java.sql.DatabaseMetaData;
19  import java.sql.PreparedStatement;
20  import java.sql.ResultSet;
21  import java.sql.SQLException;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import javax.naming.InitialContext;
26  import javax.naming.NameNotFoundException;
27  import javax.naming.NamingException;
28  import javax.sql.DataSource;
29  
30  import org.eclipse.jetty.http.security.Password;
31  import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
32  import org.eclipse.jetty.security.IdentityService;
33  import org.eclipse.jetty.security.MappedLoginService;
34  import org.eclipse.jetty.server.Server;
35  import org.eclipse.jetty.server.UserIdentity;
36  import org.eclipse.jetty.util.log.Log;
37  
38  
39  /**
40   *
41   * //TODO JASPI cf JDBCLoginService
42   * DataSourceUserRealm
43   *
44   * Obtain user/password/role information from a database
45   * via jndi DataSource.
46   */
47  public class DataSourceLoginService extends MappedLoginService
48  {
49      private String _jndiName = "javax.sql.DataSource/default";
50      private DataSource _datasource;
51      private Server _server;
52      private String _userTableName = "users";
53      private String _userTableKey = "id";
54      private String _userTableUserField = "username";
55      private String _userTablePasswordField = "pwd";
56      private String _roleTableName = "roles";
57      private String _roleTableKey = "id";
58      private String _roleTableRoleField = "role";
59      private String _userRoleTableName = "user_roles";
60      private String _userRoleTableUserKey = "user_id";
61      private String _userRoleTableRoleKey = "role_id";
62      private int _cacheMs = 30000;
63      private long _lastHashPurge = 0;
64      private String _userSql;
65      private String _roleSql;
66      private boolean _createTables = false;
67  
68      /* ------------------------------------------------------------ */
69      public DataSourceLoginService()
70      {
71      }
72      
73      /* ------------------------------------------------------------ */
74      public DataSourceLoginService(String name)
75      {
76          setName(name);
77      }
78      
79      /* ------------------------------------------------------------ */
80      public DataSourceLoginService(String name, IdentityService identityService)
81      {
82          setName(name);
83          setIdentityService(identityService);
84      }
85  
86      /* ------------------------------------------------------------ */
87      public void setJndiName (String jndi)
88      {
89          _jndiName = jndi;
90      }
91  
92      /* ------------------------------------------------------------ */
93      public String getJndiName ()
94      {
95          return _jndiName;
96      }
97  
98      /* ------------------------------------------------------------ */
99      public void setServer (Server server)
100     {
101         _server=server;
102     }
103 
104     /* ------------------------------------------------------------ */
105     public Server getServer()
106     {
107         return _server;
108     }
109 
110     /* ------------------------------------------------------------ */
111     public void setCreateTables(boolean createTables)
112     {
113         _createTables = createTables;
114     }
115 
116     /* ------------------------------------------------------------ */
117     public boolean getCreateTables()
118     {
119         return _createTables;
120     }
121 
122     /* ------------------------------------------------------------ */
123     public void setUserTableName (String name)
124     {
125         _userTableName=name;
126     }
127 
128     /* ------------------------------------------------------------ */
129     public String getUserTableName()
130     {
131         return _userTableName;
132     }
133 
134     /* ------------------------------------------------------------ */
135     public String getUserTableKey()
136     {
137         return _userTableKey;
138     }
139 
140 
141     /* ------------------------------------------------------------ */
142     public void setUserTableKey(String tableKey)
143     {
144         _userTableKey = tableKey;
145     }
146 
147 
148     /* ------------------------------------------------------------ */
149     public String getUserTableUserField()
150     {
151         return _userTableUserField;
152     }
153 
154 
155     /* ------------------------------------------------------------ */
156     public void setUserTableUserField(String tableUserField)
157     {
158         _userTableUserField = tableUserField;
159     }
160 
161 
162     /* ------------------------------------------------------------ */
163     public String getUserTablePasswordField()
164     {
165         return _userTablePasswordField;
166     }
167 
168 
169     /* ------------------------------------------------------------ */
170     public void setUserTablePasswordField(String tablePasswordField)
171     {
172         _userTablePasswordField = tablePasswordField;
173     }
174 
175 
176     /* ------------------------------------------------------------ */
177     public String getRoleTableName()
178     {
179         return _roleTableName;
180     }
181 
182 
183     /* ------------------------------------------------------------ */
184     public void setRoleTableName(String tableName)
185     {
186         _roleTableName = tableName;
187     }
188 
189 
190     /* ------------------------------------------------------------ */
191     public String getRoleTableKey()
192     {
193         return _roleTableKey;
194     }
195 
196 
197     /* ------------------------------------------------------------ */
198     public void setRoleTableKey(String tableKey)
199     {
200         _roleTableKey = tableKey;
201     }
202 
203 
204     /* ------------------------------------------------------------ */
205     public String getRoleTableRoleField()
206     {
207         return _roleTableRoleField;
208     }
209 
210 
211     /* ------------------------------------------------------------ */
212     public void setRoleTableRoleField(String tableRoleField)
213     {
214         _roleTableRoleField = tableRoleField;
215     }
216 
217 
218     /* ------------------------------------------------------------ */
219     public String getUserRoleTableName()
220     {
221         return _userRoleTableName;
222     }
223 
224 
225     /* ------------------------------------------------------------ */
226     public void setUserRoleTableName(String roleTableName)
227     {
228         _userRoleTableName = roleTableName;
229     }
230 
231 
232     /* ------------------------------------------------------------ */
233     public String getUserRoleTableUserKey()
234     {
235         return _userRoleTableUserKey;
236     }
237 
238 
239     /* ------------------------------------------------------------ */
240     public void setUserRoleTableUserKey(String roleTableUserKey)
241     {
242         _userRoleTableUserKey = roleTableUserKey;
243     }
244 
245 
246     /* ------------------------------------------------------------ */
247     public String getUserRoleTableRoleKey()
248     {
249         return _userRoleTableRoleKey;
250     }
251 
252 
253     /* ------------------------------------------------------------ */
254     public void setUserRoleTableRoleKey(String roleTableRoleKey)
255     {
256         _userRoleTableRoleKey = roleTableRoleKey;
257     }
258 
259     /* ------------------------------------------------------------ */
260     public void setCacheMs (int ms)
261     {
262         _cacheMs=ms;
263     }
264 
265     /* ------------------------------------------------------------ */
266     public int getCacheMs ()
267     {
268         return _cacheMs;
269     }
270 
271     /* ------------------------------------------------------------ */
272     @Override
273     protected void loadUsers()
274     {
275     }
276 
277     /* ------------------------------------------------------------ */
278     /** Load user's info from database.
279      * 
280      * @param userName
281      */
282     @Override
283     protected UserIdentity loadUser (String userName)
284     {
285         Connection connection = null;
286         try
287         {        
288             initDb();
289             connection = getConnection();
290             
291             PreparedStatement statement = connection.prepareStatement(_userSql);
292             statement.setObject(1, userName);
293             ResultSet rs = statement.executeQuery();
294     
295             if (rs.next())
296             {
297                 int key = rs.getInt(_userTableKey);
298                 String credentials = rs.getString(_userTablePasswordField); 
299                 statement.close();
300                 
301                 statement = connection.prepareStatement(_roleSql);
302                 statement.setInt(1, key);
303                 rs = statement.executeQuery();
304                 List<String> roles = new ArrayList<String>();
305                 while (rs.next())
306                     roles.add(rs.getString(_roleTableRoleField));    
307                 statement.close(); 
308                 return putUser(userName,new Password(credentials), roles.toArray(new String[roles.size()]));
309             }
310         }
311         catch (NamingException e)
312         {
313             Log.warn("No datasource for "+_jndiName, e);
314         }
315         catch (SQLException e)
316         {
317             Log.warn("Problem loading user info for "+userName, e);
318         }
319         finally
320         {
321             if (connection != null)
322             {
323                 try
324                 {
325                     connection.close();
326                 }
327                 catch (SQLException x)
328                 {
329                     Log.warn("Problem closing connection", x);
330                 }
331                 finally
332                 {
333                     connection = null;
334                 }
335             }
336         }
337         return null;
338     }
339    
340     /* ------------------------------------------------------------ */
341     /**
342      * Lookup the datasource for the jndiName and formulate the
343      * necessary sql query strings based on the configured table
344      * and column names.
345      * 
346      * @throws NamingException
347      */
348     public void initDb() throws NamingException, SQLException
349     {
350         if (_datasource != null)
351             return;
352         
353         InitialContext ic = new InitialContext();
354         
355         //TODO webapp scope?
356         
357         //try finding the datasource in the Server scope
358         if (_server != null)
359         {
360             try
361             {
362                 _datasource = (DataSource)NamingEntryUtil.lookup(_server, _jndiName);
363             }
364             catch (NameNotFoundException e)
365             {
366                 //next try the jvm scope
367             }
368         }
369         
370 
371         //try finding the datasource in the jvm scope
372         if (_datasource==null)
373         {
374             _datasource = (DataSource)NamingEntryUtil.lookup(null, _jndiName);
375         }
376 
377         // set up the select statements based on the table and column names configured
378         _userSql = "select " + _userTableKey + "," + _userTablePasswordField 
379                   + " from " + _userTableName 
380                   + " where "+ _userTableUserField + " = ?";
381         
382         _roleSql = "select r." + _roleTableRoleField
383                   + " from " + _roleTableName + " r, " + _userRoleTableName 
384                   + " u where u."+ _userRoleTableUserKey + " = ?"
385                   + " and r." + _roleTableKey + " = u." + _userRoleTableRoleKey;
386         
387         prepareTables();
388     }
389     
390     
391     
392     private void prepareTables()
393     throws NamingException, SQLException
394     {
395         Connection connection = null;
396         boolean autocommit = true; 
397         
398         if (_createTables)
399         {
400             try
401             {
402                 connection = getConnection();
403                 autocommit = connection.getAutoCommit();
404                 connection.setAutoCommit(false);
405                 DatabaseMetaData metaData = connection.getMetaData();
406                 
407                 //check if tables exist
408                 String tableName = (metaData.storesLowerCaseIdentifiers()? _userTableName.toLowerCase(): (metaData.storesUpperCaseIdentifiers()?_userTableName.toUpperCase(): _userTableName));
409                 ResultSet result = metaData.getTables(null, null, tableName, null);
410                 if (!result.next())
411                 {                
412                     //user table default
413                     /*
414                      * create table _userTableName (_userTableKey integer,
415                      * _userTableUserField varchar(100) not null unique,
416                      * _userTablePasswordField varchar(20) not null, primary key(_userTableKey));
417                      */
418                     connection.createStatement().executeUpdate("create table "+_userTableName+ "("+_userTableKey+" integer,"+
419                             _userTableUserField+" varchar(100) not null unique,"+
420                             _userTablePasswordField+" varchar(20) not null, primary key("+_userTableKey+"))");
421                     if (Log.isDebugEnabled()) Log.debug("Created table "+_userTableName);
422                 }
423                 
424                 result.close();
425 
426                 tableName = (metaData.storesLowerCaseIdentifiers()? _roleTableName.toLowerCase(): (metaData.storesUpperCaseIdentifiers()?_roleTableName.toUpperCase(): _roleTableName));
427                 result = metaData.getTables(null, null, tableName, null);
428                 if (!result.next())
429                 {
430                     //role table default
431                     /*
432                      * create table _roleTableName (_roleTableKey integer,
433                      * _roleTableRoleField varchar(100) not null unique, primary key(_roleTableKey));
434                      */
435                     String str = "create table "+_roleTableName+" ("+_roleTableKey+" integer, "+
436                     _roleTableRoleField+" varchar(100) not null unique, primary key("+_roleTableKey+"))";
437                     connection.createStatement().executeUpdate(str);
438                     if (Log.isDebugEnabled()) Log.debug("Created table "+_roleTableName);
439                 }
440                 
441                 result.close();
442 
443                 tableName = (metaData.storesLowerCaseIdentifiers()? _userRoleTableName.toLowerCase(): (metaData.storesUpperCaseIdentifiers()?_userRoleTableName.toUpperCase(): _userRoleTableName));
444                 result = metaData.getTables(null, null, tableName, null);
445                 if (!result.next())
446                 {
447                     //user-role table
448                     /*
449                      * create table _userRoleTableName (_userRoleTableUserKey integer,
450                      * _userRoleTableRoleKey integer,
451                      * primary key (_userRoleTableUserKey, _userRoleTableRoleKey));
452                      * 
453                      * create index idx_user_role on _userRoleTableName (_userRoleTableUserKey);
454                      */
455                     connection.createStatement().executeUpdate("create table "+_userRoleTableName+" ("+_userRoleTableUserKey+" integer, "+
456                             _userRoleTableRoleKey+" integer, "+
457                             "primary key ("+_userRoleTableUserKey+", "+_userRoleTableRoleKey+"))");                   
458                     connection.createStatement().executeUpdate("create index indx_user_role on "+_userRoleTableName+"("+_userRoleTableUserKey+")");
459                     if (Log.isDebugEnabled()) Log.debug("Created table "+_userRoleTableName +" and index");
460                 }
461                 
462                 result.close();   
463                 connection.commit();
464             }
465             finally
466             {
467                 if (connection != null)
468                 {
469                     try
470                     {
471                         connection.setAutoCommit(autocommit);
472                         connection.close();
473                     }
474                     catch (SQLException e)
475                     {
476                         if (Log.isDebugEnabled()) Log.debug("Prepare tables", e);
477                     }
478                     finally
479                     {
480                         connection = null;
481                     }
482                 }
483             }
484         }
485         else if (Log.isDebugEnabled())
486         {
487             Log.debug("createTables false");
488         }
489     }
490     
491     
492     private Connection getConnection () 
493     throws NamingException, SQLException
494     {
495         initDb();
496         return _datasource.getConnection();
497     }
498 
499 }