]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/security/JDBCLoginService.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / security / JDBCLoginService.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.security;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.sql.Connection;
24 import java.sql.DriverManager;
25 import java.sql.PreparedStatement;
26 import java.sql.ResultSet;
27 import java.sql.SQLException;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Properties;
31
32 import org.eclipse.jetty.server.UserIdentity;
33 import org.eclipse.jetty.util.Loader;
34 import org.eclipse.jetty.util.log.Log;
35 import org.eclipse.jetty.util.log.Logger;
36 import org.eclipse.jetty.util.resource.Resource;
37 import org.eclipse.jetty.util.security.Credential;
38
39 /* ------------------------------------------------------------ */
40 /**
41  * HashMapped User Realm with JDBC as data source. 
42  * The login() method checks the inherited Map for the user. If the user is not
43  * found, it will fetch details from the database and populate the inherited
44  * Map. It then calls the superclass login() method to perform the actual
45  * authentication. Periodically (controlled by configuration parameter),
46  * internal hashes are cleared. Caching can be disabled by setting cache refresh
47  * interval to zero. Uses one database connection that is initialized at
48  * startup. Reconnect on failures. authenticate() is 'synchronized'.
49  * 
50  * An example properties file for configuration is in
51  * $JETTY_HOME/etc/jdbcRealm.properties
52  * 
53  * @version $Id: JDBCLoginService.java 4792 2009-03-18 21:55:52Z gregw $
54  * 
55  * 
56  * 
57  * 
58  */
59
60 public class JDBCLoginService extends MappedLoginService
61 {
62     private static final Logger LOG = Log.getLogger(JDBCLoginService.class);
63
64     protected String _config;
65     protected String _jdbcDriver;
66     protected String _url;
67     protected String _userName;
68     protected String _password;
69     protected String _userTableKey;
70     protected String _userTablePasswordField;
71     protected String _roleTableRoleField;
72     protected int _cacheTime;
73     protected long _lastHashPurge;
74     protected Connection _con;
75     protected String _userSql;
76     protected String _roleSql;
77
78
79     /* ------------------------------------------------------------ */
80     public JDBCLoginService()
81         throws IOException
82     {
83     }
84     
85     /* ------------------------------------------------------------ */
86     public JDBCLoginService(String name)
87         throws IOException
88     {
89         setName(name);
90     }
91     
92     /* ------------------------------------------------------------ */
93     public JDBCLoginService(String name, String config)
94         throws IOException
95     {
96         setName(name);
97         setConfig(config);
98     }
99     
100     /* ------------------------------------------------------------ */
101     public JDBCLoginService(String name, IdentityService identityService, String config)
102         throws IOException
103     {
104         setName(name);
105         setIdentityService(identityService);
106         setConfig(config);
107     }
108
109
110     /* ------------------------------------------------------------ */
111     /**
112      * @see org.eclipse.jetty.security.MappedLoginService#doStart()
113      */
114     @Override
115     protected void doStart() throws Exception
116     {
117         Properties properties = new Properties();
118         Resource resource = Resource.newResource(_config);
119         try (InputStream in = resource.getInputStream())
120         {
121             properties.load(in);
122         }
123         _jdbcDriver = properties.getProperty("jdbcdriver");
124         _url = properties.getProperty("url");
125         _userName = properties.getProperty("username");
126         _password = properties.getProperty("password");
127         String _userTable = properties.getProperty("usertable");
128         _userTableKey = properties.getProperty("usertablekey");
129         String _userTableUserField = properties.getProperty("usertableuserfield");
130         _userTablePasswordField = properties.getProperty("usertablepasswordfield");
131         String _roleTable = properties.getProperty("roletable");
132         String _roleTableKey = properties.getProperty("roletablekey");
133         _roleTableRoleField = properties.getProperty("roletablerolefield");
134         String _userRoleTable = properties.getProperty("userroletable");
135         String _userRoleTableUserKey = properties.getProperty("userroletableuserkey");
136         String _userRoleTableRoleKey = properties.getProperty("userroletablerolekey");
137         _cacheTime = new Integer(properties.getProperty("cachetime"));
138
139         if (_jdbcDriver == null || _jdbcDriver.equals("")
140             || _url == null
141             || _url.equals("")
142             || _userName == null
143             || _userName.equals("")
144             || _password == null
145             || _cacheTime < 0)
146         {
147             LOG.warn("UserRealm " + getName() + " has not been properly configured");
148         }
149         _cacheTime *= 1000;
150         _lastHashPurge = 0;
151         _userSql = "select " + _userTableKey + "," + _userTablePasswordField + " from " + _userTable + " where " + _userTableUserField + " = ?";
152         _roleSql = "select r." + _roleTableRoleField
153                    + " from "
154                    + _roleTable
155                    + " r, "
156                    + _userRoleTable
157                    + " u where u."
158                    + _userRoleTableUserKey
159                    + " = ?"
160                    + " and r."
161                    + _roleTableKey
162                    + " = u."
163                    + _userRoleTableRoleKey;
164         
165         Loader.loadClass(this.getClass(), _jdbcDriver).newInstance();
166         super.doStart();
167     }
168
169
170     /* ------------------------------------------------------------ */
171     public String getConfig()
172     {
173         return _config;
174     }
175
176     /* ------------------------------------------------------------ */
177     /**
178      * Load JDBC connection configuration from properties file.
179      * 
180      * @param config Filename or url of user properties file.
181      */
182     public void setConfig(String config)
183     {        
184         if (isRunning())
185             throw new IllegalStateException("Running");
186         _config=config;
187     }
188
189     /* ------------------------------------------------------------ */
190     /**
191      * (re)Connect to database with parameters setup by loadConfig()
192      */
193     public void connectDatabase()
194     {
195         try
196         {
197             Class.forName(_jdbcDriver);
198             _con = DriverManager.getConnection(_url, _userName, _password);
199         }
200         catch (SQLException e)
201         {
202             LOG.warn("UserRealm " + getName() + " could not connect to database; will try later", e);
203         }
204         catch (ClassNotFoundException e)
205         {
206             LOG.warn("UserRealm " + getName() + " could not connect to database; will try later", e);
207         }
208     }
209
210     /* ------------------------------------------------------------ */
211     @Override
212     public UserIdentity login(String username, Object credentials)
213     {
214         long now = System.currentTimeMillis();
215         if (now - _lastHashPurge > _cacheTime || _cacheTime == 0)
216         {
217             _users.clear();
218             _lastHashPurge = now;
219             closeConnection();
220         }
221         
222         return super.login(username,credentials);
223     }
224
225     /* ------------------------------------------------------------ */
226     @Override
227     protected void loadUsers()
228     {   
229     }
230     
231     /* ------------------------------------------------------------ */
232     @Override
233     protected UserIdentity loadUser(String username)
234     {
235         try
236         {
237             if (null == _con) 
238                 connectDatabase();
239
240             if (null == _con) 
241                 throw new SQLException("Can't connect to database");
242
243             try (PreparedStatement stat1 = _con.prepareStatement(_userSql))
244             {
245                 stat1.setObject(1, username);
246                 try (ResultSet rs1 = stat1.executeQuery())
247                 {
248                     if (rs1.next())
249                     {
250                         int key = rs1.getInt(_userTableKey);
251                         String credentials = rs1.getString(_userTablePasswordField);
252                         List<String> roles = new ArrayList<String>();
253
254                         try (PreparedStatement stat2 = _con.prepareStatement(_roleSql))
255                         {
256                             stat2.setInt(1, key);
257                             try (ResultSet rs2 = stat2.executeQuery())
258                             {
259                                 while (rs2.next())
260                                     roles.add(rs2.getString(_roleTableRoleField));
261                             }
262                         }
263                         return putUser(username, credentials, roles.toArray(new String[roles.size()]));
264                     }
265                 }
266             }
267         }
268         catch (SQLException e)
269         {
270             LOG.warn("UserRealm " + getName() + " could not load user information from database", e);
271             closeConnection();
272         }
273         return null;
274     }
275     
276     /* ------------------------------------------------------------ */
277     protected UserIdentity putUser (String username, String credentials, String[] roles)
278     {
279         return putUser(username, Credential.getCredential(credentials),roles);
280     }
281     
282
283     /**
284      * Close an existing connection
285      */
286     private void closeConnection ()
287     {
288         if (_con != null)
289         {
290             if (LOG.isDebugEnabled()) LOG.debug("Closing db connection for JDBCUserRealm");
291             try { _con.close(); }catch (Exception e) {LOG.ignore(e);}
292         }
293         _con = null;
294     }
295
296 }