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 String _userSql;
64      private String _roleSql;
65      private boolean _createTables = false;
66  
67      /* ------------------------------------------------------------ */
68      public DataSourceLoginService()
69      {
70      }
71      
72      /* ------------------------------------------------------------ */
73      public DataSourceLoginService(String name)
74      {
75          setName(name);
76      }
77      
78      /* ------------------------------------------------------------ */
79      public DataSourceLoginService(String name, IdentityService identityService)
80      {
81          setName(name);
82          setIdentityService(identityService);
83      }
84  
85      /* ------------------------------------------------------------ */
86      public void setJndiName (String jndi)
87      {
88          _jndiName = jndi;
89      }
90  
91      /* ------------------------------------------------------------ */
92      public String getJndiName ()
93      {
94          return _jndiName;
95      }
96  
97      /* ------------------------------------------------------------ */
98      public void setServer (Server server)
99      {
100         _server=server;
101     }
102 
103     /* ------------------------------------------------------------ */
104     public Server getServer()
105     {
106         return _server;
107     }
108 
109     /* ------------------------------------------------------------ */
110     public void setCreateTables(boolean createTables)
111     {
112         _createTables = createTables;
113     }
114 
115     /* ------------------------------------------------------------ */
116     public boolean getCreateTables()
117     {
118         return _createTables;
119     }
120 
121     /* ------------------------------------------------------------ */
122     public void setUserTableName (String name)
123     {
124         _userTableName=name;
125     }
126 
127     /* ------------------------------------------------------------ */
128     public String getUserTableName()
129     {
130         return _userTableName;
131     }
132 
133     /* ------------------------------------------------------------ */
134     public String getUserTableKey()
135     {
136         return _userTableKey;
137     }
138 
139 
140     /* ------------------------------------------------------------ */
141     public void setUserTableKey(String tableKey)
142     {
143         _userTableKey = tableKey;
144     }
145 
146 
147     /* ------------------------------------------------------------ */
148     public String getUserTableUserField()
149     {
150         return _userTableUserField;
151     }
152 
153 
154     /* ------------------------------------------------------------ */
155     public void setUserTableUserField(String tableUserField)
156     {
157         _userTableUserField = tableUserField;
158     }
159 
160 
161     /* ------------------------------------------------------------ */
162     public String getUserTablePasswordField()
163     {
164         return _userTablePasswordField;
165     }
166 
167 
168     /* ------------------------------------------------------------ */
169     public void setUserTablePasswordField(String tablePasswordField)
170     {
171         _userTablePasswordField = tablePasswordField;
172     }
173 
174 
175     /* ------------------------------------------------------------ */
176     public String getRoleTableName()
177     {
178         return _roleTableName;
179     }
180 
181 
182     /* ------------------------------------------------------------ */
183     public void setRoleTableName(String tableName)
184     {
185         _roleTableName = tableName;
186     }
187 
188 
189     /* ------------------------------------------------------------ */
190     public String getRoleTableKey()
191     {
192         return _roleTableKey;
193     }
194 
195 
196     /* ------------------------------------------------------------ */
197     public void setRoleTableKey(String tableKey)
198     {
199         _roleTableKey = tableKey;
200     }
201 
202 
203     /* ------------------------------------------------------------ */
204     public String getRoleTableRoleField()
205     {
206         return _roleTableRoleField;
207     }
208 
209 
210     /* ------------------------------------------------------------ */
211     public void setRoleTableRoleField(String tableRoleField)
212     {
213         _roleTableRoleField = tableRoleField;
214     }
215 
216 
217     /* ------------------------------------------------------------ */
218     public String getUserRoleTableName()
219     {
220         return _userRoleTableName;
221     }
222 
223 
224     /* ------------------------------------------------------------ */
225     public void setUserRoleTableName(String roleTableName)
226     {
227         _userRoleTableName = roleTableName;
228     }
229 
230 
231     /* ------------------------------------------------------------ */
232     public String getUserRoleTableUserKey()
233     {
234         return _userRoleTableUserKey;
235     }
236 
237 
238     /* ------------------------------------------------------------ */
239     public void setUserRoleTableUserKey(String roleTableUserKey)
240     {
241         _userRoleTableUserKey = roleTableUserKey;
242     }
243 
244 
245     /* ------------------------------------------------------------ */
246     public String getUserRoleTableRoleKey()
247     {
248         return _userRoleTableRoleKey;
249     }
250 
251 
252     /* ------------------------------------------------------------ */
253     public void setUserRoleTableRoleKey(String roleTableRoleKey)
254     {
255         _userRoleTableRoleKey = roleTableRoleKey;
256     }
257 
258     /* ------------------------------------------------------------ */
259     public void setCacheMs (int ms)
260     {
261         _cacheMs=ms;
262     }
263 
264     /* ------------------------------------------------------------ */
265     public int getCacheMs ()
266     {
267         return _cacheMs;
268     }
269 
270     /* ------------------------------------------------------------ */
271     @Override
272     protected void loadUsers()
273     {
274     }
275 
276     /* ------------------------------------------------------------ */
277     /** Load user's info from database.
278      * 
279      * @param userName
280      */
281     @Override
282     protected UserIdentity loadUser (String userName)
283     {
284         Connection connection = null;
285         try
286         {        
287             initDb();
288             connection = getConnection();
289             
290             PreparedStatement statement = connection.prepareStatement(_userSql);
291             statement.setObject(1, userName);
292             ResultSet rs = statement.executeQuery();
293     
294             if (rs.next())
295             {
296                 int key = rs.getInt(_userTableKey);
297                 String credentials = rs.getString(_userTablePasswordField); 
298                 statement.close();
299                 
300                 statement = connection.prepareStatement(_roleSql);
301                 statement.setInt(1, key);
302                 rs = statement.executeQuery();
303                 List<String> roles = new ArrayList<String>();
304                 while (rs.next())
305                     roles.add(rs.getString(_roleTableRoleField));    
306                 statement.close(); 
307                 return putUser(userName,new Password(credentials), roles.toArray(new String[roles.size()]));
308             }
309         }
310         catch (NamingException e)
311         {
312             Log.warn("No datasource for "+_jndiName, e);
313         }
314         catch (SQLException e)
315         {
316             Log.warn("Problem loading user info for "+userName, e);
317         }
318         finally
319         {
320             if (connection != null)
321             {
322                 try
323                 {
324                     connection.close();
325                 }
326                 catch (SQLException x)
327                 {
328                     Log.warn("Problem closing connection", x);
329                 }
330                 finally
331                 {
332                     connection = null;
333                 }
334             }
335         }
336         return null;
337     }
338    
339     /* ------------------------------------------------------------ */
340     /**
341      * Lookup the datasource for the jndiName and formulate the
342      * necessary sql query strings based on the configured table
343      * and column names.
344      * 
345      * @throws NamingException
346      */
347     public void initDb() throws NamingException, SQLException
348     {
349         if (_datasource != null)
350             return;
351         
352         @SuppressWarnings("unused")
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 }