/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2012 "Artur Hefczyc" <artur.hefczyc@tigase.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev$
* Last modified by $Author$
* $Date$
*/
package tigase.db.jdbc;
//~--- non-JDK imports --------------------------------------------------------
import tigase.db.AuthRepository;
import tigase.db.AuthorizationException;
import tigase.db.DBInitException;
import tigase.db.DataRepository;
import tigase.db.RepositoryFactory;
import tigase.db.TigaseDBException;
import tigase.db.UserExistsException;
import tigase.db.UserNotFoundException;
import tigase.util.Algorithms;
import tigase.util.Base64;
import tigase.util.TigaseStringprepException;
import tigase.xmpp.BareJID;
import static tigase.db.AuthRepository.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.Statement;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.RealmCallback;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
//~--- classes ----------------------------------------------------------------
/**
* The user authentication connector allows for customized SQL queries to be
* used. Queries are defined in the configuration file and they can be either
* plain SQL queries or stored procedures.
*
* If the query starts with characters: <code>{ call</code> then the server
* assumes this is a stored procedure call, otherwise it is executed as a plain
* SQL query. Each configuration value is stripped from white characters on both
* ends before processing.
*
* Please don't use semicolon <code>';'</code> at the end of the query as many
* JDBC drivers get confused and the query may not work for unknown obvious
* reason.
*
* Some queries take arguments. Arguments are marked by question marks
* <code>'?'</code> in the query. Refer to the configuration parameters
* description for more details about what parameters are expected in each
* query.
*
* Example configuration.
*
* The first example shows how to put a stored procedure as a query with 2
* required parameters.
*
* <pre>
* add-user-query={ call TigAddUserPlainPw(?, ?) }
* </pre>
*
* The same query with plain SQL parameters instead:
*
* <pre>
* add-user-query=insert into users (user_id, password) values (?, ?)
* </pre>
*
* Created: Sat Nov 11 22:22:04 2006
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev$
*/
public class TigaseCustomAuth implements AuthRepository {
/**
* Private logger for class instances.
*/
private static final Logger log = Logger.getLogger(TigaseCustomAuth.class.getName());
/**
* Query executing periodically to ensure active connection with the database.
*
* Takes no arguments.
*
* Example query:
*
* <pre>
* select 1
* </pre>
*/
public static final String DEF_CONNVALID_KEY = "conn-valid-query";
/**
* Database initialization query which is run after the server is started.
*
* Takes no arguments.
*
* Example query:
*
* <pre>
* update tig_users set online_status = 0
* </pre>
*/
public static final String DEF_INITDB_KEY = "init-db-query";
/**
* Query adding a new user to the database.
*
* Takes 2 arguments: <code>(user_id (JID), password)</code>
*
* Example query:
*
* <pre>
* insert into tig_users (user_id, user_pw) values (?, ?)
* </pre>
*/
public static final String DEF_ADDUSER_KEY = "add-user-query";
/**
* Removes a user from the database.
*
* Takes 1 argument: <code>(user_id (JID))</code>
*
* Example query:
*
* <pre>
* delete from tig_users where user_id = ?
* </pre>
*/
public static final String DEF_DELUSER_KEY = "del-user-query";
/**
* Retrieves user password from the database for given user_id (JID).
*
* Takes 1 argument: <code>(user_id (JID))</code>
*
* Example query:
*
* <pre>
* select user_pw from tig_users where user_id = ?
* </pre>
*/
public static final String DEF_GETPASSWORD_KEY = "get-password-query";
/**
* Updates (changes) password for a given user_id (JID).
*
* Takes 2 arguments: <code>(password, user_id (JID))</code>
*
* Example query:
*
* <pre>
* update tig_users set user_pw = ? where user_id = ?
* </pre>
*/
public static final String DEF_UPDATEPASSWORD_KEY = "update-password-query";
/**
* Performs user login. Normally used when there is a special SP used for this
* purpose. This is an alternative way to a method requiring retrieving user
* password. Therefore at least one of those queries must be defined:
* <code>user-login-query</code> or <code>get-password-query</code>.
*
* If both queries are defined then <code>user-login-query</code> is used.
* Normally this method should be only used with plain text password
* authentication or sasl-plain.
*
* The Tigase server expects a result set with user_id to be returned from the
* query if login is successful and empty results set if the login is
* unsuccessful.
*
* Takes 2 arguments: <code>(user_id (JID), password)</code>
*
* Example query:
*
* <pre>
* select user_id from tig_users where (user_id = ?) AND (user_pw = ?)
* </pre>
*/
public static final String DEF_USERLOGIN_KEY = "user-login-query";
/**
* This query is called when user logs out or disconnects. It can record that
* event in the database.
*
* Takes 1 argument: <code>(user_id (JID))</code>
*
* Example query:
*
* <pre>
* update tig_users, set online_status = online_status - 1 where user_id = ?
* </pre>
*/
public static final String DEF_USERLOGOUT_KEY = "user-logout-query";
/** Field description */
public static final String DEF_USERS_COUNT_KEY = "users-count-query";
/** Field description */
public static final String DEF_USERS_DOMAIN_COUNT_KEY = "" + "users-domain-count-query";
/**
* Comma separated list of NON-SASL authentication mechanisms. Possible
* mechanisms are: <code>password</code> and <code>digest</code>.
* <code>digest</code> mechanism can work only with
* <code>get-password-query</code> active and only when password are stored in
* plain text format in the database.
*/
public static final String DEF_NONSASL_MECHS_KEY = "non-sasl-mechs";
/**
* Comma separated list of SASL authentication mechanisms. Possible mechanisms
* are all mechanisms supported by Java implementation. The most common are:
* <code>PLAIN</code>, <code>DIGEST-MD5</code>, <code>CRAM-MD5</code>.
*
* "Non-PLAIN" mechanisms will work only with the
* <code>get-password-query</code> active and only when passwords are stored
* in plain text format in the database.
*/
public static final String DEF_SASL_MECHS_KEY = "sasl-mechs";
public static final String NO_QUERY = "none";
/** Field description */
public static final String DEF_INITDB_QUERY = "{ call TigInitdb() }";
/** Field description */
public static final String DEF_ADDUSER_QUERY = "{ call TigAddUserPlainPw(?, ?) }";
/** Field description */
public static final String DEF_DELUSER_QUERY = "{ call TigRemoveUser(?) }";
/** Field description */
public static final String DEF_GETPASSWORD_QUERY = "{ call TigGetPassword(?) }";
/** Field description */
public static final String DEF_UPDATEPASSWORD_QUERY =
"{ call TigUpdatePasswordPlainPwRev(?, ?) }";
/** Field description */
public static final String DEF_USERLOGIN_QUERY = "{ call TigUserLoginPlainPw(?, ?) }";
/** Field description */
public static final String DEF_USERLOGOUT_QUERY = "{ call TigUserLogout(?) }";
/** Field description */
public static final String DEF_USERS_COUNT_QUERY = "{ call TigAllUsersCount() }";
/** Field description */
public static final String DEF_USERS_DOMAIN_COUNT_QUERY = ""
+ "select count(*) from tig_users where user_id like ?";
/** Field description */
public static final String DEF_NONSASL_MECHS = "password";
/** Field description */
public static final String DEF_SASL_MECHS = "PLAIN";
/** Field description */
public static final String SP_STARTS_WITH = "{ call";
// ~--- fields ---------------------------------------------------------------
private DataRepository data_repo = null;
private String initdb_query = DEF_INITDB_QUERY;
private String getpassword_query = DEF_GETPASSWORD_QUERY;
private String deluser_query = DEF_DELUSER_QUERY;
private String adduser_query = DEF_ADDUSER_QUERY;
private String updatepassword_query = DEF_UPDATEPASSWORD_QUERY;
private String userlogin_query = DEF_USERLOGIN_QUERY;
private String userdomaincount_query = DEF_USERS_DOMAIN_COUNT_QUERY;
// It is better just to not call the query if it is not defined by the user
// By default it is null then and not called.
private String userlogout_query = null;
private String userscount_query = DEF_USERS_COUNT_QUERY;
private boolean userlogin_active = false;
// private String userlogout_query = DEF_USERLOGOUT_QUERY;
private String[] sasl_mechs = DEF_SASL_MECHS.split(",");
private String[] nonsasl_mechs = DEF_NONSASL_MECHS.split(",");
// ~--- methods --------------------------------------------------------------
/**
* Describe <code>addUser</code> method here.
*
* @param user
* a <code>String</code> value
* @param password
* a <code>String</code> value
* @exception UserExistsException
* if an error occurs
* @exception TigaseDBException
* if an error occurs
*/
@Override
public void addUser(BareJID user, final String password) throws UserExistsException,
TigaseDBException {
if (adduser_query == null) {
return;
}
ResultSet rs = null;
try {
PreparedStatement add_user = data_repo.getPreparedStatement(user, adduser_query);
synchronized (add_user) {
add_user.setString(1, user.toString());
add_user.setString(2, password);
boolean is_result = add_user.execute();
if (is_result) {
rs = add_user.getResultSet();
}
}
} catch (SQLIntegrityConstraintViolationException e) {
throw new UserExistsException(
"Error while adding user to repository, user exists?", e);
} catch (SQLException e) {
throw new TigaseDBException("Problem accessing repository.", e);
} finally {
data_repo.release(null, rs);
}
}
/**
* Describe <code>digestAuth</code> method here.
*
* @param user
* a <code>String</code> value
* @param digest
* a <code>String</code> value
* @param id
* a <code>String</code> value
* @param alg
* a <code>String</code> value
* @return a <code>boolean</code> value
* @exception UserNotFoundException
* if an error occurs
* @exception TigaseDBException
* if an error occurs
* @exception AuthorizationException
* if an error occurs
*/
@Override
@Deprecated
public boolean digestAuth(BareJID user, final String digest, final String id,
final String alg) throws UserNotFoundException, TigaseDBException,
AuthorizationException {
if (userlogin_active) {
throw new AuthorizationException("Not supported.");
} else {
final String db_password = getPassword(user);
try {
final String digest_db_pass = Algorithms.hexDigest(id, db_password, alg);
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "Comparing passwords, given: {0}, db: {1}", new Object[] {
digest, digest_db_pass });
}
return digest.equals(digest_db_pass);
} catch (NoSuchAlgorithmException e) {
throw new AuthorizationException("No such algorithm.", e);
} // end of try-catch
}
}
// ~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
public String getResourceUri() {
return data_repo.getResourceUri();
}
/**
* <code>getUsersCount</code> method is thread safe. It uses local variable
* for storing <code>Statement</code>.
*
* @return a <code>long</code> number of user accounts in database.
*/
@Override
public long getUsersCount() {
if (userscount_query == null) {
return -1;
}
ResultSet rs = null;
try {
long users = -1;
PreparedStatement users_count =
data_repo.getPreparedStatement(null, userscount_query);
synchronized (users_count) {
// Load all user count from database
rs = users_count.executeQuery();
if (rs.next()) {
users = rs.getLong(1);
} // end of while (rs.next())
}
return users;
} catch (SQLException e) {
return -1;
// throw new
// TigaseDBException("Problem loading user list from repository", e);
} finally {
data_repo.release(null, rs);
rs = null;
}
}
/**
* Method description
*
*
* @param domain
*
* @return
*/
@Override
public long getUsersCount(String domain) {
if (userdomaincount_query == null) {
return -1;
}
ResultSet rs = null;
try {
long users = -1;
PreparedStatement users_domain_count =
data_repo.getPreparedStatement(null, userdomaincount_query);
synchronized (users_domain_count) {
// Load all user count from database
users_domain_count.setString(1, "%@" + domain);
rs = users_domain_count.executeQuery();
if (rs.next()) {
users = rs.getLong(1);
} // end of while (rs.next())
}
return users;
} catch (SQLException e) {
return -1;
// throw new
// TigaseDBException("Problem loading user list from repository", e);
} finally {
data_repo.release(null, rs);
rs = null;
}
}
// ~--- methods --------------------------------------------------------------
/**
* Describe <code>initRepository</code> method here.
*
* @param connection_str
* a <code>String</code> value
* @param params
* @exception DBInitException
* if an error occurs
*/
@Override
public void initRepository(final String connection_str, Map<String, String> params)
throws DBInitException {
try {
data_repo = RepositoryFactory.getDataRepository(null, connection_str, params);
initdb_query = getParamWithDef(params, DEF_INITDB_KEY, DEF_INITDB_QUERY);
if (initdb_query != null) {
data_repo.initPreparedStatement(initdb_query, initdb_query);
}
adduser_query = getParamWithDef(params, DEF_ADDUSER_KEY, DEF_ADDUSER_QUERY);
if ((adduser_query != null)) {
data_repo.initPreparedStatement(adduser_query, adduser_query);
}
deluser_query = getParamWithDef(params, DEF_DELUSER_KEY, DEF_DELUSER_QUERY);
if ((deluser_query != null)) {
data_repo.initPreparedStatement(deluser_query, deluser_query);
}
getpassword_query = getParamWithDef(params, DEF_GETPASSWORD_KEY, null);
if ((getpassword_query != null)) {
data_repo.initPreparedStatement(getpassword_query, getpassword_query);
}
updatepassword_query =
getParamWithDef(params, DEF_UPDATEPASSWORD_KEY, DEF_UPDATEPASSWORD_QUERY);
if ((updatepassword_query != null)) {
data_repo.initPreparedStatement(updatepassword_query, updatepassword_query);
}
userlogin_query = getParamWithDef(params, DEF_USERLOGIN_KEY, DEF_USERLOGIN_QUERY);
if (userlogin_query != null) {
data_repo.initPreparedStatement(userlogin_query, userlogin_query);
userlogin_active = true;
}
userlogout_query =
getParamWithDef(params, DEF_USERLOGOUT_KEY, DEF_USERLOGOUT_QUERY);
if ((userlogout_query != null)) {
data_repo.initPreparedStatement(userlogout_query, userlogout_query);
}
userscount_query =
getParamWithDef(params, DEF_USERS_COUNT_KEY, DEF_USERS_COUNT_QUERY);
if ((userscount_query != null)) {
data_repo.initPreparedStatement(userscount_query, userscount_query);
}
userdomaincount_query =
getParamWithDef(params, DEF_USERS_DOMAIN_COUNT_KEY,
DEF_USERS_DOMAIN_COUNT_QUERY);
if ((userdomaincount_query != null)) {
data_repo.initPreparedStatement(userdomaincount_query, userdomaincount_query);
}
nonsasl_mechs =
getParamWithDef(params, DEF_NONSASL_MECHS_KEY, DEF_NONSASL_MECHS).split(",");
sasl_mechs = getParamWithDef(params, DEF_SASL_MECHS_KEY, DEF_SASL_MECHS).split(",");
if ((params != null) && (params.get("init-db") != null)) {
initDb();
}
} catch (Exception e) {
data_repo = null;
throw new DBInitException(
"Problem initializing jdbc connection: " + connection_str, e);
}
}
/**
* Method description
*
*
* @param user
*
* @throws TigaseDBException
* @throws UserNotFoundException
*/
@Override
public void logout(BareJID user) throws UserNotFoundException, TigaseDBException {
if (userlogout_query == null) {
return;
}
try {
PreparedStatement user_logout =
data_repo.getPreparedStatement(user, userlogout_query);
if (user_logout != null) {
synchronized (user_logout) {
user_logout.setString(1, user.toString());
user_logout.execute();
}
}
} catch (SQLException e) {
throw new TigaseDBException("Problem accessing repository.", e);
}
}
/**
* Describe <code>otherAuth</code> method here.
*
* @param props
* a <code>Map</code> value
* @return a <code>boolean</code> value
* @exception UserNotFoundException
* if an error occurs
* @exception TigaseDBException
* if an error occurs
* @exception AuthorizationException
* if an error occurs
*/
@Override
public boolean otherAuth(final Map<String, Object> props) throws UserNotFoundException,
TigaseDBException, AuthorizationException {
String proto = (String) props.get(PROTOCOL_KEY);
if (proto.equals(PROTOCOL_VAL_SASL)) {
String mech = (String) props.get(MACHANISM_KEY);
if (mech.equals("PLAIN")) {
try {
if (saslPlainAuth(props)) {
return true;
} else {
throw new AuthorizationException("Authentication failed.");
}
} catch (TigaseStringprepException ex) {
throw new AuthorizationException("Stringprep failed for: " + props, ex);
}
} else {
return saslAuth(props);
}
} // end of if (proto.equals(PROTOCOL_VAL_SASL))
if (proto.equals(PROTOCOL_VAL_NONSASL)) {
String password = (String) props.get(PASSWORD_KEY);
BareJID user_id = (BareJID) props.get(USER_ID_KEY);
if (password != null) {
return plainAuth(user_id, password);
}
String digest = (String) props.get(DIGEST_KEY);
if (digest != null) {
String digest_id = (String) props.get(DIGEST_ID_KEY);
return digestAuth(user_id, digest, digest_id, "SHA");
}
} // end of if (proto.equals(PROTOCOL_VAL_SASL))
throw new AuthorizationException("Protocol is not supported.");
}
/**
* Describe <code>plainAuth</code> method here.
*
* @param user
* a <code>String</code> value
* @param password
* a <code>String</code> value
* @return a <code>boolean</code> value
*
* @throws AuthorizationException
* @exception UserNotFoundException
* if an error occurs
* @exception TigaseDBException
* if an error occurs
*/
@Override
@Deprecated
public boolean plainAuth(BareJID user, final String password)
throws UserNotFoundException, TigaseDBException, AuthorizationException {
if (userlogin_active) {
return userLoginAuth(user, password);
} else {
String db_password = getPassword(user);
return (password != null) && (db_password != null) && db_password.equals(password);
}
}
// Implementation of tigase.db.AuthRepository
/**
* Describe <code>queryAuth</code> method here.
*
* @param authProps
* a <code>Map</code> value
*/
@Override
public void queryAuth(final Map<String, Object> authProps) {
String protocol = (String) authProps.get(PROTOCOL_KEY);
if (protocol.equals(PROTOCOL_VAL_NONSASL)) {
authProps.put(RESULT_KEY, nonsasl_mechs);
} // end of if (protocol.equals(PROTOCOL_VAL_NONSASL))
if (protocol.equals(PROTOCOL_VAL_SASL)) {
authProps.put(RESULT_KEY, sasl_mechs);
} // end of if (protocol.equals(PROTOCOL_VAL_NONSASL))
}
/**
* Describe <code>removeUser</code> method here.
*
* @param user
* a <code>String</code> value
* @exception UserNotFoundException
* if an error occurs
* @exception TigaseDBException
* if an error occurs
*/
@Override
public void removeUser(BareJID user) throws UserNotFoundException, TigaseDBException {
if (deluser_query == null) {
return;
}
try {
PreparedStatement remove_user = data_repo.getPreparedStatement(user, deluser_query);
synchronized (remove_user) {
remove_user.setString(1, user.toString());
remove_user.execute();
}
} catch (SQLException e) {
throw new TigaseDBException("Problem accessing repository.", e);
}
}
/**
* Describe <code>updatePassword</code> method here.
*
* @param user
* a <code>String</code> value
* @param password
* a <code>String</code> value
* @exception TigaseDBException
* if an error occurs
* @throws UserNotFoundException
*/
@Override
public void updatePassword(BareJID user, final String password)
throws UserNotFoundException, TigaseDBException {
if (updatepassword_query == null) {
return;
}
try {
PreparedStatement update_pass =
data_repo.getPreparedStatement(user, updatepassword_query);
synchronized (update_pass) {
update_pass.setString(1, password);
update_pass.setString(2, user.toString());
update_pass.execute();
}
} catch (SQLException e) {
throw new TigaseDBException("Problem accessing repository.", e);
}
}
// ~--- get methods ----------------------------------------------------------
protected String getParamWithDef(Map<String, String> params, String key, String def) {
if (params == null) {
return def;
}
String result = params.get(key);
if (result != null) {
log.log(Level.CONFIG, "Custom query loaded for ''{0}'': ''{1}''", new Object[] {
key, result });
} else {
result = def;
log.log(Level.CONFIG, "Default query loaded for ''{0}'': ''{1}''", new Object[] {
key, def });
}
if (result != null) {
result = result.trim();
if (result.isEmpty() || result.equals(NO_QUERY)) {
result = null;
}
}
return result;
}
private String getPassword(BareJID user) throws TigaseDBException,
UserNotFoundException {
if (getpassword_query == null) {
return null;
}
ResultSet rs = null;
try {
PreparedStatement get_pass =
data_repo.getPreparedStatement(user, getpassword_query);
synchronized (get_pass) {
get_pass.setString(1, user.toString());
rs = get_pass.executeQuery();
if (rs.next()) {
return rs.getString(1);
} else {
throw new UserNotFoundException("User does not exist: " + user);
} // end of if (isnext) else
}
} catch (SQLException e) {
throw new TigaseDBException("Problem with retrieving user password.", e);
} finally {
data_repo.release(null, rs);
}
}
// ~--- methods --------------------------------------------------------------
private void initDb() throws SQLException {
if (initdb_query == null) {
return;
}
PreparedStatement init_db = data_repo.getPreparedStatement(null, initdb_query);
synchronized (init_db) {
init_db.executeUpdate();
}
}
private boolean saslAuth(final Map<String, Object> props) throws AuthorizationException {
try {
SaslServer ss = (SaslServer) props.get("SaslServer");
if (ss == null) {
Map<String, String> sasl_props = new TreeMap<String, String>();
sasl_props.put(Sasl.QOP, "auth");
ss =
Sasl.createSaslServer((String) props.get(MACHANISM_KEY), "xmpp",
(String) props.get(SERVER_NAME_KEY), sasl_props, new SaslCallbackHandler(
props));
props.put("SaslServer", ss);
} // end of if (ss == null)
String data_str = (String) props.get(DATA_KEY);
byte[] in_data = ((data_str != null) ? Base64.decode(data_str) : new byte[0]);
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "response: {0}", new String(in_data));
}
byte[] challenge = ss.evaluateResponse(in_data);
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "challenge: {0}", ((challenge != null) ? new String(
challenge) : "null"));
}
String challenge_str =
(((challenge != null) && (challenge.length > 0)) ? Base64.encode(challenge)
: null);
props.put(RESULT_KEY, challenge_str);
if (ss.isComplete()) {
return true;
} else {
return false;
} // end of if (ss.isComplete()) else
} catch (SaslException e) {
throw new AuthorizationException("Sasl exception.", e);
} // end of try-catch
}
private boolean saslPlainAuth(final Map<String, Object> props)
throws UserNotFoundException, TigaseDBException, AuthorizationException,
TigaseStringprepException {
String data_str = (String) props.get(DATA_KEY);
String domain = (String) props.get(REALM_KEY);
props.put(RESULT_KEY, null);
byte[] in_data = ((data_str != null) ? Base64.decode(data_str) : new byte[0]);
int auth_idx = 0;
while ((in_data[auth_idx] != 0) && (auth_idx < in_data.length)) {
++auth_idx;
}
String authoriz = new String(in_data, 0, auth_idx);
int user_idx = ++auth_idx;
while ((in_data[user_idx] != 0) && (user_idx < in_data.length)) {
++user_idx;
}
String user_name = new String(in_data, auth_idx, user_idx - auth_idx);
++user_idx;
BareJID jid = null;
if (BareJID.parseJID(user_name)[0] == null) {
jid = BareJID.bareJIDInstance(user_name, domain);
} else {
jid = BareJID.bareJIDInstance(user_name);
}
props.put(USER_ID_KEY, jid);
String passwd = new String(in_data, user_idx, in_data.length - user_idx);
return plainAuth(jid, passwd);
}
private boolean userLoginAuth(BareJID user, final String password)
throws UserNotFoundException, TigaseDBException, AuthorizationException {
if (userlogin_query == null) {
return false;
}
ResultSet rs = null;
String res_string = null;
try {
PreparedStatement user_login = data_repo.getPreparedStatement(user, userlogin_query);
synchronized (user_login) {
// String user_id = BareJID.jidToBareJID(user);
user_login.setString(1, user.toString());
user_login.setString(2, password);
rs = user_login.executeQuery();
boolean auth_result_ok = false;
if (rs.next()) {
res_string = rs.getString(1);
if (res_string != null) {
BareJID result = BareJID.bareJIDInstance(res_string);
auth_result_ok = user.equals(result);
}
if (auth_result_ok) {
return true;
} else {
if (log.isLoggable(Level.FINE)) {
log.log(Level.FINE, "Login failed, for user: ''{0}" + "''"
+ ", password: ''" + "{1}" + "''" + ", from DB got: " + "{2}",
new Object[] { user, password, res_string });
}
}
}
throw new UserNotFoundException("User does not exist: " + user
+ ", in database: " + getResourceUri());
}
} catch (TigaseStringprepException ex) {
throw new AuthorizationException("Stringprep failed for: " + res_string, ex);
} catch (SQLException e) {
throw new TigaseDBException("Problem accessing repository.", e);
} finally {
data_repo.release(null, rs);
} // end of catch
}
// ~--- inner classes --------------------------------------------------------
private class SaslCallbackHandler implements CallbackHandler {
private Map<String, Object> options = null;
// ~--- constructors -------------------------------------------------------
private SaslCallbackHandler(final Map<String, Object> options) {
this.options = options;
}
// ~--- methods ------------------------------------------------------------
// Implementation of javax.security.auth.callback.CallbackHandler
/**
* Describe <code>handle</code> method here.
*
* @param callbacks
* a <code>Callback[]</code> value
* @exception IOException
* if an error occurs
* @exception UnsupportedCallbackException
* if an error occurs
*/
@Override
public void handle(final Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
BareJID jid = null;
for (int i = 0; i < callbacks.length; i++) {
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "Callback: {0}", callbacks[i].getClass().getSimpleName());
}
if (callbacks[i] instanceof RealmCallback) {
RealmCallback rc = (RealmCallback) callbacks[i];
String realm = (String) options.get(REALM_KEY);
if (realm != null) {
rc.setText(realm);
} // end of if (realm == null)
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "RealmCallback: {0}", realm);
}
} else {
if (callbacks[i] instanceof NameCallback) {
NameCallback nc = (NameCallback) callbacks[i];
String user_name = nc.getName();
if (user_name == null) {
user_name = nc.getDefaultName();
} // end of if (name == null)
jid = BareJID.bareJIDInstanceNS(user_name, (String) options.get(REALM_KEY));
options.put(USER_ID_KEY, jid);
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "NameCallback: {0}", user_name);
}
} else {
if (callbacks[i] instanceof PasswordCallback) {
PasswordCallback pc = (PasswordCallback) callbacks[i];
try {
String passwd = getPassword(jid);
pc.setPassword(passwd.toCharArray());
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "PasswordCallback: {0}", passwd);
}
} catch (Exception e) {
throw new IOException("Password retrieving problem.", e);
} // end of try-catch
} else {
if (callbacks[i] instanceof AuthorizeCallback) {
AuthorizeCallback authCallback = ((AuthorizeCallback) callbacks[i]);
String authenId = authCallback.getAuthenticationID();
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "AuthorizeCallback: authenId: {0}", authenId);
}
String authorId = authCallback.getAuthorizationID();
if (log.isLoggable(Level.FINEST)) {
log.log(Level.FINEST, "AuthorizeCallback: authorId: {0}", authorId);
}
if (authenId.equals(authorId)) {
authCallback.setAuthorized(true);
} // end of if (authenId.equals(authorId))
} else {
throw new UnsupportedCallbackException(callbacks[i],
"Unrecognized Callback");
}
}
}
}
}
}
}
} // TigaseCustomAuth
// ~ Formatted in Sun Code Convention
// ~ Formatted by Jindent --- http://www.jindent.com