001    /*
002     * $Id: JDBCLoginService.java,v 1.6 2005/11/11 23:05:15 rbair Exp $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    package org.jdesktop.swingx.auth;
022    import java.sql.Connection;
023    import java.sql.DriverManager;
024    import java.util.Properties;
025    import java.util.logging.Level;
026    import java.util.logging.Logger;
027    
028    import javax.naming.InitialContext;
029    /**
030     * A login service for connecting to SQL based databases via JDBC
031     *
032     * @author rbair
033     */
034    public class JDBCLoginService extends LoginService {
035        private static final Logger LOG = Logger.getLogger(JDBCLoginService.class
036                .getName());
037        
038        /**
039         * The connection to the database
040         */
041        private Connection conn;
042        /**
043         * If used, defines the JNDI context from which to get a connection to
044         * the data base
045         */
046        private String jndiContext;
047        /**
048         * When using the DriverManager to connect to the database, this specifies
049         * any additional properties to use when connecting.
050         */
051        private Properties properties;
052        
053        /**
054         * Create a new JDBCLoginService and initializes it to connect to a
055         * database using the given params.
056         * @param driver
057         * @param url
058         */
059        public JDBCLoginService(String driver, String url) {
060            super(url);
061            try {
062                Class.forName(driver);
063            } catch (Exception e) {
064                LOG.log(Level.WARNING, "The driver passed to the " +
065                        "JDBCLoginService constructor could not be loaded. " +
066                        "This may be due to the driver not being on the classpath", e);
067            }
068            this.setUrl(url);
069        }
070        
071        /**
072         * Create a new JDBCLoginService and initializes it to connect to a
073         * database using the given params.
074         * @param driver
075         * @param url
076         * @param props
077         */
078        public JDBCLoginService(String driver, String url, Properties props) {
079            super(url);
080            try {
081                Class.forName(driver);
082            } catch (Exception e) {
083                LOG.log(Level.WARNING, "The driver passed to the " +
084                        "JDBCLoginService constructor could not be loaded. " +
085                        "This may be due to the driver not being on the classpath", e);
086            }
087            this.setUrl(url);
088            this.setProperties(props);
089        }
090        
091        /**
092         * Create a new JDBCLoginService and initializes it to connect to a
093         * database using the given params.
094         * @param jndiContext
095         */
096        public JDBCLoginService(String jndiContext) {
097            super(jndiContext);
098            this.jndiContext = jndiContext;
099        }
100        
101        /**
102         * @return the JDBC connection url
103         */
104        public String getUrl() {
105            return getServer();
106        }
107    
108        /**
109         * @param url set the JDBC connection url
110         */
111        public void setUrl(String url) {
112            setServer(url);
113        }
114    
115        /**
116         * @return JDBC connection properties
117         */
118        public Properties getProperties() {
119            return properties;
120        }
121    
122        /**
123         * @param properties miscellaneous JDBC properties to use when connecting
124         *        to the database via the JDBC driver
125         */
126        public void setProperties(Properties properties) {
127            this.properties = properties;
128        }
129        
130        public Connection getConnection() {
131            return conn;
132        }
133        
134        /**
135         * Attempts to get a JDBC Connection from a JNDI javax.sql.DataSource, using
136         * that connection for interacting with the database.
137         * @throws Exception
138         */
139        private void connectByJNDI(String userName, char[] password) throws Exception {
140            InitialContext ctx = new InitialContext();
141            javax.sql.DataSource ds = (javax.sql.DataSource)ctx.lookup(jndiContext);
142            conn = ds.getConnection(userName, new String(password));
143            conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
144        }
145        
146        /**
147         * Attempts to get a JDBC Connection from a DriverManager. If properties
148         * is not null, it tries to connect with those properties. If that fails,
149         * it then attempts to connect with a user name and password. If that fails,
150         * it attempts to connect without any credentials at all.
151         * <p>
152         * If, on the other hand, properties is null, it first attempts to connect
153         * with a username and password. Failing that, it tries to connect without
154         * any credentials at all.
155         * @throws Exception
156         */
157        private void connectByDriverManager(String userName, char[] password) throws Exception {
158            if (getProperties() != null) {
159                try {
160                    conn = DriverManager.getConnection(getUrl(), getProperties());
161                    conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
162                } catch (Exception e) {
163                    try {
164                        conn = DriverManager.getConnection(getUrl(), userName, new String(password));
165                        conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
166                    } catch (Exception ex) {
167                        conn = DriverManager.getConnection(getUrl());
168                        conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
169                    }
170                }
171            } else {
172                try {
173                    conn = DriverManager.getConnection(getUrl(), userName, new String(password));
174                } catch (Exception e) {
175                    LOG.log(Level.WARNING, "Connection with properties failed. " +
176                                    "Tryint to connect without.", e);
177                    //try to connect without using the userName and password
178                    conn = DriverManager.getConnection(getUrl());
179    
180                }
181            }
182        }
183    
184        /**
185         * @param name  user name
186         * @param password  user password
187         * @param server Must be either a valid JDBC URL for the type of JDBC driver you are using,
188         * or must be a valid JNDIContext from which to get the database connection
189         */
190        public boolean authenticate(String name, char[] password, String server) throws Exception {
191            //try to form a connection. If it works, conn will not be null
192            //if the jndiContext is not null, then try to get the DataSource to use
193            //from jndi
194            if (jndiContext != null) {
195                try {
196                    connectByJNDI(name, password);
197                } catch (Exception e) {
198                    try {
199                        connectByDriverManager(name, password);
200                    } catch (Exception ex) {
201                        LOG.log(Level.WARNING, "Login failed", ex);
202                        //login failed
203                        return false;
204                    }
205                }
206            } else {
207                try {
208                    connectByDriverManager(name, password);
209                } catch (Exception ex) {
210                    LOG.log(Level.WARNING, "", ex);
211                    return false;
212                }
213            }
214            return true;
215        }
216    }