package bomberman.login;
import bomberman.client.MAAdminClientImpl;
import bomberman.client.MSUserClientImpl;
import bomberman.client.MobClient;
import bomberman.client.RealClient;
import bomberman.gameserver.AdminGameServer;
import bomberman.gameserver.UserGameServer;
import javax.rmi.PortableRemoteObject;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.rmi.MarshalledObject;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.*;
import java.util.ArrayList;
/**
* Implementazione del server di autenticazione;
* è un server dual export, cioè viene esportato sia come UnicastRemoteObject
* che come PortableRemoteObject e la cui referenza è inserita sia nel registro RMI
* che in COSNaming.
*
* @author Federico Matera
*/
public class AuthServer implements Bootstrap {
private Bootstrap authStub;
private UserGameServer userGS;
private AdminGameServer adminGS;
private ArrayList<String> loggedUsers;
/**
* Costruttore del server di Autenticazione;
* esporta il server come UnicastRemoteObject e PortableRemoteObject.
*/
public AuthServer() throws RemoteException {
this.loggedUsers = new ArrayList<String>();
authStub = (Bootstrap) UnicastRemoteObject.exportObject(this, 10000);
System.out.println("# AuthServer è esportato come UnicastRemoteObject.");
PortableRemoteObject.exportObject(this);
System.out.println("# AuthServer è esportato come PortableRemoteObject.");
}
/**
* {@inheritDoc}
*/
public MarshalledObject getClient() throws RemoteException {
try {
System.out.println("> Client minimale connesso, invio il RealClient.");
RealClient cl = new RealClient(authStub);
return new MarshalledObject<RealClient>(cl);
}
catch (IOException ioe) {
return null;
}
}
/**
* {@inheritDoc}
*/
public MobClient login(String username, String password) throws RemoteException {
final String dbUrl = "jdbc:sqlite:db";
final String loginQ = "select * from auth where username = ?";
final String signupQ = "insert into auth values(?, ?)";
Connection connection;
PreparedStatement pstmt;
ResultSet rs;
try {
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection(dbUrl);
pstmt = connection.prepareStatement(loginQ);
pstmt.clearParameters();
pstmt.setString(1, username);
rs = pstmt.executeQuery();
if (rs.next()) {
String dbPassword = rs.getString("password");
rs.close();
connection.close();
if ((dbPassword.compareTo(sign(password)) == 0) && (!isLoggedYet(username))) {
loggedUsers.add(username);
System.out.println("> " + username + " loggato.");
if (username.compareTo("admin") == 0) {
if (adminGS == null)
this.adminGS = (AdminGameServer) Naming.lookup("//localhost:1098/gameserver");
return new MAAdminClientImpl(adminGS, username);
} else {
if (userGS == null)
this.userGS = (UserGameServer) Naming.lookup("//localhost:1098/gameserver");
return new MSUserClientImpl(userGS, username);
}
} else {
System.out.println("> " + username + " ha fallito il login.");
return null;
}
} else { //altrimenti registro utente
pstmt = connection.prepareStatement(signupQ);
pstmt.clearParameters();
pstmt.setString(1, username);
pstmt.setString(2, sign(password));
pstmt.executeUpdate();
connection.close();
System.out.println("> " + username + " registrato nel DB.");
return login(username, password);
}
} catch (ClassNotFoundException cnfe) {
System.out.println("AuthServer Driver jdbc non trovato: " + cnfe.getMessage());
} catch (SQLException sqle) {
System.out.println("AuthServer errore SQL: " + sqle.getMessage());
sqle.printStackTrace();
} catch (NotBoundException nbe) {
System.out.println("AuthServer not bound error: " + nbe.getMessage());
nbe.printStackTrace();
} catch (MalformedURLException mue) {
System.out.println("AuthServer malformed URL error: " + mue.getMessage());
mue.printStackTrace();
}
return null;
}
/**
* {@inheritDoc}
*/
public void logout(String username) throws RemoteException {
for (int k = 0; k < loggedUsers.size(); k++)
if (loggedUsers.get(k).compareTo(username) == 0)
loggedUsers.remove(k);
System.out.println("> si disconnette " + username);
}
/**
* Controlla se l'utente che cerca di eseguire il login è già in gioco.
* @param username L'username.
* @return true se l'username risulta già loggato, false altrimenti.
*/
private boolean isLoggedYet(String username) {
for (String loggedUsername : loggedUsers)
if (username.compareTo(loggedUsername) == 0)
return true;
return false;
}
/**
* Esegue l'hash di una stringa con algoritmo SHA-256.
* @param password La password da hashare.
* @return l'hash della password.
*/
private String sign(String password) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes("UTF-8"));
byte[] digest = md.digest();
StringBuilder sb = new StringBuilder();
for (byte b : digest)
sb.append(String.format("%02x", b));
return sb.toString();
} catch (NoSuchAlgorithmException nsae) {
System.out.println("AuthServer errore algoritmo hashing: " + nsae.getMessage());
nsae.printStackTrace();
} catch (UnsupportedEncodingException uee) {
System.out.println("AuthServer errore codifica: " + uee.getMessage());
uee.printStackTrace();
}
return null;
}
}