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 }