KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > server > security > JdbcAuthenticator


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.server.security;
30
31 import com.caucho.config.types.Period;
32 import com.caucho.log.Log;
33 import com.caucho.server.connection.CauchoRequest;
34 import com.caucho.server.dispatch.ServletConfigException;
35 import com.caucho.server.session.SessionManager;
36 import com.caucho.server.webapp.Application;
37 import com.caucho.util.CharBuffer;
38 import com.caucho.util.L10N;
39
40 import javax.annotation.PostConstruct;
41 import javax.naming.Context JavaDoc;
42 import javax.naming.InitialContext JavaDoc;
43 import javax.servlet.ServletContext JavaDoc;
44 import javax.servlet.ServletException JavaDoc;
45 import javax.servlet.http.Cookie JavaDoc;
46 import javax.servlet.http.HttpServletRequest JavaDoc;
47 import javax.servlet.http.HttpServletResponse JavaDoc;
48 import javax.sql.DataSource JavaDoc;
49 import java.security.Principal JavaDoc;
50 import java.sql.Connection JavaDoc;
51 import java.sql.PreparedStatement JavaDoc;
52 import java.sql.ResultSet JavaDoc;
53 import java.sql.SQLException JavaDoc;
54 import java.util.logging.Level JavaDoc;
55 import java.util.logging.Logger JavaDoc;
56
57 /**
58  * An authenticator using JDBC.
59  *
60  * <p/>The default table schema looks something like:
61  * <pre>
62  * CREATE TABLE LOGIN (
63  * username VARCHAR(250) NOT NULL,
64  * password VARCHAR(250),
65  * cookie VARCHAR(250),
66  * PRIMARY KEY (username)
67  * );
68  * </pre>
69  */

70
71 public class JdbcAuthenticator extends AbstractAuthenticator {
72   private static final Logger JavaDoc log = Log.open(JdbcAuthenticator.class);
73   private static final L10N L = new L10N(JdbcAuthenticator.class);
74   
75   private DataSource JavaDoc _dataSource;
76
77   private String JavaDoc _passwordQuery = "SELECT password FROM LOGIN WHERE username=?";
78
79   private String JavaDoc _cookieUpdate = "UPDATE LOGIN SET cookie=? WHERE username=?";
80   
81   private String JavaDoc _cookieQuery = "SELECT username FROM LOGIN where cookie=?";
82   private boolean _cookieLogout;
83   
84   private String JavaDoc _roleQuery;
85   
86   protected boolean _useCookie;
87   protected int _cookieVersion = -1;
88   protected String JavaDoc _cookieDomain;
89   protected long _cookieMaxAge = 365L * 24L * 3600L * 1000L;
90   
91   private CharBuffer _cb = new CharBuffer();
92     
93   /**
94    * Gets the database
95    */

96   public DataSource JavaDoc getDataSource()
97   {
98     return _dataSource;
99   }
100
101   /**
102    * Sets the database pool name.
103    */

104   public void setDataSource(DataSource JavaDoc dataSource)
105   {
106     _dataSource = dataSource;
107   }
108
109   /**
110    * Gets the password query.
111    *
112    * <p>Example:
113    * <pre><code>
114    * SELECT password FROM LOGIN WHERE username=?
115    * </code></pre>
116    */

117   public String JavaDoc getPasswordQuery()
118   {
119     return _passwordQuery;
120   }
121
122   /**
123    * Sets the password query.
124    */

125   public void setPasswordQuery(String JavaDoc query)
126   {
127     _passwordQuery = query;
128   }
129
130   /**
131    * Gets the cookie auth query.
132    */

133   public String JavaDoc getCookieAuthQuery()
134   {
135     return _cookieQuery;
136   }
137
138   /**
139    * Sets the cookie auth query.
140    */

141   public void setCookieAuthQuery(String JavaDoc query)
142   {
143     _cookieQuery = query;
144   }
145
146   /**
147    * Gets the cookie update query.
148    */

149   public String JavaDoc getCookieAuthUpdate()
150   {
151     return _cookieUpdate;
152   }
153
154   /**
155    * Sets the cookie update query.
156    */

157   public void setCookieAuthUpdate(String JavaDoc query)
158   {
159     _cookieUpdate = query;
160   }
161
162   /**
163    * If true, the cookie is removed on logout
164    */

165   public void setCookieLogout(boolean cookieLogout)
166   {
167     _cookieLogout = cookieLogout;
168   }
169   
170   /**
171    * Gets the role query.
172    */

173   public String JavaDoc getRoleQuery()
174   {
175     return _roleQuery;
176   }
177
178   /**
179    * Sets the role query.
180    */

181   public void setRoleQuery(String JavaDoc query)
182   {
183     _roleQuery = query;
184   }
185
186   /**
187    * Returns true if Resin should generate the resinauth cookie by default.
188    */

189   public boolean getUseCookie()
190   {
191     return _useCookie;
192   }
193
194   /**
195    * Set true if Resin should generate the resinauth cookie by default.
196    */

197   public void setUseCookie(boolean useCookie)
198   {
199     _useCookie = useCookie;
200   }
201
202   /**
203    * Returns the version for a login cookie.
204    */

205   public int getCookieVersion()
206   {
207     return _cookieVersion;
208   }
209
210   /**
211    * Sets the version for a login cookie.
212    */

213   public void setCookieVersion(int version)
214   {
215     _cookieVersion = version;
216   }
217
218   /**
219    * Returns the domain for a login cookie.
220    */

221   public String JavaDoc getCookieDomain()
222   {
223     return _cookieDomain;
224   }
225
226   /**
227    * Sets the domain for a login cookie.
228    */

229   public void setCookieDomain(String JavaDoc cookieDomain)
230   {
231     _cookieDomain = cookieDomain;
232   }
233
234   /**
235    * Returns the max-age for a login cookie.
236    */

237   public long getCookieMaxAge()
238   {
239     return _cookieMaxAge;
240   }
241
242   /**
243    * Sets the max age for a login cookie.
244    */

245   public void setCookieMaxAge(Period cookieMaxAge)
246   {
247     _cookieMaxAge = cookieMaxAge.getPeriod();
248   }
249
250   /**
251    * Initialize the authenticator.
252    */

253   @PostConstruct
254   public void init()
255     throws ServletException JavaDoc
256   {
257     super.init();
258
259     if (_dataSource == null) {
260       try {
261         Context JavaDoc ic = new InitialContext JavaDoc();
262
263         _dataSource = (DataSource JavaDoc) ic.lookup("java:comp/env/jdbc/db-pool");
264       } catch (Exception JavaDoc e) {
265         log.log(Level.FINE, e.toString(), e);
266       }
267
268       if (_dataSource == null)
269         throw new ServletConfigException(L.l("Unknown database pool jdbc/db-pool."));
270     }
271
272     int i = _passwordQuery.indexOf('?');
273     if (i < 0)
274       throw new ServletConfigException(L.l("`{0}' expects a parameter",
275                                      "password-query"));
276
277     if (_cookieQuery != null) {
278       i = _cookieQuery.indexOf('?');
279       if (i < 0)
280         throw new ServletConfigException(L.l("`{0}' expects a parameter",
281                                        "cookie-auth-query"));
282     }
283     
284     if (_cookieUpdate != null) {
285       i = _cookieUpdate.indexOf('?');
286       if (i < 0)
287         throw new ServletConfigException(L.l("`{0}' expects two parameters",
288                                        "cookie-auth-update"));
289       int j = _cookieUpdate.indexOf('?', i + 1);
290       if (j < 0)
291         throw new ServletConfigException(L.l("`{0}' expects two parameters",
292                                        "cookie-auth-update"));
293     }
294
295     if ((_cookieUpdate != null) && (_cookieQuery == null))
296       throw new ServletConfigException(L.l("<{0}> expects `{1}'",
297                                      "cookie-auth-update", "cookie-query"));
298     
299     if (_roleQuery != null) {
300       i = _roleQuery.indexOf('?');
301       if (i < 0)
302         throw new ServletConfigException(L.l("`{0}' expects a parameter",
303                                              "role-query"));
304     }
305   }
306
307   /**
308    * Authenticates the user given the request.
309    *
310    * @param username the user name for the login
311    * @param password the password for the login
312    *
313    * @return the authenticated user or null for a failure
314    */

315   public Principal JavaDoc loginImpl(HttpServletRequest JavaDoc request,
316                              HttpServletResponse JavaDoc response,
317                              ServletContext JavaDoc application,
318                              String JavaDoc username, String JavaDoc password)
319     throws ServletException JavaDoc
320   {
321     Principal JavaDoc user = loginImpl(username, password);
322
323     if (_cookieQuery == null || user == null)
324       return user;
325
326     String JavaDoc cookieAuth = (String JavaDoc) request.getAttribute("j_use_cookie_auth");
327     if (cookieAuth == null)
328       cookieAuth = (String JavaDoc) request.getParameter("j_use_cookie_auth");
329
330     if ("true".equals(cookieAuth) || "on".equals(cookieAuth) ||
331     _useCookie && cookieAuth == null)
332       addAuthCookie(request, response, application, user);
333
334     return user;
335   }
336   
337    /**
338     * Adds a cookie to store authentication.
339     */

340    protected void addAuthCookie(HttpServletRequest JavaDoc request,
341                                 HttpServletResponse JavaDoc response,
342                                 ServletContext JavaDoc application,
343                                 Principal JavaDoc user)
344      
345    {
346      Application app = (Application) application;
347      SessionManager sm = app.getSessionManager();
348      String JavaDoc id;
349        
350      id = sm.createSessionId(request);
351        
352      if (updateCookie(user, id)) {
353        Cookie JavaDoc cookie = new Cookie JavaDoc("resinauthid", id);
354        cookie.setPath("/");
355
356        if (getCookieVersion() >= 0)
357          cookie.setVersion(getCookieVersion());
358        else
359          cookie.setVersion(sm.getCookieVersion());
360
361        if (_cookieDomain != null)
362          cookie.setDomain(_cookieDomain);
363        else if (getCookieDomain() != null)
364          cookie.setDomain(getCookieDomain());
365        else
366          cookie.setDomain(sm.getCookieDomain());
367  
368        if (_cookieMaxAge > 0)
369          cookie.setMaxAge((int) (_cookieMaxAge / 1000L));
370
371        response.addCookie(cookie);
372      }
373    }
374
375   /**
376    * Authenticates the user given the request.
377    *
378    * @param username the user name for the login
379    * @param password the password for the login
380    *
381    * @return the authenticated user or null for a failure
382    */

383   public Principal JavaDoc loginImpl(String JavaDoc username, String JavaDoc password)
384     throws ServletException JavaDoc
385   {
386     Connection JavaDoc conn = null;
387     PreparedStatement JavaDoc stmt = null;
388     ResultSet JavaDoc rs = null;
389
390     try {
391       conn = _dataSource.getConnection();
392       stmt = conn.prepareStatement(_passwordQuery);
393
394       stmt.setString(1, username);
395
396       rs = stmt.executeQuery();
397       if (! rs.next()) {
398         if (log.isLoggable(Level.FINE))
399           log.fine("no such user:" + username);
400         
401         return null;
402       }
403       
404       String JavaDoc dbPassword = rs.getString(1);
405
406       if (dbPassword != null && dbPassword.equals(password)) {
407         return new CachingPrincipal(username);
408       }
409       else {
410         if (log.isLoggable(Level.FINE))
411           log.fine("mismatched password:" + username);
412         
413         return null;
414       }
415     } catch (Exception JavaDoc e) {
416       e.printStackTrace();
417       throw new ServletException JavaDoc(e);
418     } finally {
419       try {
420         if (rs != null)
421           rs.close();
422       } catch (SQLException JavaDoc e) {
423       }
424       try {
425         if (stmt != null)
426           stmt.close();
427       } catch (SQLException JavaDoc e) {
428       }
429       try {
430         if (conn != null)
431           conn.close();
432       } catch (SQLException JavaDoc e) {
433       }
434     }
435   }
436   
437   /**
438    * Returns the password for authenticators too lazy to calculate the
439    * digest.
440    */

441   protected String JavaDoc getDigestPassword(HttpServletRequest JavaDoc request,
442                                      HttpServletResponse JavaDoc response,
443                                      ServletContext JavaDoc application,
444                                      String JavaDoc username, String JavaDoc realm)
445     throws ServletException JavaDoc
446   {
447     Connection JavaDoc conn = null;
448     PreparedStatement JavaDoc stmt = null;
449     ResultSet JavaDoc rs = null;
450       
451     try {
452       conn = _dataSource.getConnection();
453       stmt = conn.prepareStatement(_passwordQuery);
454
455       stmt.setString(1, username);
456
457       rs = stmt.executeQuery();
458       if (! rs.next()) {
459         if (log.isLoggable(Level.FINE))
460           log.fine("no such user:" + username);
461         
462         return null;
463       }
464       
465       String JavaDoc dbPassword = rs.getString(1);
466
467       return dbPassword;
468     } catch (Exception JavaDoc e) {
469       throw new ServletException JavaDoc(e);
470     } finally {
471       try {
472         if (rs != null)
473           rs.close();
474       } catch (SQLException JavaDoc e) {
475       }
476       try {
477         if (stmt != null)
478           stmt.close();
479       } catch (SQLException JavaDoc e) {
480       }
481       try {
482         if (conn != null)
483           conn.close();
484       } catch (SQLException JavaDoc e) {
485       }
486     }
487   }
488
489   protected Principal JavaDoc getUserPrincipalImpl(HttpServletRequest JavaDoc request,
490                                            ServletContext JavaDoc application)
491     throws ServletException JavaDoc
492   {
493     if (_cookieQuery == null)
494       return null;
495     
496     Cookie JavaDoc cookie = null;
497     
498     if (request instanceof CauchoRequest)
499       cookie = ((CauchoRequest) request).getCookie("resinauthid");
500     else {
501       Cookie JavaDoc []cookies = request.getCookies();
502       for (int i = 0; cookies != null && i < cookies.length; i++) {
503         if (cookies[i].getName().equals("resinauthid")) {
504           cookie = cookies[i];
505           break;
506         }
507       }
508     }
509
510     if (cookie == null)
511       return null;
512
513     return authenticateCookie(cookie.getValue());
514   }
515
516   /**
517    * Authenticate based on a cookie.
518    *
519    * @param cookieValue the value of the resin-auth cookie
520    *
521    * @return the user for the cookie.
522    */

523   public Principal JavaDoc authenticateCookie(String JavaDoc cookieValue)
524     throws ServletException JavaDoc
525   {
526     if (_cookieQuery == null)
527       return null;
528
529     Connection JavaDoc conn = null;
530     PreparedStatement JavaDoc stmt = null;
531     ResultSet JavaDoc rs = null;
532     
533     try {
534       conn = _dataSource.getConnection();
535       stmt = conn.prepareStatement(_cookieQuery);
536       stmt.setString(1, cookieValue);
537
538       rs = stmt.executeQuery();
539       if (! rs.next())
540         return null;
541       
542       String JavaDoc user = rs.getString(1);
543
544       if (user != null)
545         return new CachingPrincipal(user);
546       else
547         return null;
548     } catch (Exception JavaDoc e) {
549       throw new ServletException JavaDoc(e);
550     } finally {
551       try {
552         if (rs != null)
553           rs.close();
554       } catch (SQLException JavaDoc e) {
555       }
556       try {
557         if (stmt != null)
558           stmt.close();
559       } catch (SQLException JavaDoc e) {
560       }
561       try {
562         if (conn != null)
563           conn.close();
564       } catch (SQLException JavaDoc e) {
565       }
566     }
567   }
568
569   /**
570    * Associates a user with a persistent cookie.
571    *
572    * @param user the user for the cookie
573    * @param cookieValue the value of the resin-auth cookie
574    *
575    * @return true if the cookie value is valid, i.e. it's unique
576    */

577   public boolean updateCookie(Principal JavaDoc user, String JavaDoc cookieValue)
578   {
579     if (_cookieUpdate == null || user == null || cookieValue == null)
580       return true;
581     
582     Connection JavaDoc conn = null;
583     PreparedStatement JavaDoc stmt = null;
584     
585     try {
586       conn = _dataSource.getConnection();
587       stmt = conn.prepareStatement(_cookieUpdate);
588       stmt.setString(1, cookieValue);
589       stmt.setString(2, user.getName());
590
591       stmt.executeUpdate();
592     } catch (Exception JavaDoc e) {
593       log.log(Level.FINE, e.toString(), e);
594     } finally {
595       try {
596         if (stmt != null)
597           stmt.close();
598       } catch (SQLException JavaDoc e) {
599       }
600       try {
601         if (conn != null)
602           conn.close();
603       } catch (SQLException JavaDoc e) {
604       }
605     }
606
607     return true;
608   }
609
610   public boolean isUserInRole(HttpServletRequest JavaDoc request,
611                               HttpServletResponse JavaDoc response,
612                               ServletContext JavaDoc application,
613                               Principal JavaDoc principal, String JavaDoc role)
614   {
615     if (_roleQuery == null)
616       return principal != null && "user".equals(role);
617     else if (principal == null || role == null)
618       return false;
619
620     CachingPrincipal cachingPrincipal = null;
621
622     if (principal instanceof CachingPrincipal) {
623       cachingPrincipal = (CachingPrincipal) principal;
624
625       Boolean JavaDoc isInRole = cachingPrincipal.isInRole(role);
626
627       if (isInRole != null)
628     return isInRole.equals(Boolean.TRUE);
629     }
630
631     Connection JavaDoc conn = null;
632     PreparedStatement JavaDoc stmt = null;
633     ResultSet JavaDoc rs = null;
634       
635     try {
636       conn = _dataSource.getConnection();
637       stmt = conn.prepareStatement(_roleQuery);
638       stmt.setString(1, principal.getName());
639
640       boolean inRole = false;
641       
642       rs = stmt.executeQuery();
643       while (rs.next()) {
644         String JavaDoc dbRole = rs.getString(1);
645
646     if (cachingPrincipal != null)
647       cachingPrincipal.addRole(dbRole);
648     
649         if (role.equals(dbRole))
650       inRole = true;
651       }
652       
653       return inRole;
654     } catch (Exception JavaDoc e) {
655       log.log(Level.FINE, e.toString(), e);
656       
657       return false;
658     } finally {
659       try {
660         if (rs != null)
661           rs.close();
662       } catch (SQLException JavaDoc e) {
663       }
664       try {
665         if (stmt != null)
666           stmt.close();
667       } catch (SQLException JavaDoc e) {
668       }
669       try {
670         if (conn != null)
671           conn.close();
672       } catch (SQLException JavaDoc e) {
673       }
674     }
675   }
676
677   /**
678    * Logs the user out from the session.
679    *
680    * @param request the servlet request
681    */

682   public void logout(HttpServletRequest JavaDoc request,
683                      HttpServletResponse JavaDoc response,
684                      ServletContext JavaDoc application,
685                      Principal JavaDoc user)
686     throws ServletException JavaDoc
687   {
688     super.logout(request, response, application, user);
689
690     // null the cookie
691
if (_cookieLogout)
692       updateCookie(user, "");
693   }
694 }
695
Popular Tags