Java tutorial
/** * This file is part of Boardservice Software package. * @copyright (c) 2014 Cuong Pham-Minh * * Boardservice is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License, version 2 (GPL-2.0) * as published by the Free Software Foundation. * * 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 General Public License for more details. * * A copy of the license can be viewed in the docs/LICENSE.txt file. * The same can be viewed at <http://opensource.org/licenses/gpl-2.0.php> */ package com.board.games.handler.modx; import java.io.File; import java.io.IOException; import java.math.BigDecimal; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.StringTokenizer; import java.util.concurrent.atomic.AtomicInteger; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import org.ini4j.Ini; import com.board.games.config.ServerConfig; import com.board.games.handler.generic.PokerConfigHandler; import com.board.games.service.wallet.WalletAdapter; import com.cubeia.firebase.api.action.local.LoginRequestAction; import com.cubeia.firebase.api.action.local.LoginResponseAction; import com.cubeia.firebase.api.login.LoginHandler; import com.cubeia.firebase.api.service.ServiceRouter; import com.saltedhashed.Verifier; import com.saltedhashed.crypto.PBKDF2Algorithms; import com.saltedhashed.model.Algorithm; import com.saltedhashed.model.AlgorithmDetails; import com.saltedhashed.model.PasswordResponse; public class MODXPokerLoginServiceImpl extends PokerConfigHandler implements LoginHandler { private static AtomicInteger pid = new AtomicInteger(0); private Logger log = Logger.getLogger(this.getClass()); private ServiceRouter router; private static Connection connect = null; private static Statement statement = null; // private static PreparedStatement preparedStatement = null; private static ResultSet resultSet = null; private String connectionStr = ""; private String jdbcDriverClassName = ""; private String dbPrefix = ""; private boolean needAgeAgreement = false; private int authTypeId = 1; static { PBKDF2Algorithms.initialize(); } public static void main(String[] a) { Verifier verifier = new Verifier(); String dbHash = "iDxLTbkejeeaQqpPoZTqUCJfWo1ALcBf7gMlYwwMa+Y="; //"dlgQ65ruCfeVVxqHJ3Bf02j50P0Wvis7WOoTfHYV3Nk="; String password = "rememberme"; String dbSalt = "008747a35b77a4c7e55ab7ea8aec3ee0"; PasswordResponse response = new PasswordResponse(); String salt = "008747a35b77a4c7e55ab7ea8aec3ee0"; response.setAlgorithm(Algorithm.PBKDF2); response.setSalt(salt); response.setAlgorithmDetails(new AlgorithmDetails()); response.getAlgorithmDetails().setIterations(1000); response.getAlgorithmDetails().setHashFunction("SHA256"); response.getAlgorithmDetails().setKeySize(263); PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 1000, response.getAlgorithmDetails().getKeySize()); try { SecretKeyFactory skf = PBKDF2Algorithms.getSecretKeyFactory( "PBKDF2WithHmac" + response.getAlgorithmDetails().getHashFunction().replace("-", "")); byte[] hash = skf.generateSecret(spec).getEncoded(); String encodedHash = Base64.encodeBase64String(hash); response.setHash(encodedHash); System.out.println("hash " + response.getHash()); if (verifier.verify(password, response)) { // Check it against database stored hash if (encodedHash.equals(dbHash)) { System.out.println("Authentication Successful"); } else { System.out.println("Authentication failed"); } } else { System.out.println("failed verification of hashing"); } } catch (Exception e) { throw new IllegalStateException(e); } } protected void initialize() { super.initialize(); try { Ini ini = new Ini(new File("JDBCConfig.ini")); String jdbcDriver = ini.get("JDBCConfig", "jdbcDriver"); String connectionUrl = ini.get("JDBCConfig", "connectionUrl"); String database = ini.get("JDBCConfig", "database"); dbPrefix = ini.get("JDBCConfig", "dbPrefix"); String user = ini.get("JDBCConfig", "user"); String password = ini.get("JDBCConfig", "password"); jdbcDriverClassName = ini.get("JDBCConfig", "driverClassName"); connectionStr = "jdbc" + ":" + jdbcDriver + "://" + connectionUrl + "/" + database + "?user=" + user + "&password=" + password; String forceAgeAgreement = ini.get("JDBCConfig", "forceAgeAgreement"); if (!forceAgeAgreement.equals("") && "Y".equals(forceAgeAgreement.toUpperCase())) { needAgeAgreement = true; } } catch (IOException ioe) { log.error("Exception in initialize " + ioe.toString()); } catch (Exception e) { log.error("Exception in initialize " + e.toString()); } } @Override public LoginResponseAction handle(LoginRequestAction req) { // Must be the very first call initialize(); boolean userHasAcceptedAgeclause = false; log.debug("Data login " + req.getData()); int count = 0; int idx = 0; int ref = 0; StringBuffer sb = new StringBuffer(); for (byte b : req.getData()) { idx++; // log.debug((char)b); char val = (char) b; // if (idx >7 ) sb.append(val); } //log.debug("count " + count); // TO DBG: activate trace of detail array below log.debug("sb " + sb.toString()); String logindataRequest = sb.toString(); /* log.debug("logindataRequest" + logindataRequest); if (logindataRequest.toUpperCase().equals("AGEVERIFICATIONDONE")) { userHasAcceptedAgeclause = true; } */ boolean isBot = false; String loginName = req.getUser(); int idxb = loginName.indexOf("_"); if (idxb != -1) { // let bots through String idStr = loginName.substring(idxb + 1); // if (loginName.toUpperCase().startsWith("BOT")) { isBot = true; // } } log.debug("datarequest " + logindataRequest); StringTokenizer st = new StringTokenizer(logindataRequest, ";"); String socialNetworkId = ""; String socialAvatar = ""; if (!isBot) { String ageClause = st.nextToken().trim(); log.debug("ageClause " + ageClause); if (ageClause.toUpperCase().equals("AGEVERIFICATIONDONE")) { userHasAcceptedAgeclause = true; } log.debug("User has accepted clause = " + (userHasAcceptedAgeclause ? "yes" : "no")); int snFlag = new Integer(st.nextToken()); log.debug("authId " + (snFlag == 5 || snFlag == 6 ? "use sn" : "no sn")); socialNetworkId = (String) st.nextToken(); log.debug("socialNetworkId " + socialNetworkId); socialAvatar = new String(st.nextToken()); log.debug("socialAvatar " + socialAvatar); if (snFlag == 5) { // overwrite default authTypeId authTypeId = 5; //force email with fb log.debug("authTypeId " + authTypeId); } else if (snFlag == 6) { // overwrite default authTypeId authTypeId = 6; //force email with google plus log.debug("authTypeId " + authTypeId); } else { authTypeId = 1; } } else { socialNetworkId = "999999"; socialAvatar = ""; userHasAcceptedAgeclause = true; authTypeId = 1; } LoginResponseAction response = null; try { log.debug("Performing authentication on " + req.getUser()); String userIdStr = null; if (authTypeId == 5 || authTypeId == 6) { log.debug("*** Social Network authentication ***"); userIdStr = authenticateSocialNetwork(req.getUser(), socialNetworkId, socialAvatar, getServerCfg(), userHasAcceptedAgeclause, authTypeId, needAgeAgreement); } else { log.debug("*** Forum authentication ***"); userIdStr = authenticate(req.getUser(), req.getPassword(), getServerCfg(), userHasAcceptedAgeclause, authTypeId); } if (!userIdStr.equals("")) { response = new LoginResponseAction(Integer.parseInt(userIdStr) > 0 ? true : false, (req.getUser().toUpperCase().startsWith("GUESTXDEMO") ? req.getUser() + "_" + userIdStr : req.getUser()), Integer.parseInt(userIdStr)); // pid.incrementAndGet() response.setErrorCode(Integer.parseInt(userIdStr)); String errMsg = "Login failed "; switch (Integer.parseInt(userIdStr)) { case -3: errMsg += " User does not exist, please sign up same account type on forum first"; break; case -5: errMsg += " User must check age requirement to play due to 18+ clause"; break; case -2: errMsg += " User has not met required posts"; break; case -1: errMsg += " User password is invalid"; break; default: break; } response.setErrorMessage(errMsg); log.debug(Integer.parseInt(userIdStr) > 0 ? "Authentication successful" : "Authentication failed with errorCode as " + userIdStr); return response; } /* String userIdStr = authenticate(req.getUser(), req.getPassword(), getServerCfg(),userHasAcceptedAgeclause,authTypeId); if (!userIdStr.equals("")) { response = new LoginResponseAction(Integer.parseInt(userIdStr) > 0?true:false, (req.getUser().toUpperCase().startsWith("GUESTXDEMO")?req.getUser()+"_"+userIdStr:req.getUser()), Integer.parseInt(userIdStr)); // pid.incrementAndGet() return response; }*/ } catch (SQLException sqle) { log.error("Error authenticate", sqle); response = new LoginResponseAction(false, -1); response.setErrorMessage(getSystemErrorMessage(sqle)); response.setErrorCode(getSystemErrorCode(sqle)); log.error(sqle); } catch (Exception e) { log.error("Error system", e); } response = new LoginResponseAction(false, -1); response.setErrorMessage(getNotFoundErrorMessage()); response.setErrorCode(getNotFoundErrorCode()); return response; } /** * This method should return the error code to send back if the sql query * fails. Default msg is 0. * * @param e * The sql exception, never null * @return The system error code */ protected int getSystemErrorCode(SQLException e) { return 0; } /** * This method should return the error message to send back if the sql query * fails. Default msg is "System error." * * @param e * The sql exception, never null * @return The system error message */ protected String getSystemErrorMessage(SQLException e) { return "System error."; } /** * This method should return the error code to send back if the sql query * does not get any results. Default msg is 0. * * @return The "user not found" error code */ protected int getNotFoundErrorCode() { return 0; } /** * This method should return the message to send back if the sql query does * not get any results. Default msg is "User not found." * * @return The "user not found" error message, may be null */ protected String getNotFoundErrorMessage() { return "User not found or registered but at least 1 post is required to play."; } private String authenticate(String user, String password, ServerConfig serverConfig, boolean checkAge, int authTypeId) throws Exception { String selectSQL = ""; try { if (serverConfig == null) { log.error("ServerConfig is null."); return "-3"; } int idx = user.indexOf("_"); if (idx != -1) { // let bots through String idStr = user.substring(idx + 1); // if (user.toUpperCase().startsWith("BOT")) { if (serverConfig.isUseIntegrations()) { WalletAdapter walletAdapter = new WalletAdapter(); log.debug("Calling createWalletAccount"); //walletAdapter.createWalletAccount(new Long(String.valueOf(member_id))); Long userId = walletAdapter.checkCreateNewUser(idStr, idStr, "UNUSED", new Long(0), serverConfig.getCurrency(), serverConfig.getWalletBankAccountId(), (serverConfig.getInitialAmount().multiply(new BigDecimal(20))), true, false, 0); return String.valueOf(userId); } else { return idStr; } // } } if (user.toUpperCase().startsWith("GUESTXDEMO")) { return String.valueOf(pid.incrementAndGet()); } log.debug("loading class name " + jdbcDriverClassName); // This will load the MySQL driver, each DB has its own driver // "com.mysql.jdbc.Driver" Class.forName(jdbcDriverClassName); // Setup the connection with the DB // "jdbc:mysql://localhost/dbName?" + "user=&password="); connect = DriverManager.getConnection(connectionStr); // Statements allow to issue SQL queries to the database statement = connect.createStatement(); log.debug("Execute query: authenticate"); selectSQL = "select id, username, password, salt from " + dbPrefix + "users" + " where username = " + "\'" + user + "\'"; log.debug("Executing query : " + selectSQL); resultSet = statement.executeQuery(selectSQL); String members_pass_hash = null; String members_pass_salt = null; String members_display_name = null; boolean authenticated = false; int member_id = 0; int posts = 0; if (resultSet != null && resultSet.next()) { String members_seo_name = resultSet.getString("username"); member_id = resultSet.getInt("id"); members_display_name = resultSet.getString("username"); members_pass_hash = resultSet.getString("password"); members_pass_salt = resultSet.getString("salt"); log.error("DB members_pass_hash = " + members_pass_hash); // posts = resultSet.getInt("user_posts"); // log.debug("# of Post " + posts); log.debug("User: " + user + " Password " + "********"); Verifier verifier = new Verifier(); PasswordResponse response = new PasswordResponse(); response.setAlgorithm(Algorithm.PBKDF2); response.setSalt(members_pass_salt); response.setAlgorithmDetails(new AlgorithmDetails()); response.getAlgorithmDetails().setIterations(1000); response.getAlgorithmDetails().setHashFunction("SHA256"); response.getAlgorithmDetails().setKeySize(263); PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), members_pass_salt.getBytes(), 1000, response.getAlgorithmDetails().getKeySize()); SecretKeyFactory skf = PBKDF2Algorithms.getSecretKeyFactory( "PBKDF2WithHmac" + response.getAlgorithmDetails().getHashFunction().replace("-", "")); byte[] hash = skf.generateSecret(spec).getEncoded(); String encodedHash = Base64.encodeBase64String(hash); response.setHash(encodedHash); log.debug("Encrypted hash " + response.getHash()); if (verifier.verify(password, response)) { // Check it against database stored hash authenticated = encodedHash.equals(members_pass_hash) ? true : false; } else { log.debug("failed verification of hashing"); } if (authenticated) { log.debug("Authentication successful"); log.debug("Member id " + String.valueOf(member_id)); if (serverConfig.isUseIntegrations()) { WalletAdapter walletAdapter = new WalletAdapter(); log.error("Calling createWalletAccount"); //walletAdapter.createWalletAccount(new Long(String.valueOf(member_id))); Long userId = walletAdapter.checkCreateNewUser(String.valueOf(member_id), members_seo_name, "UNUSED", new Long(1), serverConfig.getCurrency(), serverConfig.getWalletBankAccountId(), serverConfig.getInitialAmount(), checkAge, needAgeAgreement, authTypeId); if (userId < 0) { // user did not accept age clauses return "-5"; } log.debug("assigned new id as #" + String.valueOf(userId)); return String.valueOf(userId); } else { return String.valueOf(member_id); } /* if (posts >= 1) { return String.valueOf(member_id); } else { log.error("Required number of posts not met, denied login"); return "-2"; }*/ } else { log.error("hash not matched for user " + user + " password " + password); return "-1"; } } else { log.error("resultset is null " + selectSQL); } } catch (Exception e) { log.error("Error : " + e.toString()); // throw e; } finally { close(); } return "-3"; } private void close() { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connect != null) { connect.close(); } } catch (Exception e) { } } }