001 /*
002 * Copyright 2010 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package com.hs.mail.security.login;
017
018 import java.security.Principal;
019 import java.sql.Connection;
020 import java.sql.DriverManager;
021 import java.sql.PreparedStatement;
022 import java.sql.ResultSet;
023 import java.sql.SQLException;
024 import java.util.Map;
025
026 import javax.security.auth.Subject;
027 import javax.security.auth.callback.Callback;
028 import javax.security.auth.callback.CallbackHandler;
029 import javax.security.auth.callback.NameCallback;
030 import javax.security.auth.callback.PasswordCallback;
031 import javax.security.auth.login.AccountNotFoundException;
032 import javax.security.auth.login.CredentialException;
033 import javax.security.auth.login.LoginException;
034
035 import com.hs.mail.security.UserPrincipal;
036
037 /**
038 * A LoginModule that allows for authentication based on Legacy database.
039 *
040 * @author Won Chul Doh
041 * @since Jul 18, 2007
042 *
043 */
044 public class JdbcLoginModule extends BasicLoginModule {
045
046 private String driver;
047 private String url;
048 private String username;
049 private String password;
050 private String query;
051
052 @Override
053 public void initialize(Subject subject, CallbackHandler callbackHandler,
054 Map<String, ?> sharedState, Map<String, ?> options) {
055 super.initialize(subject, callbackHandler, sharedState, options);
056 driver = getOption("driver", null);
057 if (driver == null)
058 throw new Error("No JDBC driver specified");
059 try {
060 Class.forName(driver);
061 } catch (ClassNotFoundException e) {
062 throw new RuntimeException("JDBC driver not found: " + driver);
063 }
064 url = getOption("url", null);
065 if (url == null) {
066 throw new Error("No database URL specified");
067 }
068 username = getOption("username", null);
069 password = getOption("password", null);
070 if (username == null && password != null || username != null
071 && password == null) {
072 throw new Error(
073 "Both username and password option must be specified");
074 }
075 query = getOption("query", null);
076 if (query == null) {
077 throw new Error("Query not specified");
078 }
079 }
080
081 @Override
082 protected Principal[] validate(Callback[] callbacks) throws LoginException {
083 String username = ((NameCallback) callbacks[0]).getName();
084 char[] password = ((PasswordCallback) callbacks[1]).getPassword();
085
086 Connection cn = null;
087 ResultSet rs = null;
088 PreparedStatement pstmt = null;
089 try {
090 cn = (this.password != null)
091 ? DriverManager.getConnection(url, this.username, this.password)
092 : DriverManager.getConnection(url);
093 pstmt = cn.prepareStatement(query);
094 pstmt.setString(1, username);
095 rs = pstmt.executeQuery();
096 if (!rs.next())
097 throw new AccountNotFoundException("Account for " + username
098 + " not found");
099 String encodedPwd = rs.getString(1);
100 Principal[] principals = new Principal[1];
101 principals[0] = new UserPrincipal(username);
102 boolean ok = checkPassword(encodedPwd, password);
103 if (!ok)
104 throw new CredentialException("Incorrect password for "
105 + username);
106 else
107 return principals;
108 } catch (SQLException e) {
109 throw new LoginException("Error while reading database: "
110 + e.getMessage());
111 } finally {
112 try {
113 if (pstmt != null)
114 pstmt.close();
115 if (rs != null)
116 rs.close();
117 if (cn != null)
118 cn.close();
119 } catch (SQLException e) { }
120 }
121 }
122
123 }